如何测试图像是灰度的?

时间:2018-07-02 00:30:19

标签: c# bitmap grayscale

Aforge .net / Accord .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 个答案:

答案 0 :(得分:2)

好像我在this link中得到了答案。

  

如果图像是灰度图像,则

if(R=G=B) //Grayscale 
     

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

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

通过这种方式,您可以获得很好的结果。

但是,我怀疑此过程会像地狱一样慢。

因此,欢迎有更好主意的人回答。

答案 1 :(得分:1)

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

我不确定您为什么会排除1bpp。它是一种索引格式,与其他格式一样,实际上具有与8bpp一样的调色板,这意味着它甚至不限于纯黑白。这是该鹦鹉的1bpp灰​​度版本,在其调色板中带有两个灰度值:

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