简体   繁体   English

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

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

I want to do a simple color to grayscale conversion using java.awt.image.BufferedImage . 我想使用java.awt.image.BufferedImage为灰度转换做一个简单的颜色。 I'm a beginner in the field of image processing, so please forgive if I confused something. 我是图像处理领域的初学者,所以如果我感到困惑,请原谅。

My input image is an RGB 24-bit image (no alpha), I'd like to obtain a 8-bit grayscale BufferedImage on the output, which means I have a class like this (details omitted for clarity): 我的输入图像是一个RGB 24位图像(没有alpha),我想在输出上获得一个8位灰度级BufferedImage ,这意味着我有一个这样的类(为清晰起见省略了详细信息):

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 ColorModel called 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). 第一种方法工作得更快,但产生的图像非常暗,这意味着我失去了带宽是不可接受的(在灰度和sRGB ColorModel之间使用了一些颜色转换映射,称为tosRGB8LUT,这对我来说效果不佳,到目前为止正如我所知,但我不确定,我只是假设使用了这些值。 The second method works slower, but the effect is very nice. 第二种方法效果较慢,但效果非常好。

Is there a method of combining those two, eg. 有没有一种方法可以将这两者结合起来,例如: using a custom indexed ColorSpace for ColorConvertOp ? 使用自定义索引ColorSpace for ColorConvertOp If yes, could you please give me an example? 如果有,你能举个例子吗?

Thanks in advance. 提前致谢。

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;
}

There's an example here which differs from your first example in one small aspect, the parameters to ColorConvertOp . 这里有一个例子它与你的第一个例子在一个小方面不同, ColorConvertOp的参数。 Try this: 尝试这个:

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

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值的数组,将其转换并重新设置。

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时,可以通过优化昂贵的浮点算术运算来加速。

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. 取图像高度y,图像宽度x,图像颜色深度m和整数位大小n。 Only works if (2^m)/(x*y*2^n) >= 1. Keep an bit integer total for each color channel as you process the initial gray scale values. 仅在(2 ^ m)/(x * y * 2 ^ n)> = 1时有效。在处理初始灰度值时,为每个颜色通道保留一个位整数。 Divide each total by the (x*y) for the average value avr[channel] of each channel. 将每个总和除以(x * y)每个通道的平均值avr [channel]。 Add (192 - avr[channel]) to each pixel for each 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. 请记住,这种方法可能不会与标准亮度方法具有相同的质量水平,但如果您正在寻找速度和质量之间的折衷,并且不想处理昂贵的浮点运算,它可能会为你工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM