代码之家  ›  专栏  ›  技术社区  ›  user366312

如何将图像测试为灰度?

  •  1
  • user366312  · 技术社区  · 6 年前

    弗戈 .net版本/ 协议 .NET库, the following test 执行以确定图像是否为灰度:

    public static bool IsGrayscale (Bitmap image)
    {
        bool ret = false;
    
        // check pixel format
        if (image.PixelFormat == PixelFormat.Format8bppIndexed)
        {
            ret = true;
            // check palette
            ColorPalette cp = image.Palette;
            Color c;
            // init palette
            for ( int i = 0; i < 256; i++ )
            {
                c = cp.Entries[i];
                if ((c.R != i) || (c.G != i) || (c.B != i))
                {
                    ret = false;
                    break;
                }
            }
        }
        return ret;
    }
    

    这不是谬误吗?

    至于 definition 去,灰度图像可以是除1位pp以外的任何颜色深度。例如,以下是32位灰度图像:

    enter image description here
    enter image description here

    所以,我的问题是,测试灰度图像的正确方法是什么?

    2 回复  |  直到 6 年前
        1
  •  2
  •   user366312    6 年前

    看来我有答案了 this link 是的。

    如果图像是灰度图像,则

    if(R=G=B) //Grayscale 
    

    为了获得更准确的结果,可以引入一些阈值。即

    if((abs(R-G)< Threshold))// Threshold-> can be greater than zero. eg
    0.006 //Grayscale 
    

    这样你可以得到相当好的结果。

    但是,我想, 这个过程会非常缓慢。

    所以,任何有更好想法的人都欢迎回答。

        2
  •  1
  •   Nyerguds    6 年前

    该代码正在检查像素值与其亮度对应的标准8位灰度。这或多或少是灰度的一个标准,但它确实与优化的调色板或类似的东西不匹配。

    我不知道你为什么会排除1BP。它是一种索引格式,和其他格式一样,实际上有一个像8ppp一样的调色板,这意味着它甚至不限于纯黑白。这是该鹦鹉的1ppp灰度版本,调色板中有两个灰度值:

    1bpp gray Parrot

    检查索引图像的最简单方法确实是检查调色板并进行r=g=b测试,但从技术上讲,即使这样,只要调色板上的任何非灰色颜色实际上不是灰度的,图像也是灰度的 习惯于 在图像上。

    一个可靠的方法可能只是让lockbits将图像转换为32bppargb,然后检查r、g和b。但即使在那里你也得做出选择… do 100% transparent pixels that don't match R=G=B make the image "not grayscale" 是吗?

    不管怎样,下面是我将使用的方法:

    public static Boolean IsGrayscale(Bitmap cur)
    {
        // Indexed format, and no non-gray colours in the images palette: immediate pass.
        if ((cur.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed
            && cur.Palette.Entries.All(c => c.R == c.G && c.R == c.B))
            return true;
        // Quick indexed check failed; actually check image data.
        // Get bytes out of the image, converted to 32bpp ARGB 
        BitmapData curBitmapData = cur.LockBits(new Rectangle(0, 0, cur.Width, cur.Height),
            ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        Int32 stride = curBitmapData.Stride;
        Byte[] data = new Byte[stride * cur.Height];
        Marshal.Copy(curBitmapData.Scan0, data, 0, data.Length);
        cur.UnlockBits(curBitmapData);
        // Go over all bytes per block of four.
        Int32 curRowOffs = 0;
        for (Int32 y = 0; y < cur.Height; y++)
        {
            // Set offset to start of current row
            Int32 curOffs = curRowOffs;
            for (Int32 x = 0; x < cur.Width; x++)
            {
                Byte b = data[curOffs];
                Byte g = data[curOffs + 1];
                Byte r = data[curOffs + 2];
                Byte a = data[curOffs + 3];
                // Increase offset to next colour
                curOffs += 4;
                if (a == 0)
                    continue;
                if (r != g || r != b)
                    return false;
            }
            // Increase row offset
            curRowOffs += stride;
        }
        return true;
    }