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

时间:2010-10-13 09:08:24

标签: java image image-processing awt jai

我想使用java.awt.image.BufferedImage为灰度转换做一个简单的颜色。我是图像处理领域的初学者,所以如果我感到困惑,请原谅。

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

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

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

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

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

第二个是:

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

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

是否有将这两者结合起来的方法,例如:为ColorSpace使用自定义索引ColorConvertOp?如果是的话,你能举个例子吗?

提前致谢。

5 个答案:

答案 0 :(得分:5)

有一个示例here与第一个示例的不同之处在于一个小方面,ColorConvertOp的参数。试试这个:

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

答案 1 :(得分:5)

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

答案 2 :(得分:2)

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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.

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.