java.awt.image.BufferedImage 24 位 RGB 到 8 位灰度转换使用自定义 ColorSpace

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3922172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 03:58:30  来源:igfitidea点击:

java.awt.image.BufferedImage 24-bit RGB to 8-bit Grayscale conversion using custom ColorSpace

javaimageimage-processingawtjai

提问by mmm

I want to do a simple color to grayscale conversion using java.awt.image.BufferedImage. I'm a beginner in the field of image processing, so please forgive if I confused something.

我想使用java.awt.image.BufferedImage. 我是图像处理领域的初学者,所以如果我混淆了一些东西,请原谅。

My input image is an RGB 24-bit image (no alpha), I'd like to obtain a 8-bit grayscale BufferedImageon the output, which means I have a class like this (details omitted for clarity):

我的输入图像是 RGB 24 位图像(无 alpha),我想BufferedImage在输出上获得 8 位灰度,这意味着我有一个这样的类(为清楚起见,省略了详细信息):

public class GrayscaleFilter {
    private BufferedImage colorFrame;
    private BufferedImage grayFrame = 
        new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

I've succesfully tried out 2 conversion methods until now, first being:

到目前为止,我已经成功地尝试了 2 种转换方法,首先是:

    private BufferedImageOp grayscaleConv = 
        new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

    protected void filter() {
        grayscaleConv.filter(colorFrame, grayFrame);
    }

And the second being:

第二个是:

    protected void filter() {       
        WritableRaster raster = grayFrame.getRaster();

        for(int x = 0; x < raster.getWidth(); x++) {
            for(int y = 0; y < raster.getHeight(); y++){
                int argb = colorFrame.getRGB(x,y);
                int r = (argb >> 16) & 0xff;
                int g = (argb >>  8) & 0xff;
                int b = (argb      ) & 0xff;

                int l = (int) (.299 * r + .587 * g + .114 * b);
                raster.setSample(x, y, 0, l);
            }
        }
    }

The first method works much faster but the image produced is very dark, which means I'm losing bandwidth which is unacceptable (there is some color conversion mapping used between grayscale and sRGB ColorModelcalled tosRGB8LUT which doesn't work well for me, as far as I can tell but I'm not sure, I just suppose those values are used). The second method works slower, but the effect is very nice.

第一种方法工作得更快,但生成的图像非常暗,这意味着我正在失去无法接受的带宽(在灰度和 sRGB 之间使用了一些颜色转换映射,ColorModel称为 tosRGB8LUT,这对我来说效果不佳,就我而言我可以说,但我不确定,我只是假设使用了这些值)。第二种方法运行速度较慢,但​​效果非常好。

Is there a method of combining those two, eg. using a custom indexed ColorSpacefor ColorConvertOp? If yes, could you please give me an example?

是否有将这两者结合的方法,例如。使用自定义索引ColorSpaceColorConvertOp?如果是的话,你能给我举个例子吗?

Thanks in advance.

提前致谢。

回答by Mark Ransom

There's an example herewhich differs from your first example in one small aspect, the parameters to ColorConvertOp. Try this:

这里有一个示例它在一个小方面与您的第一个示例有所不同,即ColorConvertOp. 试试这个:

protected void filter() {
   BufferedImageOp grayscaleConv = 
      new ColorConvertOp(colorFrame.getColorModel().getColorSpace(), 
                         grayFrame.getColorModel().getColorSpace(), null);
   grayscaleConv.filter(colorFrame, grayFrame);
}

回答by Sorter

public BufferedImage getGrayScale(BufferedImage inputImage){
    BufferedImage img = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
    Graphics g = img.getGraphics();
    g.drawImage(inputImage, 0, 0, null);
    g.dispose();
    return img;
}

回答by AnonymousCoward

Try modifying your second approach. Instead of working on a single pixel, retrieve an array of argb int values, convert that and set it back.

尝试修改您的第二种方法。不是处理单个像素,而是检索 argb int 值数组,将其转换并将其设置回原处。

回答by Nguy?n Minh V?

The second method is based on pixel's luminance therefore it obtains more favorable visual results. It could be sped a little bit by optimizing the expensive floating point arithmetic operation when calculate l using lookup array or hash table.

第二种方法是基于像素的亮度,因此可以获得更有利的视觉效果。在使用查找数组或哈希表计算 l 时,可以通过优化昂贵的浮点算术运算来加快速度。

回答by AaronF

Here is a solution that has worked for me in some situations.

这是在某些情况下对我有用的解决方案。

Take image height y, image width x, the image color depth m, and the integer bit size n. Only works if (2^m)/(x*y*2^n) >= 1. Keep a n bit integer total for each color channel as you process the initial gray scale values. Divide each total by the (x*y) for the average value avr[channel] of each channel. Add (192 - avr[channel]) to each pixel for each channel.

取图像高度y、图像宽度x、图像颜色深度m和整数位大小n。仅在 (2^m)/(x*y*2^n) >= 1 时有效。在处理初始灰度值时,为每个颜色通道保留一个整数位。将每个总数除以 (x*y) 以获得每个通道的平均值 avr[channel]。将 (192 - avr[channel]) 添加到每个通道的每个像素。

Keep in mind that this approach probably won't have the same level of quality as standard luminance approaches, but if you're looking for a compromise between speed and quality, and don't want to deal with expensive floating point operations, it may work for you.

请记住,这种方法可能不会具有与标准亮度方法相同的质量水平,但是如果您正在寻找速度和质量之间的折衷,并且不想处理昂贵的浮点运算,则可能为你工作。