Как я могу проверить изображение в оттенках серого? - PullRequest
0 голосов
/ 02 июля 2018

В Aforge .net / Accord .net библиотеке следующий тест выполняется для определения того, является ли изображение в градациях серого:

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

Разве это не ошибочно?

Что касается определения , изображение в градациях серого может иметь любую глубину цвета, кроме 1-битного pp. Например, ниже приводится 32-битное изображение в градациях серого:

enter image description here
enter image description here

Итак, мой вопрос: как правильно проверить изображение в градациях серого?

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Этот код проверяет стандартную 8-битную шкалу серого, где значения пикселей соответствуют их яркости. Это более или менее стандарт для градаций серого, но он действительно не будет соответствовать оптимизированным палитрам или чему-то в этом роде.

Я не уверен, почему вы исключили бы 1bpp. Это индексированный формат, как и любой другой, и на самом деле он имеет цветовую палитру, такую ​​как 8bpp, что означает, что он даже не ограничивается чисто черным и белым. Это версия этого попугая в оттенках серого размером 1 п.н. с двумя значениями серого в его палитре:

1bpp gray Parrot

Самый простой способ проверить проиндексированные изображения - это действительно пройти по палитре и выполнить тест R = G = B, но технически даже тогда вы можете утверждать, что изображение является серым, если на нем не серые цвета. палитра на самом деле не используется на изображении.

Верный способ, вероятно, состоит в том, чтобы заставить LockBits преобразовать изображение в 32bppARGB, а затем проверить R, G и B на этом. Но даже там вам придется делать выбор ... сделать 100% прозрачных пикселей, которые не соответствуют R = G = B, сделать изображение "не в градациях серого" ?

В любом случае, вот какой метод я бы использовал:

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;
}
0 голосов
/ 02 июля 2018

Похоже, я получил ответ в по этой ссылке .

Если изображение серого цвета, то

if(R=G=B) //Grayscale 

Для более точных результатов вы можете ввести некоторые пороговые значения. * 1009 то есть *

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

Таким образом, вы можете получить довольно хорошие результаты.

Но, я подозреваю, эта процедура будет такой же медленной, как ад.

Итак, любой, у кого есть идея получше, может ответить.

...