Remove background from images

Auto Masking

To receive better background removing results, Graph Cut segmentation with pre-calculated brushstrokes can be used.

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.

MaskingResult[] results;
try (RasterImage image = (RasterImage)Image.load("input.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.
options.setCalculateDefaultStrokes(true);
// Setting post-process feathering radius based on the image size.
options.setFeatheringRadius((Math.max(image.getWidth(), image.getHeight()) / 500) + 1);
options.setMethod(SegmentationMethod.GraphCut);
options.setDecompose(false);
options.setBackgroundReplacementColor(Color.getTransparent());
final PngOptions exportOptions = new PngOptions();
exportOptions.setColorType(PngColorType.TruecolorWithAlpha);
exportOptions.setSource(new FileCreateSource("tempFile"));
options.setExportOptions(exportOptions);
results = new ImageMasking(image).decompose(options);
}
try (RasterImage resultImage = (RasterImage)results[1].getImage())
{
final PngOptions exportOptions = new PngOptions();
exportOptions.setColorType(PngColorType.TruecolorWithAlpha);
resultImage.save("output.png", exportOptions);
}
// Release resources
for (MaskingResult result : results)
{
result.close();
}

The figure below illustrates the result of the Graph Cut auto masking with feathering:

Original image

Auto masked image

Fig. 2 (a) Original image (b) Auto masked image

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.

// 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 ArrayList<AssumedObjectData>(2);
// THe object type and the area containing that object should be specified.
assumedObjects.add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(100, 100, 150, 300)));
assumedObjects.add(new AssumedObjectData(DetectedObjectType.Dog, new Rectangle(300, 100, 50, 30)));
MaskingResult[] results;
AutoMaskingGraphCutOptions options;
// First masking iteration is performed to get auto calculated foreground/background brushstrokes.
try (RasterImage image = (RasterImage)Image.load("input.jpg"))
{
// To use Graph Cut with auto calculated strokes, AutoMaskingGraphCutOptions is used.
options = new AutoMaskingGraphCutOptions();
options.setAssumedObjects(assumedObjects);
// Indicating that a new calculation of the default strokes should be performed during the image decomposition.
options.setCalculateDefaultStrokes(true);
// Setting post-process feathering radius.
options.setFeatheringRadius(3);
options.setMethod(SegmentationMethod.GraphCut);
options.setDecompose(false);
options.setBackgroundReplacementColor(Color.getTransparent());
final PngOptions pngOptions = new PngOptions();
pngOptions.setColorType(PngColorType.TruecolorWithAlpha);
pngOptions.setSource(new FileCreateSource("tempFile"));
options.setExportOptions(pngOptions);
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.
Point[] appliedBackgroundStrokes = options.getDefaultBackgroundStrokes();
Point[] appliedForegroundStrokes = options.getDefaultForegroundStrokes();
Rectangle[] appliedObjectRectangles = options.getDefaultObjectsRectangles();
try (RasterImage resultImage = (RasterImage)results[1].getImage())
{
final PngOptions pngOptions = new PngOptions();
pngOptions.setColorType(PngColorType.TruecolorWithAlpha);
resultImage.save("output.png", pngOptions);
}
// Second masking iteration is performed to further improve masking quality by adding new manually chosen foreground/background points.
try (RasterImage image = (RasterImage)Image.load("input.jpg"))
{
// Re-using AutoMaskingGraphCutOptions there is no need to perform default stroke calculations a second time.
options.setCalculateDefaultStrokes(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.
final AutoMaskingArgs maskingArgs = new AutoMaskingArgs();
maskingArgs.setObjectsPoints(new Point[][]
{
new Point[] { new Point(100, 100), new Point(150, 100) },
new Point[] { new Point(500, 200) },
});
maskingArgs.setObjectsRectangles(new Rectangle[]
{
new Rectangle(100, 100, 300, 300),
});
options.setArgs(maskingArgs);
results = new ImageMasking(image).decompose(options);
}
// Saving final masking result.
try (RasterImage resultImage = (RasterImage)results[1].getImage())
{
final PngOptions pngOptions = new PngOptions();
pngOptions.setColorType(PngColorType.TruecolorWithAlpha);
resultImage.save("output.png", pngOptions);
}
// Release resources
for (MaskingResult result : results)
{
result.close();
}

The figure below illustrates the result of re-using default strokes in repeated auto masking with new points:

Original image

Auto masked image

Fig. 3 (a) Original image (b) Auto masked image

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 a one assumed human object is also specified in the AssumedObjects property of the AutoMaskingGraphCutOptions.

// 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 ArrayList<AssumedObjectData>(2);
// THe object type and the area containing that object should be specified.
assumedObjects.add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(100, 100, 150, 300)));
assumedObjects.add(new AssumedObjectData(DetectedObjectType.Dog, new Rectangle(300, 100, 50, 30)));
MaskingResult[] results;
try (RasterImage image = (RasterImage)Image.load("input.jpg"))
{
// To use Graph Cut with auto calculated strokes, AutoMaskingGraphCutOptions is used.
AutoMaskingGraphCutOptions options = new AutoMaskingGraphCutOptions();
options.setAssumedObjects(assumedObjects);
// Indicating that a new calculation of the default strokes should be performed during the image decomposition.
options.setCalculateDefaultStrokes(true);
// Setting post-process feathering radius based on the image size.
options.setFeatheringRadius((Math.max(image.getWidth(), image.getHeight()) / 500) + 1);
options.setMethod(SegmentationMethod.GraphCut);
options.setDecompose(false);
options.setBackgroundReplacementColor(Color.getTransparent());
final PngOptions pngOptions = new PngOptions();
pngOptions.setColorType(PngColorType.TruecolorWithAlpha);
pngOptions.setSource(new FileCreateSource("tempFile"));
options.setExportOptions(pngOptions);
results = new ImageMasking(image).decompose(options);
}
// Saving final masking result.
try (RasterImage resultImage = (RasterImage)results[1].getImage())
{
final PngOptions pngOptions = new PngOptions();
pngOptions.setColorType(PngColorType.TruecolorWithAlpha);
resultImage.save("output.png", pngOptions);
}
// Release resources
for (MaskingResult result : results)
{
result.close();
}

The figure below illustrates the result of the Graph Cut auto masking with specified assumed object data:

Original image

Auto masked image

Fig. 4 (a) Original image (b) Auto masked image

Manual Masking

The following code snippet provided below demonstrates how to apply manual masking to a raster image.

// The path to the documents directory.
String dataDir = "ModifyingImages/";
String sourceFileName = dataDir + "Colored by Faith_small.psd";
String outputFileName = dataDir + "Colored by Faith_small_manual.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);
RasterImage image = (RasterImage) Image.load(sourceFileName);
try
{
MaskingOptions maskingOptions = new MaskingOptions();
maskingOptions.setMethod(SegmentationMethod.Manual);
maskingOptions.setDecompose(false);
ManualMaskingArgs argus = new ManualMaskingArgs();
argus.setMask(manualMask);
maskingOptions.setArgs(argus);
PngOptions options = new PngOptions();
options.setColorType(PngColorType.TruecolorWithAlpha);
options.setSource(new StreamSource());
maskingOptions.setExportOptions(options);
MaskingResult[] maskingResults = new ImageMasking(image).decompose(maskingOptions);
Image resultImage = maskingResults[1].getImage();
try
{
resultImage.save(outputFileName);
}
finally
{
resultImage.close();
}
}
finally
{
image.close();
}

The figure below illustrates the result of the manual masking:

Original image

Manually masked image

Fig. 5 (a) Original image (b) Manually masked image