2

I want to invert and gray scale an image. Here is my original image:
enter image description here

Here is the final result I want to achieve (produced with Paint.NET):
enter image description here

However using some (basic?) Java code found on Internet, I only get the picture below: enter image description here

Here is the code I used:

private static final byte[] invertTable;

static {
    invertTable = new byte[256];
    for (int i = 0; i < 256; i++) {
        invertTable[i] = (byte) (255 - i);
    }
}

private static BufferedImage grayScale(BufferedImage source) {
    ColorConvertOp grayScale = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

    return grayScale.filter(source,null);
}

private static BufferedImage invertImage(final BufferedImage src) {
    final int w = src.getWidth();

    final int h = src.getHeight();

    final BufferedImage dst = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

    final BufferedImageOp invertOp = new LookupOp(new ByteLookupTable(0, invertTable), null);

    return invertOp.filter(src, dst);
}

// ...
BufferedImage sourceImage = ...
BufferedImage convertedImage = grayScale(invertImage(sourceImage));

How can I improve the above code?

Stephan
  • 41,764
  • 65
  • 238
  • 329

3 Answers3

6

Using Imgproc and Core, I did

Mat src = new Mat();
Mat gray = new Mat();
src = Highgui.imread("...");
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
Core.bitwise_not(gray, gray);
Highgui.imwrite("...", gray);

and got something closer, though not identical:

OpenCV default grayscale mapping + bitwise invert

mtrw
  • 34,200
  • 7
  • 63
  • 71
  • Which Maven dependency should I use to get `Imgproc` and `Core`? – Stephan Apr 30 '15 at 07:05
  • I am only getting started with Java, and haven't gotten to using Maven yet. I followed the directions in http://docs.opencv.org/2.4.4-beta/doc/tutorials/introduction/desktop_java/java_dev_intro.html#create-a-simple-java-project-in-eclipse, and added `import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.highgui.Highgui; import org.opencv.imgproc.Imgproc;` Hope that helps – mtrw Apr 30 '15 at 10:49
4

In the title it says OpenCV but there's a tag for BoofCV. So here's how to do it in BoofCV:

BufferedImage orig = UtilImageIO.loadImage("filename");
ImageUInt8 gray = ConvertBufferedImage.convertFrom(orig, (ImageUInt8) null);
ImageUInt8 inverted = new ImageUInt8(gray.width,gray.height);
GrayImageOps.invert(gray,255,inverted);

enter image description here

lessthanoptimal
  • 2,722
  • 2
  • 23
  • 25
1

While I'm not familiar with ColorConvertOp, I would suspect that it is converting the color image to greyscale in a different way then Paint.NET is. There is no correct way.

Take a look at the yellow. Should yellow be a dark or light grey? It looks like Paint.NET thinks it is light and the ColorConvertOp thinks it is dark.

Try doing the conversion yourself by just averaging the red/green/blue.

(red+green+blue)/3
denver
  • 2,863
  • 2
  • 31
  • 45
  • 2
    Be warned: the average of color components is one way to get a grayscale image, but it doesn't match the sensitivity of human eyes to different colors. Doing a weighted average will give results that probably "look better". A quick overview can be found [here](http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/) – Aurelius Apr 29 '15 at 21:56
  • As Aurelius says there are many ways to do it, each attempting to make the image, better, and more accurate. In most applications it doesn't really matter which approach is taken. – denver Apr 30 '15 at 14:13