简体   繁体   English

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

[英]Reliable way to check if image is Grey scale

I am currently working on one use case where i need to determine if uploaded image is Grey Scale or RGB. 我目前正在研究一个用例,我需要确定上传的图像是灰度还是RGB。 I found couple of ways to identify this, but not sure if they are reliable and can be used collectively to confirm image is grey scale or not. 我找到了几种方法来识别它,但不确定它们是否可靠并且可以集体用于确认图像是否为灰度。

Part 1: Read Image and get NumberDataElements using Raster. 第1部分:使用Raster读取图像并获取NumberDataElements。

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

I observed value of elem is "1" in some cases, but not in all. 在某些情况下,我观​​察到elem的值为“1”,但并非总体而言。

Part 2: Check RGB value of each pixel. 第2部分:检查每个像素的RGB值。 If R , G, B value is same of given pixel. 如果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;
                }


            }

Here i check R, G,B values are same for any given pixel and this behavior is consistent across all pixels. 在这里,我检查任何给定像素的R,G,B值是否相同,并且这种行为在所有像素上都是一致的。

I am using these 2 approaches, but not sure how accurate they are. 我正在使用这两种方法,但不确定它们的准确程度。 Kindly suggest.. 请建议..

Move your if (flag) { break; } 移动你的if (flag) { break; } if (flag) { break; } line outside of the inner for loop. if (flag) { break; }内的外线for循环。

And you only need to check that (red != green || green != blue) . 你只需要检查一下(red != green || green != blue) Breaking any one of these two equalities ensures that the third MUST be broken, so you only require two checks. 打破这两个等式中的任何一个确保第三个必须被打破,所以你只需要两次检查。

I'd also possibly just set an isGrayscale variable of boolean to true and then set it to false, when the equality logic breaks, rather than setting a flag to true. 我也可能只是将boolean的isGrayscale变量设置为true,然后在相等逻辑中断时将其设置为false,而不是将标志设置为true。 It should be assumed to be grayscale, until it breaks and becomes false. 它应该被假定为灰度,直到它破裂并变为假。 No problem with what you have here with flag, but this is a little more meaningful and intuitive. 没有问题,你在这里有旗帜,但这有点更有意义和直观。

If you want to get really clever, you could allow for a delta of variance to allow for images that are SUFFICIENTLY grayscale for purpose ie their deviance from equality is lower than a set barrier. 如果你想变得非常聪明,你可以允许方差三角形以允许用于目的的足够灰度的图像,即它们的相等偏差低于设定的障碍。 But this works as it is :) 但是这样可行:)

Below approach is worked for me. 以下方法对我有用。 Thanks guys for help. 谢谢大家的帮助。

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


            }

I think your second option is a reliable and correct method of proving an image is greyscale. 我认为你的第二种选择是一种可靠而正确的方法来证明图像是灰度的。 Your code has some problems: * you don't break out of the outer loop the way you intended to (look carefully at the second break - I think it should be in the outer loop but NOT the inner loop). 你的代码有一些问题:*你没有按照你想要的方式突破外部循环(仔细观察第二个中断 - 我认为它应该在外部循环而不是内部循环)。 * as leonbloy explains in his comment your comparison could be simpler *正如leonbloy在他的评论中解释的那样,你的比较可能更简单

But if you fix these small problems it should work reliably. 但是,如果你解决这些小问题,它应该可靠地工作。

Checking R=G=B will tell you if an image is greyscale, thats for sure. 检查R = G = B将告诉您图像是否为灰度,这是肯定的。 But i would be very careful with that approach. 但我会非常小心这种方法。 You dont know where the images came from. 你不知道图像来自哪里。 They could be saved with lossy compression or some other strange format. 它们可以通过有损压缩或其他一些奇怪的格式保存。 I dont know if formats like jpg actually colorshift greyscale pixels, but that might also be dependant on the compression algorithm (and thus the program used to save the image). 我不知道像jpg这样的格式是否实际上是colorhift灰度像素,但这也可能取决于压缩算法(因此用于保存图像的程序)。 Anyway i would suggest you convert images to greyscale by yourself just to be sure. 无论如何,我建议你自己将图像转换为灰度,以确保。 At least for those images that fail the R=G=B test. 至少对于那些未通过R = G = B测试的图像。

For your algorithm i strongly suggest you create a new function for checking R=G=B. 对于您的算法,我强烈建议您创建一个新函数来检查R = G = B. This way, if you found a pixel that fails the test you can return false immediately. 这样,如果您发现一个未通过测试的像素,您可以立即返回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: I just checked the compression colorshift thing. PS:我刚检查了压缩色移的东西。 I cant archieve color shifting with pohotohop and jpg format. 我不能用pohotohop和jpg格式改变颜色。 But its possible to save a greyscale image as gif in such a way, that its not exactly greyscale anymore. 但它可以以这种方式将灰度图像保存为gif,使其不再是灰度图像。

The question is : do you want the image itself to be grayscale, or the encoding ? 问题是:你想要图像本身是灰度还是编码?

Your second solution tells you whether the image is grayscale or not, regardless of the encoding (ie, it returns true even the image could potentially have colors, but just doesn't). 您的第二个解决方案会告诉您图像是否为灰度,无论编码如何(即,即使图像可能具有颜色,但它也会返回true)。 It isn't perfect however, one could perfectly imagine a situation where the image is grayscale in some color space different than RGB, and a rounding error makes your test fail. 然而,它并不完美,人们可以完美地想象一下图像在不同于RGB的某些颜色空间中的灰度级,并且舍入错误会使您的测试失败。 Or a lossy encoding. 或者有损编码。 You should add a margin of error and convert to proper grayscale any image that is close enough. 您应该添加一个误差范围,并将任何足够接近的图像转换为适当的灰度。

Your first solution is an imperfect attempt at finding out whether the encoding is grayscale. 您的第一个解决方案是查找编码是否为灰度的不完美尝试。 An image with a color palette of size 255 would also give you elem=1 , and a grayscale image can have elem=2 if it has an alpha channel. 具有255的调色板的图像也将给出elem=1 ,并且如果具有alpha通道,则灰度图像可以具有elem=2

In order to check if your encoding is grayscale, I suggest the following test : 为了检查您的编码是否为灰度,我建议进行以下测试:

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

To do this, you will need to import the classes ColorModel and ColorSpace from java.awt.image and java.awt.color . 为此,您需要从java.awt.imagejava.awt.color导入ColorModel和ColorSpace类。

You could also investigate whether image.getType() has value BufferedImage.TYPE_BYTE_GRAY or BufferedImage.TYPE_USHORT_GRAY . 您还可以调查image.getType()是否具有值BufferedImage.TYPE_BYTE_GRAYBufferedImage.TYPE_USHORT_GRAY

Here is a very simple way: 这是一个非常简单的方法:

  1. Test the image type 测试图像类型
  2. Test the image number of channels 测试通道的图像数量
  3. Test the pixels values. 测试像素值。

Here is the code 这是代码

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

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

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