【问题标题】:Reliable way to check if image is Grey scale检查图像是否为灰度的可靠方法
【发布时间】:2016-03-23 16:40:52
【问题描述】:

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

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

【问题讨论】:

  • red != green || green != blue || red != blue 只需进行两次比较即可。此外,您两次调用“break”,第二次是多余的。
  • 虽然 RGB 中的“灰色”表示 R = G = B,但可能存在一些变化,例如。 G。如果图像具有嵌入的颜色配置文件,或者从 jpeg 恢复。我相信更可靠但更慢的方法是将像素转换为 HSV 并检查 S(饱和度)是否接近 0。
  • @SashaSalauyou 据我所知,即使图像是 jpeg 并使用了颜色表,此代码仍然可以工作,因为图像已被解码并且 getRGB 独立于源格式。
  • @Elemental 是的,当然。将我的评论视为确定图像“看起来灰度”而不是“灰度”的一种方式
  • @leonbloy 他们有两个循环,但他们的休息没有正确放置。 Dark Knight 将图像存储为 RGB 但实际上是灰度图像似乎很奇怪。您是否考虑过检查 BufferedImage#getType?

标签: java bufferedimage dpi


【解决方案1】:

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

您只需要检查(red != green || green != blue)。打破这两个等式中的任何一个可确保必须打破第三个等式,因此您只需要进行两次检查。

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

如果您想变得非常聪明,您可以允许方差增量以允许图像具有足够灰度的目的,即它们对等式的偏差低于设定的障碍。但这可以正常工作:)

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        检查 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,它不再完全是灰度。

        【讨论】:

          【解决方案5】:

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

          您的第二个解决方案会告诉您图像是否为灰度,无论编码如何(即,即使图像可能有颜色,它也会返回 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 的值。

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-10-08
              • 2011-10-06
              • 1970-01-01
              • 2015-02-21
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多