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

时间:2016-03-22 14:03:47

标签: java bufferedimage dpi

我目前正在研究一个用例,我需要确定上传的图像是灰度还是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值是否相同,并且这种行为在所有像素中都是一致的。

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

6 个答案:

答案 0 :(得分:2)

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

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

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

如果你想变得非常聪明,你可以允许方差三角形以允许用于目的的充分灰度图像,即它们的相等偏差低于设定的障碍。但这样可行:)

答案 1 :(得分:1)

以下方法对我有用。谢谢大家的帮助。

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


            }

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

检查R = G = B将告诉您图像是否为灰度,这是肯定的。但我会非常小心这种方法。你不知道图像来自哪里。它们可以通过有损压缩或其他一些奇怪的格式保存。我不知道像jpg这样的格式是否实际上是colorhift灰度像素,但这也可能取决于压缩算法(因此用于保存图像的程序)。无论如何,我建议你自己将图像转换为灰度,以确保。至少对于那些未通过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,使其不再是灰度图像。

答案 4 :(得分:0)

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

您的第二个解决方案会告诉您图像是否为灰度,无论编码如何(即,即使图像可能具有颜色,它也会返回true,但实际上没有)。然而,它并不完美,人们可以完美地想象一下图像在不同于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_GRAYBufferedImage.TYPE_USHORT_GRAY

答案 5 :(得分:0)

这是一个非常简单的方法:

  1. 测试图像类型
  2. 测试图像的通道数
  3. 测试像素值。
  4. 这是代码

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