Binarize a color image to a bw image

Simplified problem:
I would like to create a 1bit bw image from a color image. To do that I use the Bradley’s method.

RasterImage ri = (RasterImage)RasterImage.load("C:\\temp\\in.png");
ri.binarizeBradley(threshold);
ri.save("C:\\temp\\out.png");

Unfortunately the out.png has a bit depth of 24 instead of 1.

Actual problem:
I have a BufferedImage of type BufferedImage.TYPE_INT_RGB and would like to binarize it.
The resulting BufferedImage should be of type BufferedImage.TYPE_BYTE_BINARY.

public BufferedImage binarize(BufferedImage rgbImage) {
	RasterImage rasterImage = ImageExtensions.fromJava(rgbImage);
	rasterImage.binarizeBradley(8.0);
	BufferedImage result = ImageExtensions.toJava(rasterImage);
	return result;
}

The resulting BufferedImage has type BufferedImage.TYPE_INT_ARGB instead of BufferedImage.TYPE_BYTE_BINARY

@martin.duerig

Can you please share the source PNG file along with generated output PNG file so that we may analyze that on our end to assist you further.

You can download the files here (available till December 25, 2020).

I provided three input und three output examples with different source bit depths

  • 8 bit depth. Input: in8bit.png, output: out8bit.png
  • 24 bit depth. Input: in24bit.png, output: out24bit.png
  • 32 bit depth. Input: in32bit.png, output: out32bit.png

As already mentioned, none of the output pictures results in a bit depth of 1.

@martin.duerig

I have added a ticket with ID IMAGINGJAVA-1972 in our issue tracking system to further investigate and resolve the issue on our ed. This thread has been linked with the issue so that you may be notified once the issue will be fixed.

@martin.duerig

Can you please try using the following code on your ent to be able to save to Grayscale PNG 1,2,4,8 bits. We have attached them in attached zip file for reference.

using (Aspose.Imaging.FileFormats.Png.PngImage image =
(Aspose.Imaging.FileFormats.Png.PngImage)Image.Load(@"in8bit.png")
)
{
image.BinarizeBradley(10);
image.Save(
@"out_binarize1bit.png",
new Aspose.Imaging.ImageOptions.PngOptions()
{
Progressive = false,
ColorType = Aspose.Imaging.FileFormats.Png.PngColorType.Grayscale,
BitDepth = (byte)1
});
}

1_8_bit_png_output.zip (1.3 MB)

Simplified problem:
I rewrote your C# code in Java (I’m using the java library aspose-imaging-20.12-jdk16.jar)

    PngOptions options = new PngOptions();
    options.setBitDepth((byte)1);
    options.setColorType(PngColorType.Grayscale);
    options.setProgressive(false);
    PngImage pngImage = (PngImage) PngImage.load("C:\\temp\\in8.png");
    pngImage.binarizeBradley(8.0);
    pngImage.save("C:\\temp\\out8.png", options);

The code above works fine and I get a bit depth of exactly 1. This solves the simplified problem.

Actual Problem
What I need for the actual problem is a single band BufferedImage.

    BufferedImage bufferedImage = ImageExtensions.toJava(pngImage); // no options available here
    System.out.println(bufferedImage.getColorModel().getNumColorComponents()); // should be 1 instead of 4

Unfortunately the ImageExtensions.toJava method signature cannot be parametrized to accept a BufferedImage type.
Therefore I came up with the following workaround

public BufferedImage binarize(BufferedImage rgbImage) {
    RasterImage rasterImage = ImageExtensions.fromJava(rgbImage);
    rasterImage.binarizeBradley(8.0);
    BufferedImage source = ImageExtensions.toJava(rasterImage);
    BufferedImage result = renderBw(source);
    return result;
}

private BufferedImage renderBw(BufferedImage source) {
    BufferedImage result = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
    Graphics2D g2d = null;
    try {
        g2d = result.createGraphics();
        g2d.drawImage(source, 0, 0, null);
    } finally {
        if (g2d != null) {
            g2d.dispose();
        }
    }
    return result;
}

@martin.duerig

Thank you for the elaboration and sharing further details. I have included the information in our issue tracking system and will get back to you with feedback as soon as it will be shared.

1 Like

@martin.duerig

In Aspose.Imaging for Java 21.2, new utility methods are implemented in com.aspose.imaging.extensions.ImageExtensions that allow to define a format (bpp,storage type) of output image BufferImage.

public static java.awt.image.BufferedImage toJava(Image image, int bufferedImageType)
public static java.awt.image.BufferedImage toJava(Image image, Rectangle subImageRect, int bufferedImageType)

You may consider using following code for this purpose:

final String inputFile = "in32bit.png";
BufferedImage rgbImage = ImageIO.read(new File(inputFile));
RasterImage rasterImage = ImageExtensions.fromJava(rgbImage);
try
{
    rasterImage.binarizeBradley(8.0);
    BufferedImage binaryImage = ImageExtensions.toJava(rasterImage, BufferedImage.TYPE_BYTE_BINARY);

    assert binaryImage.getColorModel().getPixelSize() == 1;

    ImageIO.write(binaryImage, "PNG", new File("out1bit.png"));
}
finally
{
    rasterImage.close();
}

The issues you have found earlier (filed as IMAGINGJAVA-1972) have been fixed in this update.