将RGB图像转换为灰度图像以在Java中减少内存使用。

20

我有一个RGB的bufferedImage bImg。
我想将bImg转换为灰度图像。

BufferedImage grayIm=new BufferedImage(bImg.getWidth(null), bImg.getHeight(null), BufferedImage.TYPE_BYTE_GRAY); 

我尝试了 grayIm,但是我无法为这个 grayIm 设置灰度值。


可能是重复问题 - https://dev59.com/U1jUa4cB1Zd3GeqPS5kz#6471524 - mre
"我无法为这个灰度图 grayIm 设置灰度值" 的意思是什么?" - tim_yates
3个回答

45

一种方法是转换颜色空间(性能较差):

ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);  
ColorConvertOp op = new ColorConvertOp(cs, null);  
BufferedImage image = op.filter(bufferedImage, null);

另一种方法是使用BufferedImage,就像您现在所做的那样(性能更好):

BufferedImage image = new BufferedImage(width, height,  
    BufferedImage.TYPE_BYTE_GRAY);  
Graphics g = image.getGraphics();  
g.drawImage(colorImage, 0, 0, null);  
g.dispose();  

最后但并非最不重要的是,最佳性能使用GrayFilter:

ImageFilter filter = new GrayFilter(true, 50);  
ImageProducer producer = new FilteredImageSource(colorImage.getSource(), filter);  
Image mage = Toolkit.getDefaultToolkit().createImage(producer);  

来源:http://www.codebeach.com/2008/03/convert-color-image-to-gray-scale-image.html

编辑:根据Mark的评论。


1
在第三个方法中,createImage未定义。this应该是Toolkit.getDefaultToolkit() - Mark Jeronimus
第三种实现方案的性能比下面的解决方案好很多吗? - Jürgen K.

29

注意:这不是问题提出者所要求的(因为它并没有减少内存使用),但我会留在这里,因为像手动逐像素处理这样的方法很受人们欢迎。相反,我将展示如何精确计算灰度颜色。


这很简单。思路是遍历图像中的每个像素,并将其更改为其灰度等效值。

public static void makeGray(BufferedImage img)
{
    for (int x = 0; x < img.getWidth(); ++x)
    for (int y = 0; y < img.getHeight(); ++y)
    {
        int rgb = img.getRGB(x, y);
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = (rgb & 0xFF);

        // Normalize and gamma correct:
        float rr = Math.pow(r / 255.0, 2.2);
        float gg = Math.pow(g / 255.0, 2.2);
        float bb = Math.pow(b / 255.0, 2.2);

        // Calculate luminance:
        float lum = 0.2126 * rr + 0.7152 * gg + 0.0722 * bb;

        // Gamma compand and rescale to byte range:
        int grayLevel = (int) (255.0 * Math.pow(lum, 1.0 / 2.2));
        int gray = (grayLevel << 16) + (grayLevel << 8) + grayLevel; 
        img.setRGB(x, y, gray);
    }
}

然而,这并没有减少内存。要有效地减少内存使用量,请执行相同的过程,但将灰度BufferedImage用作输出。


2
但这会减少内存吗?@Martijn Courteaux - sayem siam
9
实际上,灰度转换并不是简单地对R、G、B通道取平均值,因为蓝色对我们的亮度感知贡献最少,而绿色贡献最大。需要进行加权平均才能准确地表示灰度图像中的光强度。使用0.2126R + 0.7152G + 0.0722B。 - Mr.WorshipMe
@Mr.WorshipMe:不错!我知道这个现象。你有关于你的权重的任何资源吗? - Martijn Courteaux
1
@MartijnCourteaux 这就是OpenCV在cvtColor中使用的内容,它也出现在维基百科关于灰度的文章中。 - Mr.WorshipMe
@MartijnCourteaux。如何从仅有的一个通道(如R)创建灰度图像?仅使用红色的RGB值是否足够用于新图片? - Jürgen K.
Mr. Worship使用的系数是Rec709(HDTV)和sRGB(IEC标准)的标准。但是,RGB值需要先进行线性化处理。答案中显示了简单的指数方法,尽管IEC标准中的分段方法通常被推荐。如果您从三个8位INT开始,并希望返回一个8位INT,则可以使用以下代码://ANDY'S DOWN AND DIRTY GRAYSCALE™ gray=((Rs/255.0)**2.2*0.2126+(Gs/255.0)**2.2*0.7152+(Bs/255.0)**2.2*0.0722)**0.4545*255; - Myndex

2

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