将RGB像素转换为灰度会使暗像素呈现出蓝色调。

3

我目前正在尝试使用Java处理图像,尝试使用BufferedImage类将RGB图像转换为灰度图像。

我的想法是获取每个像素的RGB值,并将它们设置为(R+G+B)/3:

BufferedImage image = ImageIO.read(new File(file));

int[] pixel;
int r, g, b;

for (int y = 0; y < image.getHeight(); y++)
{
    for (int x = 0; x < image.getWidth(); x++) 
    {
        pixel = image.getRaster().getPixel(x, y, new int[3]);

        r = pixel[0];
        g = pixel[1];
        b = pixel[2];
        int gr = (int)((r+g+b)/3);

        String hex = Integer.toHexString(gr)+Integer.toHexString(gr)+Integer.toHexString(gr);
        int i = Integer.parseInt(hex, 16);

        image.setRGB(x, y, i);
    }
}

ImageIO.write(image, "jpg", new File("im2.jpg"));

结果如下:

最终结果如下:

输入图像描述

输入图像描述

虽然这可能是将图像转换为灰度图的最低效方法,但我不知道为什么会发生这种情况。我错过了什么吗?


1
虽然看起来很酷 :p - Pieter De Bie
1
当 gr=(r+g+b)/3 小于16(0x10)时会发生什么?你的字符串连接将不正确。例如,当 gr=9 时,十六进制将为“999”。 - David Zimmerman
3个回答

2
当灰度值小于 16 时,它将不再是一个两位数的十六进制数。因此,你的十六进制字符串将变为 "444" 而不是 "040404"。这将导致蓝色颜色。
为什么不使用


Color myColor = new Color(gr, gr, gr);

2
当十六进制值不是两个数字时,就会出现这种情况。例如,Integer.toHexString(10)返回"a"。

所以,例如如果r=10g=10b=10,你将执行Integer.toHexString("aaa"),这样就会得到相当蓝的颜色(aa=170),带点绿色(a=10),没有红色。这种效果显然会在图像的暗区域更明显,导致大部分为蓝色但有些微绿的效果。

下面是缩放您图片的一小部分,显示了蓝色和一点绿色。

A sample from your image showing blues and a little green

要解决这个问题,请正确滚动数字。

image.setRGB(x, y, new Color(gr,gr,gr).getRGB());

1
代替:

int gr = (int)((r+g+b)/3);

    String hex = Integer.toHexString(gr)+Integer.toHexString(gr)+Integer.toHexString(gr);
    int i = Integer.parseInt(hex, 16);

    image.setRGB(x, y, i);

试试这个:

Color newColor = new Color(r+g+b,r+g+b,r+g+b);

           image.setRGB(j,i,newColor.getRGB());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接