检查图像是否为灰度级的可靠方法



我目前正在处理一个用例,需要确定上传的图像是灰度级还是RGB。我找到了几种方法来识别这一点,但不确定它们是否可靠,是否可以共同用于确认图像是否为灰度级。

第1部分:使用Raster读取图像并获取NumberDataElements。

BufferedImage image = ImageIO.read(file);
        Raster ras = image.getRaster();
        int elem = ras.getNumDataElements();

我观察到elem的值在某些情况下是"1",但并非所有情况下都是。

第2部分:检查每个像素的RGB值。若R,G,B的值和给定的像素相同。

BufferedImage image = ImageIO.read(file);
        Raster ras = image.getRaster();
        //Number of Color elements
        int elem = ras.getNumDataElements();
        int width = image.getWidth();
        int height = image.getHeight();
        int pixel,red, green, blue;
        for (int i = 0; i < width; i++)
            for (int j = 0; j < height; j++) {
                //scan through each pixel
                pixel = image.getRGB(i, j);
                red = (pixel >> 16) & 0xff;
                green = (pixel >> 8) & 0xff;
                blue = (pixel) & 0xff;
                //check if R=G=B
                if (red != green || green != blue ) {
                    flag = true;
                    break;
                }

            }

在这里,我检查R、G、B的值对于任何给定的像素都是相同的,并且这种行为在所有像素上都是一致的。

我正在使用这两种方法,但不确定它们的准确性。请建议。。

if (flag) { break; }行移到内部for循环之外。

你只需要检查(red != green || green != blue)。打破这两个等式中的任何一个都可以确保第三个等式必须被打破,所以你只需要两次检查。

我也可能只是将布尔值的isGrayscale变量设置为true,然后在相等逻辑中断时将其设置为false,而不是将标志设置为true。应该假设它是灰度级的,直到它断裂并变为假。这里的flag并没有问题,但它更有意义和直观。

如果你想变得非常聪明,你可以允许方差增量,以允许足够灰度的图像,即它们与相等的偏差低于设定的阈值。但这是有效的:)

下面的方法对我很有效。谢谢大家的帮助。

BufferedImage image = ImageIO.read(file);
        Raster ras = image.getRaster();
        //Number of Color elements
        int elem = ras.getNumDataElements();
        int width = image.getWidth();
        int height = image.getHeight();
        int pixel,red, green, blue;
        for (int i = 0; i < width; i++)
            for (int j = 0; j < height; j++) {
                //scan through each pixel
                pixel = image.getRGB(i, j);
                red = (pixel >> 16) & 0xff;
                green = (pixel >> 8) & 0xff;
                blue = (pixel) & 0xff;
                //check if R=G=B
                if (red != green || green != blue ) {
                    flag = true;
                    break;
                }

            }

我认为您的第二个选项是证明图像灰度的可靠且正确的方法。您的代码存在一些问题:*你没有按照你想要的方式突破外循环(仔细看第二次突破——我认为它应该在外循环,而不是内循环)。*正如leonbloy在他的评论中所解释的那样,你的比较可能更简单

但如果你解决了这些小问题,它应该能可靠地工作。

检查R=G=B会告诉你图像是否为灰度级,这是肯定的。但我会非常谨慎地对待这种做法。你不知道这些图片是从哪里来的。它们可以用有损压缩或其他奇怪的格式保存。我不知道像jpg这样的格式是否真的会改变灰度像素的颜色,但这也可能取决于压缩算法(以及用于保存图像的程序)。无论如何,我建议你自己将图像转换为灰度,只是为了确定。至少对于那些未通过R=G=B测试的图像。

对于你的算法,我强烈建议你创建一个新的函数来检查R=G=B。这样,如果你发现一个像素没有通过测试,你可以立即返回false。

public static boolean isGreyscale(BufferedImage image)
{
    int pixel,red, green, blue;
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++) 
        {
            pixel = image.getRGB(i, j);
            red = (pixel >> 16) & 0xff;
            green = (pixel >> 8) & 0xff;
            blue = (pixel) & 0xff;
            if (red != green || green != blue ) return false;
        }
    }
    return true;
}

PS:我刚刚检查了压缩色移的问题。我无法用pohotohop和jpg格式存档颜色偏移。但是可以用这种方式将灰度图像保存为gif,使其不再完全是灰度图像。

问题是:您希望图像本身是灰度级的,还是编码?

您的第二个解决方案告诉您图像是否为灰度级,而不考虑编码(即,即使图像可能有颜色,但它也会返回真值)。然而,这并不完美,人们可以完美地想象这样一种情况,即图像在不同于RGB的颜色空间中是灰度级的,舍入误差会导致测试失败。或者有损编码。您应该添加一个误差幅度,并将任何足够接近的图像转换为适当的灰度。

您的第一个解决方案是尝试找出编码是否为灰度。调色板大小为255的图像也会提供elem=1,如果灰度图像具有alpha通道,则可以提供elem=2

为了检查您的编码是否为灰度,我建议进行以下测试:

int type = image.getColorModel().getColorSpace().getType();
boolean grayscale = (type==ColorSpace.TYPE_GRAY || type==ColorSpace.CS_GRAY);

为此,您需要从java.awt.imagejava.awt.color导入类ColorModel和ColorSpace。

您还可以调查image.getType()的值是BufferedImage.TYPE_BYTE_GRAY还是BufferedImage.TYPE_USHORT_GRAY

这里有一个非常简单的方法:

  1. 测试图像类型
  2. 测试通道的图像数量
  3. 测试像素值

这是代码

boolean isGrayScale(BufferedImage image)
    {
    // Test the type
    if ( image.getType() == BufferedImage.TYPE_BYTE_GRAY ) return true ;
    if ( image.getType() == BufferedImage.TYPE_USHORT_GRAY ) return true ;
    // Test the number of channels / bands
    if ( image.getRaster().getNumBands() == 1 ) return true ; // Single channel => gray scale
    // Multi-channels image; then you have to test the color for each pixel.
    for (int y=0 ; y < image.getHeight() ; y++)
    for (int x=0 ; x < image.getWidth() ; x++)
        for (int c=1 ; c < image.getRaster().getNumBands() ; c++)
            if ( image.getRaster().getSample(x, y, c-1) != image.getRaster().getSample(x, y, c) ) return false ;
    return true ;
    }

最新更新