Проверьте, цветное изображение или нет

Я пытаюсь выяснить, является ли изображение цветным или нет. На этот вопрос StackOverflow есть ответ это говорит о том, что я должен проверить перечисление PixelFormat Image. К сожалению, ответ мне не очень ясен. Безопасно ли проверять, отличается ли image.PixelFormat от PixelFormat.Format16bppGrayScale, чтобы считать, что это цветное изображение? А как насчет других значений перечисления? Документация MSDN не очень ясна...


person Kassem    schedule 26.04.2012    source источник
comment
Хотите проверить, поддерживает ли он цвета или содержит цвета? Это может быть Format32bppArgb и по-прежнему содержать только черный, белый и серый цвета.   -  person SimpleVar    schedule 26.04.2012
comment
@YoryeNathan: я хочу знать, содержит ли он цвета.   -  person Kassem    schedule 26.04.2012
comment
Тогда это другое. Вы хотите, чтобы это работало для каждого PixelFormat?   -  person SimpleVar    schedule 26.04.2012
comment
@YoryeNathan: Честно говоря, я не совсем уверен. Дело в том, что пользователь может загрузить изображение на сайт, тогда мне нужно проверить, цветное это изображение или нет. Соответственно, мне нужно делать разные вещи...   -  person Kassem    schedule 26.04.2012
comment
Значит, пользователь загружает изображение любого типа? Есть диалоговое окно файла и т.д.? Нет расширенного фильтра?   -  person SimpleVar    schedule 26.04.2012
comment
В Bitmap есть метод GetPixel. msdn.microsoft.com/en-us/library/ тогда можно было бы проверить значения RGB для каждого пикселя, но это отстой.   -  person Andrew Jones    schedule 26.04.2012
comment
@YoryeNathan: Нет, я ограничусь изображениями в формате jpg, png и gif.   -  person Kassem    schedule 26.04.2012
comment
@AndrewJones: Да, это то, чего я пытаюсь избежать...   -  person Kassem    schedule 26.04.2012


Ответы (3)


Вы можете улучшить это, избегая Color.FromArgb и перебирая байты вместо целых чисел, но я подумал, что это будет более читабельным для вас и более простым для понимания как подход.

Общая идея заключается в том, чтобы преобразовать изображение в растровое изображение известного формата (32 бита на пиксель ARGB), а затем проверить, содержит ли это растровое изображение какие-либо цвета.

Блокировка битов растрового изображения позволяет вам перебирать его цветовые данные во много раз быстрее, чем при использовании GetPixel, используя небезопасный код.

Если альфа пикселя равна 0, то это, очевидно, GrayScale, потому что альфа 0 означает, что он полностью непрозрачен. Кроме этого - если R = G = B, то он серый (а если они = 255, то черный).

private static unsafe bool IsGrayScale(Image image)
{
    using (var bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))
    {
        using (var g = Graphics.FromImage(bmp))
        {
            g.DrawImage(image, 0, 0);
        }

        var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

        var pt = (int*)data.Scan0;
        var res = true;

        for (var i = 0; i < data.Height * data.Width; i++)
        {
            var color = Color.FromArgb(pt[i]);

            if (color.A != 0 && (color.R != color.G || color.G != color.B))
            {
                res = false;
                break;
            }
        }

        bmp.UnlockBits(data);

        return res;
    }
}
person SimpleVar    schedule 26.04.2012
comment
Рад, что помог. Просто убедитесь, что я не перепутал с альфой (0 или 255). В остальном все должно пройти гладко :) - person SimpleVar; 27.04.2012

Ответ SimpleVar в основном правильный: этот код неправильно обрабатывает, когда исходное изображение имеет формат индексированного цвета.

Чтобы решить эту проблему, просто замените внешний блок using на:

using (var bmp = new Bitmap(image)) {

и полностью удалите внутренний using, так как объект Graphics больше не нужен. Это создаст идеальную копию изображения в неиндексированном формате, независимо от формата исходного изображения в пикселях.

person timeshifter08    schedule 18.09.2018

person    schedule
comment
Пожалуйста, добавьте контекст в свой ответ и объясните, что делает код. stackoverflow.com/help/how-to-answer - person jmdon; 19.07.2018