Как проверить не пустая ли картинка?

253
20 декабря 2017, 19:12

Есть список изображений. Стоит задача определить пустая ли картинка или на ней есть изображение. Нашел код для моей задачи http://www.chinhdo.com/20080910/detect-blank-images/ однако он некорректно работает.

public static bool IsBlank(string imageFileName)
{
    double stdDev = GetStdDev(imageFileName);
    return stdDev < 100000;
}
/// <summary>
/// Get the standard deviation of pixel values.
/// </summary>
/// <param name="imageFileName">Name of the image file.</param>
/// <returns>Standard deviation.</returns>
public static double GetStdDev(string imageFileName)
{
    double total = 0, totalVariance = 0;
    int count = 0;
    double stdDev = 0;
    // First get all the bytes
    using (Bitmap b = new Bitmap(imageFileName))
    {
        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, b.PixelFormat);
        int stride = bmData.Stride;
        IntPtr Scan0 = bmData.Scan0;
        unsafe
        {
            byte* p = (byte*)(void*)Scan0;
            int nOffset = stride - b.Width * 3;
            for (int y = 0; y < b.Height; ++y)
            {
                for (int x = 0; x < b.Width; ++x)
                {
                    count++;
                    byte blue = p[0];                            
                    byte green = p[1];
                    byte red = p[2];
                    int pixelValue = Color.FromArgb(0, red, green, blue).ToArgb();
                    total += pixelValue;
                    double avg = total / count;
                    totalVariance += Math.Pow(pixelValue - avg, 2);
                    stdDev = Math.Sqrt(totalVariance / count);
                    p += 3;
                }
                p += nOffset;
            }
        }
        b.UnlockBits(bmData);
    }
    return stdDev;
}

Answer 1

Один из способов - проверить стандартное отклонение на выход за некоторый порог. Этот порог надо подбирать экспериментально.

Посчитать стандартное отклонение проще всего по формуле

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

Получается примерно такой псевдокод:

float sumR = 0, sumG = 0, sumB = 0, sumR2 = 0, sumG2 = 0, sumB2 = 0;
int count = 0;
для всех пискелей картинки
{
    пусть r, g, b - значения цветовых компонент текущего пискеля
    sumR += r;
    sumG += g;
    sumB += b;
    sumR2 += r*r;
    sumG2 += g*g;
    sumB2 += b*b;
    count++;
}
float dev = sqrt(sumR2 + sumG2 + sumB2 
    - sumR * sumR - sumG * sumG - sumB * sumB) / count;
if (dev > НекотороеЧисло)
    Картинка есть!
else
    Картинки нет!

Однако, у этого способа есть ограничения. К примеру, такая простая проверка не способна отличить мелкий объект в углу (который определенно на картинке есть) от слабого градиента через всю картинку (который является просто фоном).

Если вам важно не срабатывать на картинках с градиентами - то можно воспользоваться альтернативными способами. Например, можно численно применить к картинке оператор Лапласа (найти вторую пространственную производную), что эквивалентно свертке изображения с ядром вроде вот такого:

Или же можно использовать первую производную - оператор Гамильтона (точнее, его численное представление в виде оператора Собеля) с ядрами

Также можно воспользоваться любым другим методом определения границ.

Если вдруг окажется что картинку вы получаете с камеры - не забудьте сделать поправку на освещение. Например, можно поделить стандартное отклонение на среднее значение, и порог устанавливать уже для этого отношения.

READ ALSO
Почему не переключается песня WMPLib?

Почему не переключается песня WMPLib?

Функция, когда заканчивается песня (Сase 8 ' MediaEnded из MSDN), запускает следующую песню, но почему-то когда проигрывает песня, песня меняется, но не проигрывается

217
Serialize ASCIIEncoding

Serialize ASCIIEncoding

Работаю сейчас с AR (Active Reports), есть у них классы HTMLExport, PdfExport, TextExportТак вот в текст экспорт есть public свойство Encoding Encoding, которое содержит кодировки

196
Не вызывается callback потока в C#

Не вызывается callback потока в C#

Имеется приложение на C# ASPNET MVC

209
Как передать state в this.props.children. React

Как передать state в this.props.children. React

ПриветНе знаю как при загрузке с помощью react-router какогото layaut-а передать state в this

261