【问题标题】:How to convert an image to a 0-255 grey scale image如何将图像转换为 0-255 灰度图像
【发布时间】:2014-10-17 06:02:13
【问题描述】:

我想将图像转换为像素强度0-255之间的灰度图像。

我能够使用以下 Java 方法将图像转换为灰度图像。

public void ConvertToGrayScale(BufferedImage bufImage, int ImgWidth, int ImgHeight) {

    for (int w = 0; w < ImgWidth; w++) {
        for (int h = 0; h < ImgHeight; h++) {

            Color color = new Color(bufImage.getRGB(w, h));
            int ColAvgVal = ((color.getRed() + color.getGreen() + color.getBlue()) / 3);
            Color avg = new Color(ColAvgVal, ColAvgVal, ColAvgVal);

            bufImage.setRGB(w, h, avg.getRGB());

            System.out.println(avg.getRGB());
        }
    }
}

"System.out.println(avg.getRGB());"用于查看像素强度,但所有灰度级均为负值且不在 0-255 之间

我做错了吗?如何将图像转换为像素强度介于 0-255 之间的灰度图像。

谢谢

【问题讨论】:

    标签: java image-processing grayscale


    【解决方案1】:

    color.getRGB() 不返回 0..255 的值,它返回一个由红色、绿色和蓝色值组合而成的整数,包括 Alpha 值。据推测,这个 alpha 值是 0xFF,这使得 any 组合颜色最终为 0xFFrrggbb,或者,如您所见,以小数形式写入时是一个巨大的负数。

    要查看分配的“灰色”级别,只需检查ColAvgVal

    请注意,在 RGB 和灰度之间进行转换的更好公式是使用PAL/NTSC conversion

    gray = 0.299 * red + 0.587 * green + 0.114 * blue
    

    因为“全蓝”的灰度应该比“全红”和“全绿”更暗。


    注意:如果您直接使用此公式,请注意浮点舍入误差。理论上,它不应该为gray返回0..255之外的值;在实践中,它会。所以测试并钳制结果。

    另一个不需要对每个像素进行测试和钳位的选项是使用仅整数版本:

    gray = (299 * red + 587 * green + 114 * blue)/1000;
    

    应该只有很小的舍入误差。

    【讨论】:

    • 另一个选项是:gray = (77*red + 150*green + 29*blue) &gt;&gt; 8;。向右位移 8 相当于除以 256,77/256 = 0.299, 150/256 = 0.58729/256 = 0.114。如您所说,这会计算用于转换为灰度的 SMPTE 标准,但它避免了所有的除法。不过,您的整数版本还是很好的解决方法!
    • @Jongware 感谢您的回复当我打印“ColAvgVal”值时,我能够看到 0..255 的灰度级。我尝试将“ColAvgVal”分配给 bufImage.setRGB(w, h, ColAvgVal);我得到了一张蓝色的图像。由于我想从灰度级 0..255 获得灰度图像,我将如何获得它?谢谢
    • @user3347358 - 您需要将 all 颜色分量设置为相同的值才能使其看起来像灰度。将gray 设置为ColAvgVal 并从中创建一个新颜色,例如:Color avg = new Color(ColAvgVal, ColAvgVal, ColAvgVal);,然后执行bufImage.setRGB(w, h, avg.getRGB());
    • @user3347358 - ColAvgVal 已经计算过了。灰度图像的红色、绿色和蓝色值全部相同,因此您只需打印出ColAvgVal。该值对于所有 RGB 组件都是相同的。但是,如果您想成为技术人员,请使用avg.getRed(); avg.getGreen(); avg.getBlue();。很想知道为什么当您看到循环中较早完成的等效语句时会问这个问题。
    • 这样做:System.out.println(ColAvgVal);,在循环中,这就是 我之前已经告诉过你。我将停止淹没 Jongware 帖子的 cmets,我将把它留给你。祝你好运!
    【解决方案2】:

    您可以查看this 。希望对你有帮助。

    您可以检查一些不同的方法,例如:

    // The average grayscale method
    private static BufferedImage avg(BufferedImage original) {
    
    int alpha, red, green, blue;
    int newPixel;
    
    BufferedImage avg_gray = new BufferedImage(original.getWidth(), original.getHeight(), original.getType());
    int[] avgLUT = new int[766];
    for(int i=0; i<avgLUT.length; i++)
        avgLUT[i] = (int) (i / 3);
    
    for(int i=0; i<original.getWidth(); i++) {
        for(int j=0; j<original.getHeight(); j++) {
    
            // Get pixels by R, G, B
            alpha = new Color(original.getRGB(i, j)).getAlpha();
            red = new Color(original.getRGB(i, j)).getRed();
            green = new Color(original.getRGB(i, j)).getGreen();
            blue = new Color(original.getRGB(i, j)).getBlue();
    
            newPixel = red + green + blue;
            newPixel = avgLUT[newPixel];
            // Return back to original format
            newPixel = colorToRGB(alpha, newPixel, newPixel, newPixel);
    
            // Write pixels into image
            avg_gray.setRGB(i, j, newPixel);
    
        }
    }
    
    return avg_gray;
    
    }
    

    【讨论】:

    • 这确实会执行灰度转换,但您没有解释为什么会这样。此外,avgLUT 计算是绝对没有必要的。您所做的只是将每个颜色通道的强度相加,然后使用 LUT 来查看它对应的位置,它只输出总和并除以 3,这就是 OP 已经拥有的。因此,我不明白这篇文章的目的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    • 2015-12-07
    相关资源
    最近更新 更多