将TYPE_INT_RGB转换为TYPE_BYTE_GRAY图像会产生错误的结果

问题描述 投票:1回答:1

我正在尝试将24位RGB格式的灰度图像转换为8位格式的灰度图像。换句话说,输入和输出在视觉上应该是相同的,只是通道数会改变。这是输入图像:

“

用于将其转换为8位的代码:

File input = new File("input.jpg");
File output = new File("output.jpg");

// Read 24-bit RGB input JPEG.
BufferedImage rgbImage = ImageIO.read(input);
int w = rgbImage.getWidth();
int h = rgbImage.getHeight();

// Create 8-bit gray output image from input.
BufferedImage grayImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
int[] rgbArray = rgbImage.getRGB(0, 0, w, h, null, 0, w);
grayImage.setRGB(0, 0, w, h, rgbArray, 0, w);

// Save output.
ImageIO.write(grayImage, "jpg", output);

这是输出图像:

“输出”

如您所见,有一些细微的差别。但是它们应该是相同的。对于看不到它的人,这里是the difference between the two images(当在Gimp中使用“差异混合”模式查看时,全黑表示没有差异)。如果我使用PNG代替输入和输出,则会发生相同的问题。

grayImage.setRGB之后,我尝试比较两个图像中相同像素的颜色值:

int color1 = rgbImage.getRGB(230, 150);  // This returns 0xFF6D6D6D.
int color2 = grayImage.getRGB(230, 150);  // This also returns 0xFF6D6D6D.

两种颜色相同。但是,如果我对Gimp中的图像进行相同的比较,则会分别得到0xFF6D6D6D0xFF272727……巨大的差异。

这里发生了什么?有什么办法可以从24位灰度图像中获得相同的8位图像?我正在使用Oracle JDK 1.8作记录。

java jpeg bufferedimage javax.imageio color-channel
1个回答
2
投票

我测试的前两件事,我打印了两个图像。

BufferedImage @ 544fa968:类型= 5 ColorModel:#pixelBits = 24 numComponents = 3色彩空间= java.awt.color.ICC_ColorSpace@68e5eea7透明度= 1具有alpha = false isAlphaPre = false ByteInterleavedRaster:宽度= 400高度= 400 #numDataElements 3个dataOff [0] = 2

BufferedImage @ 11fc564b:类型= 10 ColorModel:#pixelBits = 8 numComponents = 1颜色空间= java.awt.color.ICC_ColorSpace@394a2528透明度= 1具有alpha = false isAlphaPre = false ByteInterleavedRaster:宽度= 400高度= 400 #numDataElements 1个数据关闭[0] = 0

我们可以看到图像具有不同的色彩空间,并且数据偏移量也不同。

而且我使用图形在输出上绘制原始图像。

Graphics g = grayImage.getGraphics();
g.drawImage(rgbImage, 0, 0, null);

这很好。我将图片另存为png,并不是因为它会改变您看到的效果,并且当我在两张图片之间进行区别时,它们是相同的。

底线是,两种不同图像类型的rgb值不同。因此,尽管使用get rgb看到相同的值,但显示它们时,它们将被解释为不同的值。

使用图形的速度较慢,但​​是可以输出正确的图像。

我认为这里的区别是setRGB / getRGB以非直观的方式对数据进行操作。

DataBuffer rgbBuffer = rgbImage.getRaster().getDataBuffer();
DataBuffer grayBuffer = grayImage.getRaster().getDataBuffer();

System.out.println(grayBuffer.size() + ", " + rgbBuffer.size() );
for(int i = 0; i<10; i++){
    System.out.println(
        grayBuffer.getElem(i) + "\t"
        + rgbBuffer.getElem(3*i) + ", " 
        + rgbBuffer.getElem(3*i+1) + ", " 
        + rgbBuffer.getElem(3*i + 2) );
}

显示我们期望的数据。 rgb缓冲区的大小是其3倍,像素直接对应。

160000,480000255 255、255、255255 255、255、255254254、254、254253253、253、253252252、252、252252252、252、252251251、251、251251251、251、251250250、250、250250250、250、250

当我们检查相应的rgb值时。

for(int i = 0; i<10; i++){
    System.out.println( 
        Integer.toHexString( grayImage.getRGB(i, 0) ) + ", "
        +  Integer.toHexString( rgbImage.getRGB(i, 0) ) + "  " );
}

ffffffff,ffffffffffffffff,ffffffffffffffff,ffffeefefffefefe,fffdfdfdfffefefe,fffffcfcfffefefe,fffffcfcfffdfdfd,fffbfbfbfffdfdfd,fffbfbfbfffdfdfd,fffafafafffdfdfd,fffafafa

因此,要使图像正确,它必须具有不同的rgb值。

© www.soinside.com 2019 - 2024. All rights reserved.