Remove background from images in C#
Masking involves setting some of the pixel values in an image to zero, or some other “background” value. Aspose.Imaging supports the following types of masking.
- Manual Masking
- Auto Masking
Auto Masking
Graph Cut auto masking using Imaging.Cloud API
To get better remove background results, Graph Cut segmentation with pre-calculated brushstrokes can be used. The following example demonstrates usage of the Imaging.Cloud API’s detected objects as an input for Graph Cut auto masking to further improve masking results. DetectedObjectList’s data is converted into an AssumedObjectData collection first so that it can be passed into the AutoMaskingGraphCutOptions.
using Aspose.Imaging; | |
using Aspose.Imaging.Cloud.Sdk.Api; | |
using Aspose.Imaging.Cloud.Sdk.Model; | |
using Aspose.Imaging.Cloud.Sdk.Model.Requests; | |
using Aspose.Imaging.FileFormats.Png; | |
using Aspose.Imaging.ImageOptions; | |
using Aspose.Imaging.Masking; | |
using Aspose.Imaging.Masking.Options; | |
using Aspose.Imaging.Masking.Result; | |
using Aspose.Imaging.Sources; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
string templatesFolder = @"c:\Users\USER\Downloads\templates\"; | |
string dataDir = templatesFolder; | |
// To improve masking results, data of the specific objects that should be included in the foreground masking result could be provided. | |
List<AssumedObjectData> assumedObjects = new List<AssumedObjectData>(); | |
// Imaging.Cloud API could be used get objects located on the image and using that data to further improve masking results. | |
using (var stream = File.OpenRead(dataDir + "couple.jpg")) | |
{ | |
var request = new CreateObjectBoundsRequest() | |
{ | |
imageData = stream, | |
outPath = "output_objects.jpg", | |
threshold = 1, | |
includeLabel = true, | |
includeScore = true, | |
}; | |
ImagingApi api = new ImagingApi("****","****",""); | |
DetectedObjectList detectedObjectList = api.CreateObjectBounds(request); | |
if (detectedObjectList != null && detectedObjectList.DetectedObjects != null && detectedObjectList.DetectedObjects.Count > 0) | |
{ | |
// Detected object's data from the DetectedObjectList should be converted to the | |
// AssumedObjectData to be fit to use with the AutoMaskingGraphCutOptions. | |
foreach (DetectedObject detectedObject in detectedObjectList.DetectedObjects) | |
{ | |
if (detectedObject.Bounds.X != null && detectedObject.Bounds.Y != null | |
&& detectedObject.Bounds.Width != null | |
&& detectedObject.Bounds.Height != null) | |
{ | |
assumedObjects.Add( | |
new AssumedObjectData( | |
detectedObject.Label, | |
new Aspose.Imaging.Rectangle( | |
(int)detectedObject.Bounds.X.Value, | |
(int)detectedObject.Bounds.Y.Value, | |
(int)detectedObject.Bounds.Width.Value, | |
(int)detectedObject.Bounds.Height.Value))); | |
} | |
} | |
} | |
} | |
MaskingResult results; | |
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg")) | |
{ | |
// To use Graph Cut with auto calculated strokes, AutoMaskingGraphCutOptions is used. | |
AutoMaskingGraphCutOptions options = new AutoMaskingGraphCutOptions | |
{ | |
AssumedObjects = assumedObjects, | |
// Indicating that a new calculation of the default strokes should be performed during the image decomposition. | |
CalculateDefaultStrokes = true, | |
// Setting post-process feathering radius based on the image size. | |
FeatheringRadius = (Math.Max(image.Width, image.Height) / 500) + 1, | |
Method = SegmentationMethod.GraphCut, | |
Decompose = false, | |
ExportOptions = | |
new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new FileCreateSource(dataDir + "result.png") | |
}, | |
BackgroundReplacementColor = Color.Transparent | |
}; | |
results = new ImageMasking(image).Decompose(options); | |
// Saving final masking result. | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result2.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
File.Delete(dataDir + "result.png"); | |
File.Delete(dataDir + "result2.png"); |
Using Graph Cut auto masking with feathering
The following example demonstrates saving of the image masking results with feathering based on image size. Image masking is performed using auto calculated default strokes. The Args property of AutoMaskingGraphCutOptions can be omitted since default strokes are placed there in the end.
using Aspose.Imaging; | |
using Aspose.Imaging.FileFormats.Png; | |
using Aspose.Imaging.ImageOptions; | |
using Aspose.Imaging.Masking; | |
using Aspose.Imaging.Masking.Options; | |
using Aspose.Imaging.Masking.Result; | |
using Aspose.Imaging.Sources; | |
using System; | |
using System.IO; | |
string templatesFolder = @"c:\Users\USER\Downloads\templates\"; | |
string dataDir = templatesFolder; | |
MaskingResult results; | |
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg")) | |
{ | |
// To use Graph Cut with auto calculated strokes, AutoMaskingGraphCutOptions is used. | |
AutoMaskingGraphCutOptions options = new AutoMaskingGraphCutOptions | |
{ | |
// Indicating that a new calculation of the default strokes should be performed during the image decomposition. | |
CalculateDefaultStrokes = true, | |
// Setting post-process feathering radius based on the image size. | |
FeatheringRadius = (Math.Max(image.Width, image.Height) / 500) + 1, | |
Method = SegmentationMethod.GraphCut, | |
Decompose = false, | |
ExportOptions = | |
new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new FileCreateSource(dataDir + "result.png") | |
}, | |
BackgroundReplacementColor = Color.Transparent | |
}; | |
results = new ImageMasking(image).Decompose(options); | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result2.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
File.Delete(dataDir + "result.png"); | |
File.Delete(dataDir + "result2.png"); |
Re-using default strokes in repeated auto masking with new points
The following example demonstrates saving of the image masking results with feathering based on image size and re-using masking options for the new masking iteration. Image masking is performed using auto calculated default strokes. Additionally, the data of the two assumed objects are also specified in the AssumedObjects property of the AutoMaskingGraphCutOptions. After getting the initial masking results, applied background/foreground strokes are modified and another masking iteration is performed.
using Aspose.Imaging; | |
using Aspose.Imaging.FileFormats.Png; | |
using Aspose.Imaging.ImageOptions; | |
using Aspose.Imaging.Masking; | |
using Aspose.Imaging.Masking.Options; | |
using Aspose.Imaging.Masking.Result; | |
using Aspose.Imaging.Sources; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
string templatesFolder = @"c:\Users\USER\Downloads\templates\"; | |
string dataDir = templatesFolder; | |
// To improve masking results, data of the specific objects that should be included in the foreground masking result could be provided. | |
List<AssumedObjectData> assumedObjects = new List<AssumedObjectData>(); | |
// The object type and the area containing that object should be specified. | |
assumedObjects.Add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(0, 0, 300, 300))); | |
MaskingResult results; | |
AutoMaskingGraphCutOptions options; | |
Point[] appliedBackgroundStrokes; | |
Point[] appliedForegroundStrokes; | |
Rectangle[] appliedObjectRectangles; | |
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg")) | |
{ | |
// To use Graph Cut with auto calculated strokes, AutoMaskingGraphCutOptions is used. | |
options = new AutoMaskingGraphCutOptions | |
{ | |
AssumedObjects = assumedObjects, | |
// Indicating that a new calculation of the default strokes should be performed during the image decomposition. | |
CalculateDefaultStrokes = true, | |
// Setting post-process feathering radius based on the image size. | |
FeatheringRadius = (Math.Max(image.Width, image.Height) / 500) + 1, | |
Method = SegmentationMethod.GraphCut, | |
Decompose = false, | |
ExportOptions = new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new FileCreateSource(dataDir + "result.png") | |
}, | |
BackgroundReplacementColor = Color.Transparent | |
}; | |
using (IMaskingSession maskingSession = new ImageMasking(image).CreateSession(options)) | |
{ | |
results = maskingSession.Decompose(); | |
// Saving intermediate masking result. | |
using (RasterImage resultImage = results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result2.png", | |
new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
// At this point applied foreground/background strokes can be analyzed and based on it additional | |
// foreground/background strokes can be manually provided. | |
appliedBackgroundStrokes = options.DefaultBackgroundStrokes; | |
appliedForegroundStrokes = options.DefaultForegroundStrokes; | |
appliedObjectRectangles = options.DefaultObjectsRectangles; | |
// Re-using AutoMaskingGraphCutOptions there is no need to perform default stroke calculations a second time. | |
// When both default strokes and ObjectsPoints in the Args property of AutoMaskingArgs are provided, Point arrays are end up combined. | |
// The first ObjectsPoints array is considered to be a background points array and | |
// the second ObjectsPoints array is considered to be a foreground points array. | |
// When both DefaultObjectsRectangles and ObjectsRectangles in the Args property of AutoMaskingArgs are provided, | |
// only the array from the Args is being used. | |
AutoMaskingArgs newAutoMaskingArgs = new AutoMaskingArgs() | |
{ | |
ObjectsPoints = new Point[][] | |
{ | |
// Additionally specifying areas we want to be removed. | |
GetRectanglePoints( | |
new Rectangle(100, 100, 35, 90), | |
new Rectangle(300, 140, 95, 50) | |
) | |
}, | |
}; | |
results = maskingSession.ImproveDecomposition(newAutoMaskingArgs); | |
using (RasterImage resultImage = results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + | |
"result3.png", | |
new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
} | |
//Examples - graph - cut - repeated - masking - with - new- points.cs | |
// To improve masking results, data of the specific objects that should be included in the foreground masking result could be provided. | |
assumedObjects = new List<AssumedObjectData>(); | |
// THe object type and the area containing that object should be specified. | |
assumedObjects.Add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(100, 100, 150, 300))); | |
// First masking iteration is performed to get auto calculated foreground/background brushstrokes. | |
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg")) | |
{ | |
// To use Graph Cut with auto calculated strokes, AutoMaskingGraphCutOptions is used. | |
options = new AutoMaskingGraphCutOptions | |
{ | |
AssumedObjects = assumedObjects, | |
// Indicating that a new calculation of the default strokes should be performed during the image decomposition. | |
CalculateDefaultStrokes = true, | |
// Setting post-process feathering radius. | |
FeatheringRadius = 3, | |
Method = SegmentationMethod.GraphCut, | |
Decompose = false, | |
ExportOptions = | |
new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new FileCreateSource(dataDir + "result4.png") | |
}, | |
BackgroundReplacementColor = Color.Transparent | |
}; | |
results = new ImageMasking(image).Decompose(options); | |
// At this point applied foreground/background strokes can be analyzed and based on it additional | |
// foreground/background strokes can be manually provided. | |
appliedBackgroundStrokes = options.DefaultBackgroundStrokes; | |
appliedForegroundStrokes = options.DefaultForegroundStrokes; | |
appliedObjectRectangles = options.DefaultObjectsRectangles; | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result5.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
// Second masking iteration is performed to further improve masking quality by adding new manually chosen foreground/background points. | |
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg")) | |
{ | |
// Re-using AutoMaskingGraphCutOptions there is no need to perform default stroke calculations a second time. | |
options.CalculateDefaultStrokes = false; | |
// When both default strokes and ObjectsPoints in the Args property of AutoMaskingArgs are provided, Point arrays are end up combined. | |
// The first ObjectsPoints array is considered to be a background points array and | |
// the second ObjectsPoints array is considered to be a foreground points array. | |
// When both DefaultObjectsRectangles and ObjectsRectangles in the Args property of AutoMaskingArgs are provided, | |
// only the array from the Args is being used. | |
options.Args = new AutoMaskingArgs() | |
{ | |
ObjectsPoints = new Point[][] | |
{ | |
new Point[] { new Point(100, 100), new Point(150, 100) }, | |
new Point[] { new Point(300, 200) }, | |
}, | |
ObjectsRectangles = new Rectangle[] | |
{ | |
new Rectangle(100, 100, 300, 300), | |
} | |
}; | |
results = new ImageMasking(image).Decompose(options); | |
// Saving final masking result. | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result6.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
/// <summary> | |
/// Return all points that belongs to the specified rectangles. | |
/// </summary> | |
/// <param name="rectangles">The array of rectangles.</param> | |
/// <returns>All rectangle points.</returns> | |
static Point[] GetRectanglePoints(params Rectangle[] rectangles) | |
{ | |
int arraySize = 0; | |
foreach (Rectangle rectangle in rectangles) | |
{ | |
arraySize += rectangle.Width * rectangle.Height; | |
} | |
Point[] pointArray = new Point[arraySize]; | |
int arrayIndex = 0; | |
foreach (Rectangle rectangle in rectangles) | |
{ | |
for (int x = rectangle.Left; x < rectangle.Right; x++) | |
{ | |
for (int y = rectangle.Top; y < rectangle.Bottom; y++) | |
{ | |
pointArray[arrayIndex++] = new Point(x, y); | |
} | |
} | |
} | |
return pointArray; | |
} | |
File.Delete(dataDir + "result.png"); | |
File.Delete(dataDir + "result2.png"); | |
File.Delete(dataDir + "result3.png"); | |
File.Delete(dataDir + "result4.png"); | |
File.Delete(dataDir + "result5.png"); | |
File.Delete(dataDir + "result6.png"); |
Using Graph Cut auto masking with specified assumed objects data
The following example demonstrates saving of the image masking results with feathering based on image size. Image masking is performed using auto calculated default strokes. Additionally, the data of the two assumed objects are also specified in the AssumedObjects property of the AutoMaskingGraphCutOptions.
using Aspose.Imaging; | |
using Aspose.Imaging.FileFormats.Png; | |
using Aspose.Imaging.ImageOptions; | |
using Aspose.Imaging.Masking; | |
using Aspose.Imaging.Masking.Options; | |
using Aspose.Imaging.Masking.Result; | |
using Aspose.Imaging.Sources; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
string templatesFolder = @"c:\Users\USER\Downloads\templates\"; | |
string dataDir = templatesFolder; | |
// To improve masking results, data of the specific objects that should be included in the foreground masking result could be provided. | |
List<AssumedObjectData> assumedObjects = new List<AssumedObjectData>(); | |
// THe object type and the area containing that object should be specified. | |
assumedObjects.Add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(0, 0, 256, 365))); | |
MaskingResult results; | |
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg")) | |
{ | |
// To use Graph Cut with auto calculated strokes, AutoMaskingGraphCutOptions is used. | |
AutoMaskingGraphCutOptions options = new AutoMaskingGraphCutOptions | |
{ | |
AssumedObjects = assumedObjects, | |
// Indicating that a new calculation of the default strokes should be performed during the image decomposition. | |
CalculateDefaultStrokes = true, | |
// Setting post-process feathering radius based on the image size. | |
FeatheringRadius = (Math.Max(image.Width, image.Height) / 500) + 1, | |
Method = SegmentationMethod.GraphCut, | |
Decompose = false, | |
ExportOptions = | |
new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new FileCreateSource(dataDir + "result.png") | |
}, | |
BackgroundReplacementColor = Color.Transparent | |
}; | |
results = new ImageMasking(image).Decompose(options); | |
// Saving final masking result. | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result2.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
File.Delete(dataDir + "result.png"); | |
File.Delete(dataDir + "result2.png"); |
Performing Graph Cut segmentation with user-defined point and feathering radius
The following example demonstrates saving of the Graph Cut image masking result with feathering set to 3. Image masking is performed using the user-defined Point array.
using Aspose.Imaging; | |
using Aspose.Imaging.FileFormats.Png; | |
using Aspose.Imaging.ImageOptions; | |
using Aspose.Imaging.Masking; | |
using Aspose.Imaging.Masking.Options; | |
using Aspose.Imaging.Masking.Result; | |
using Aspose.Imaging.Sources; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
string templatesFolder = @"c:\Users\USER\Downloads\templates\"; | |
string dataDir = templatesFolder; | |
MaskingResult results; | |
using (RasterImage image = (RasterImage)Image.Load(dataDir + "template.jpg")) | |
{ | |
// To apply feathering, GraphCutMaskingOptions is used. | |
GraphCutMaskingOptions options = new GraphCutMaskingOptions() | |
{ | |
// Setting post-process feathering radius. | |
FeatheringRadius = 3, | |
Method = SegmentationMethod.GraphCut, | |
Decompose = false, | |
ExportOptions = | |
new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new FileCreateSource(dataDir + "result.png") | |
}, | |
BackgroundReplacementColor = Color.Transparent, | |
// Foreground/background strokes are passed to the | |
// AutoMaskingArgs Args property's ObjectsPoints array. | |
Args = new AutoMaskingArgs() | |
{ | |
ObjectsPoints = new Point[][] | |
{ | |
new Point[] | |
{ | |
new Point(100, 100), | |
}, | |
} | |
} | |
}; | |
results = new ImageMasking(image).Decompose(options); | |
// Saving final masking result. | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result2.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
File.Delete(dataDir + "result.png"); | |
File.Delete(dataDir + "result2.png"); |
The following code snippet provided below demonstrates how to apply auto masking to a raster image.
using Aspose.Imaging; | |
using Aspose.Imaging.FileFormats.Png; | |
using Aspose.Imaging.ImageOptions; | |
using Aspose.Imaging.Masking; | |
using Aspose.Imaging.Masking.Options; | |
using Aspose.Imaging.Masking.Result; | |
using Aspose.Imaging.Sources; | |
using System.IO; | |
string templatesFolder = @"c:\Users\USER\Downloads\templates\"; | |
string dataDir = templatesFolder; | |
string sourceFileName = dataDir + "template.png"; | |
AutoMaskingArgs maskingArgs = new AutoMaskingArgs() | |
{ | |
ObjectsPoints = new Point[][] | |
{ | |
new Point[] | |
{ | |
new Point(100, 100), | |
new Point(200, 200), | |
new Point(300, 300), | |
}, | |
} | |
}; | |
string outputFileName = dataDir + "result.png"; | |
using (RasterImage image = (RasterImage)Image.Load(sourceFileName)) | |
{ | |
MaskingOptions maskingOptions = new MaskingOptions() | |
{ | |
Method = SegmentationMethod.GraphCut, | |
Args = maskingArgs, | |
Decompose = false, | |
ExportOptions = | |
new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new StreamSource(new MemoryStream()) | |
}, | |
}; | |
MaskingResult results = new ImageMasking(image).Decompose(maskingOptions); | |
// Saving final masking result. | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result2.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
File.Delete(dataDir + "result.png"); | |
File.Delete(dataDir + "result2.png"); |
Manual Masking
The following code snippet provided below demonstrates how to apply manual masking to a raster image.
using Aspose.Imaging; | |
using Aspose.Imaging.FileFormats.Png; | |
using Aspose.Imaging.ImageOptions; | |
using Aspose.Imaging.Masking; | |
using Aspose.Imaging.Masking.Options; | |
using Aspose.Imaging.Masking.Result; | |
using Aspose.Imaging.Shapes; | |
using Aspose.Imaging.Sources; | |
using System.IO; | |
string templatesFolder = @"c:\Users\USER\Downloads\templates\"; | |
string dataDir = templatesFolder; | |
string sourceFileName = dataDir + "couple.png"; | |
GraphicsPath manualMask = new GraphicsPath(); | |
Figure firstFigure = new Figure(); | |
firstFigure.AddShape(new EllipseShape(new RectangleF(100, 30, 40, 40))); | |
firstFigure.AddShape(new RectangleShape(new RectangleF(10, 200, 50, 30))); | |
manualMask.AddFigure(firstFigure); | |
GraphicsPath subPath = new GraphicsPath(); | |
Figure secondFigure = new Figure(); | |
secondFigure.AddShape( | |
new PolygonShape( | |
new PointF[] | |
{ | |
new PointF(310, 100), new PointF(350, 200), new PointF(250, 200) | |
}, true)); | |
secondFigure.AddShape(new PieShape(new RectangleF(10, 10, 80, 80), 30, 120)); | |
subPath.AddFigure(secondFigure); | |
manualMask.AddPath(subPath); | |
using (RasterImage image = (RasterImage)Image.Load(sourceFileName)) | |
{ | |
MaskingOptions maskingOptions = new MaskingOptions() | |
{ | |
Method = SegmentationMethod.Manual, | |
Args = new ManualMaskingArgs | |
{ | |
Mask = manualMask | |
}, | |
Decompose = false, | |
ExportOptions = | |
new PngOptions() | |
{ | |
ColorType = PngColorType.TruecolorWithAlpha, | |
Source = new StreamSource(new MemoryStream()) | |
}, | |
}; | |
MaskingResult results = new ImageMasking(image).Decompose(maskingOptions); | |
// Saving final masking result. | |
using (RasterImage resultImage = (RasterImage)results[1].GetImage()) | |
{ | |
resultImage.Save(dataDir + "result.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha }); | |
} | |
} | |
File.Delete(dataDir + "result.png"); |