Remove background from images in Java
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
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(); | |
} |
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(); | |
} |
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.
// 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(); | |
} |
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.
MaskingResult[] results; | |
try (RasterImage image = (RasterImage) Image.load("input.jpg")) | |
{ | |
// To apply feathering, GraphCutMaskingOptions is used. | |
GraphCutMaskingOptions options = new GraphCutMaskingOptions(); | |
// 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); | |
// Foreground/background strokes are passed to the | |
// AutoMaskingArgs Args property's ObjectsPoints array. | |
final AutoMaskingArgs maskingArgs = new AutoMaskingArgs(); | |
maskingArgs.setObjectsPoints(new Point[][] | |
{ | |
new Point[] | |
{ | |
new Point(100, 100), | |
}, | |
}); | |
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 following code snippet provided below demonstrates how to apply auto masking to a raster image.
// The path to the documents directory. | |
String dataDir = "ModifyingImages/"; | |
String sourceFileName = dataDir + "Colored by Faith_small.psd"; | |
String inputPointsFileName = dataDir + "Java_ColoredByFaith_small.dat"; | |
AutoMaskingArgs maskingArgs = new AutoMaskingArgs(); | |
fillInputPoints(inputPointsFileName, maskingArgs); | |
String outputFileName = dataDir + "Colored by Faith_small_auto.png"; | |
RasterImage image = (RasterImage) Image.load(sourceFileName); | |
try | |
{ | |
MaskingOptions maskingOptions = new MaskingOptions(); | |
maskingOptions.setMethod(SegmentationMethod.GraphCut); | |
maskingOptions.setArgs(maskingArgs); | |
maskingOptions.setDecompose(false); | |
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(); | |
} |
private static void fillInputPoints(String filePath, AutoMaskingArgs autoMaskingArgs) throws IOException | |
{ | |
InputStream inputStream = new FileInputStream(filePath); | |
try | |
{ | |
LEIntegerReader reader = new LEIntegerReader(inputStream); | |
boolean hasObjectRectangles = inputStream.read() != 0; | |
boolean hasObjectPoints = inputStream.read() != 0; | |
autoMaskingArgs.setObjectsRectangles(null); | |
autoMaskingArgs.setObjectsPoints(null); | |
if (hasObjectRectangles) | |
{ | |
int len = reader.read(); | |
Rectangle[] rects = new Rectangle[len]; | |
for (int i = 0; i < len; i++) | |
{ | |
// firstly Y | |
int y = reader.read(); | |
// secondly X | |
int x = reader.read(); | |
// width | |
int width = reader.read(); | |
// height | |
int height = reader.read(); | |
rects[i] = new Rectangle(x, y, width, height); | |
} | |
autoMaskingArgs.setObjectsRectangles(rects); | |
} | |
if (hasObjectPoints) | |
{ | |
int len = reader.read(); | |
Point[][] points = new Point[len][]; | |
for (int i = 0; i < len; i++) | |
{ | |
int il = reader.read(); | |
points[i] = new Point[il]; | |
for (int j = 0; j < il; j++) | |
{ | |
int x = reader.read(); | |
int y = reader.read(); | |
points[i][j] = new Point(x, y); | |
} | |
} | |
autoMaskingArgs.setObjectsPoints(points); | |
} | |
} | |
finally | |
{ | |
inputStream.close(); | |
} | |
} |
private static class LEIntegerReader | |
{ | |
private final InputStream stream; | |
private final byte[] buffer = new byte[4]; | |
LEIntegerReader(InputStream stream) | |
{ | |
this.stream = stream; | |
} | |
int read() throws IOException | |
{ | |
int len = stream.read(buffer); | |
if (len != 4) | |
{ | |
throw new RuntimeException("Unexpected EOF"); | |
} | |
return ((buffer[3] & 0xff) << 24) | ((buffer[2] & 0xff) << 16) | ((buffer[1] & 0xff) << 8) | (buffer[0] & 0xFF); | |
} | |
} |
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(); | |
} |