Image masking

Image masking (simplified image segmentation) is the process of dividing image to background and foreground parts. It is widely used for recognition, diagnostics, computer vision.

Example of masked image with changed background is presented below.

|

|

|

| | ——————————————- | ——————————————- | ———————————————————- | | Fig. 1 (a) Original image | (b) Manually masked image | (c) Automatically masked image with segmentation algorithm |

Here we can observe on figures 1 - b, c image masking results - background and foreground of initial image 1 - a.

Aspose.Imaging supports the following types of masking.

  • Manual Masking - Using a set of ROIs as the mask. The ROIs for each slice are used to define the mask. Needed additional user input.
  • Auto Masking - Automatic mode that does not require from user lot of input data, but can be not so accurate.  

Aspose.Imaging supports few automatic masking algorithms, among them: K-means, Watershed and Graph Cut algorithm (one of proposed automatic methods).

Below we can observe masking results of original image.

Original image 1. K-means image segmentation algorithm (Value metric : Color intensity) 2. K-means image segmentation algorithm (Value metric : Color intensity), with indicating rectangular area for foreground 3. K-means image segmentation algorithm (Value metric : Color intensity * Euclidean distance) 4. Marker-controlled Watershed algorithm 5. Graph Cut algorithm (with indicating areas by user)

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();
}

Auto masking

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);
}
}