在Java中将图像转换为灰度的错误亮度

我使用以下代码在Java中将图像转换为灰度:

BufferedImage originalImage = ImageIO.read(new File("/home/david/input.bmp")); BufferedImage grayImage = new BufferedImage(originalImage.getWidth() , originalImage.getHeight() , BufferedImage.TYPE_BYTE_GRAY); ColorSpace gray = ColorSpace.getInstance(ColorSpace.CS_GRAY); ColorConvertOp colorConvert = new ColorConvertOp(gray, null); colorConvert.filter(originalImage, grayImage); ImageIO.write(grayImage, "bmp", new File("/home/david/output_java.bmp")); 

这似乎有效,但问题是输出图像与gimp生成的灰度图像非常不同(参见下面的示例)。

  1. 我可以控制图像是如何生成的?
  2. 我如何才能使结果与gimp结果更相似?

原始图片:

彩色原始图像

在Java中生成的灰度图像:

ColorConvertOp生成的灰度图像

在Gimp中生成的灰度图像( Image -> Mode -> Grayscale ):

在Gimp生成的灰度图像

顺便说一下:我有一堆来自ffmpeg的图像(带有灰色选项),它们就像Gimp图像所以因为这样我想要那样的图像。

找出Gimp使用的转换公式。 它可能需要一些人类的颜色感知,而Java实现是数学的(R+G+B)/ 3

最后我写了实现BufferedImageOp接口的GrayscaleFilter类。

我已经关注了这个关于Java图像处理的非常好的指南。

这是相关的代码片段:

 public class GrayscaleFilter extends AbstractFilter { public final static double[] METHOD_AVERAGE = {1.0/3.0, 1.0/3.0, 1.0/3.0}; public final static double[] METHOD_GIMP_LUMINOSITY = {0.21, 0.71, 0.07}; public GrayscaleFilter(final double[] rgb) { this(rgb[0], rgb[1], rgb[2]); } public BufferedImage filter(BufferedImage src, BufferedImage dest) { if (src.getType() == BufferedImage.TYPE_BYTE_GRAY) { dest = src; return dest; } if (dest == null) dest = createCompatibleDestImage(src, null); final int width = src.getWidth(); final int height = src.getHeight(); int[] inPixels = new int[width * height]; GraphicsUtilities.getPixels(src, 0, 0, width, height, inPixels); byte[] outPixels = doFilter(inPixels); GraphicsUtilities.setPixels(dest, 0, 0, width, height, outPixels); return dest; } private byte[] doFilter(int[] inputPixels) { int red, green, blue; int i = 0; byte[] outPixels = new byte[inputPixels.length]; for(int pixel : inputPixels) { // Obtengo valores originales red = (pixel >> 16) & 0xFF; green = (pixel >> 8) & 0xFF; blue = pixel & 0xFF; // Calculo valores nuevos outPixels[i++] = (byte)( red * red_part + green * green_part + blue * blue_part ); } return outPixels; } public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { return new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_GRAY); } }