Home > Back-end >  BufferedImage -> int[] -> BufferedImage result in greyed black
BufferedImage -> int[] -> BufferedImage result in greyed black

Time:10-14

I am doing some basic experimentation on picture filtering using convolution matrix, based on the Wikipedia page about kernels in image processing.

In order to compute the RGB transformations, I am reading the bitmap via a BufferedImage then get the pixels with getRgb(). While testing the simplest identity filter I noticed that for a specific picture I was getting some grey instead of the original black, while for some other picture, the black was OK.

After more testing, I found that without any transform, a simple BufferedImage -> int[] -> BufferedImage results in the greyed result.

What am I missing ? ImageMagick identify shows that both are 8-bit 256 colors pictures without alpha channels.

betty1.png PNG 339x600 339x600 0 0 8-bit Gray 256c 24526B 0.000u 0:00.000
betty2.jpg JPEG 603x797 603x797 0 0 8-bit Gray 256c 126773B 0.000u 0:00.001

With this picture the result is as expected. result ok

With this one, the result is unexpectedly greyed. result nok

Here is a simple sscce test class to show the problem:

import java.awt.BorderLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;

/* simple test class for convolution matrix */
public class CopyPic {

    public static void main(String args[]) throws FileNotFoundException, IOException {
        if (args.length < 1) {
            System.err.println("Usage: CopyPic <picture_file>");
            System.exit(1);
        }
        String        imgPath   = args[0];
        String        inputName = imgPath.substring(0, imgPath.lastIndexOf("."));
        File          ifile     = new File(imgPath);
        InputStream   fis_in    = new FileInputStream(ifile);
        BufferedImage bi_in     = ImageIO.read(fis_in);
        fis_in.close();

        int width  = bi_in.getWidth();
        int height = bi_in.getHeight();
        System.out.println(String.format("%s = %d x %d", imgPath, width, height));
        int[] rgb_in = new int[width * height];
        bi_in.getRGB(0, 0, width, height, rgb_in, 0, width);

        BufferedImage bi_out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // for (int y = 0; y < height; y  ) {
            // for (int x = 0; x < width; x  ) {
                // bi_out.setRGB(x, y, rgb_out[y * width   x]);
            // }
        // }
        bi_out.setRGB(0, 0, width, height, rgb_in, 0, width);
        
        display(bi_in, bi_out);
        
        String outputName = inputName   "-copy.png";
        File         ofile   = new File(outputName);
        OutputStream fos_out = new FileOutputStream(ofile);
        ImageIO.write(bi_out, "PNG", fos_out);
        fos_out.flush();
        fos_out.close();
        System.out.println("Wrote "   outputName);
    }
    // use that to have internal viewer
    private static JFrame frame;
    private static JLabel label1, label2;
    private static void display(BufferedImage img1, BufferedImage img2) {
        if (frame == null) {
            frame = new JFrame();
            frame.setTitle(String.format("%dx%d Original / Copy", img1.getWidth(), img1.getHeight()));
            frame.setSize(img1.getWidth()   img2.getWidth(), img1.getHeight());
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            label1 = new JLabel();
            label1.setIcon(new ImageIcon(img1));
            frame.getContentPane().add(label1, BorderLayout.WEST);
            label2 = new JLabel();
            label2.setIcon(new ImageIcon(img2));
            frame.getContentPane().add(label2, BorderLayout.EAST);
            frame.setLocationRelativeTo(null);
            frame.pack();
            frame.setVisible(true);
        } else {
            label1.setIcon(new ImageIcon(img1));
            label2.setIcon(new ImageIcon(img2));
        }
    }

}

CodePudding user response:

When the ImageIO.read function creates a BufferedImage it uses the type that it thinks is best suited. This type might not be what you expect. In particular, for a JPG image the type might not be TYPE_INT_ARGB.

This is the case for your second image and becomes evident when you print the type of that image:

System.out.println(bi_in.getType());

For that image, this prints 10 on my machine, which represents TYPE_BYTE_GRAY.

So, to fix your problem you should use:

BufferedImage bi_out = new BufferedImage(width, height, bi_in.getType()); 
  • Related