эффективный способ определить, пусто ли изображение - PullRequest
4 голосов
/ 02 июня 2010

Мне нужен очень быстрый метод, чтобы определить, пусто ли изображение. В моем случае все пиксели белые и прозрачные. Изображения PNG. Мой текущий метод состоит в том, чтобы загрузить их в растровое изображение памяти и проверить значение каждого пикселя, но это медленный способ Есть ли более эффективный способ?

Это мой текущий код:

'Lock the bitmap bits.  
    Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(rectBmp, _
        Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat)

    Try
        Dim x As Integer
        Dim y As Integer

        For y = 0 To bmpData.Height - 1
            For x = 0 To bmpData.Width - 1
                If System.Runtime.InteropServices.Marshal.ReadByte(bmpData.Scan0, (bmpData.Stride * y) + (4 * x) + 3) <> 0 Then
                    Return True
                    Exit For
                End If
            Next
        Next
    Finally
        bmp.UnlockBits(bmpData)
    End Try

Ответы [ 7 ]

2 голосов
/ 02 июня 2010

Вы можете «отобразить» растровое изображение GDI + на закрепленный byte[] (или int[] или даже uint[]) и тем самым напрямую использовать массив для чтения и записи растровых данных ARGB.

В следующей статье CodeProject объясняется, как это сделать: http://www.codeproject.com/KB/GDI-plus/pointerlessimageproc.aspx

1 голос
/ 05 июня 2010

Используя C # (я знаю, что ваш образец находится в VB.Net), вы можете использовать небезопасный и получить очень быстрый доступ к своему растровому изображению:

        const int ALPHA_PIXEL = 3;
        const int RED_PIXEL = 2;
        const int GREEN_PIXEL = 1;
        const int BLUE_PIXEL = 0;

        try
        {
            BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);

            int bytesPerPixel = (bmp.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4);
            int stride = bmData.Stride;

            unsafe
            {
                byte* pixel = (byte*)(void*)bmData.Scan0;
                for (int y = 0; y < bmp.Height; y++)
                {
                    int yPos = y * stride;
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int pos = yPos + (x * bytesPerPixel);

                        if (pixel[pos + RED_PIXEL] != 255 || pixel[pos + GREEN_PIXEL] != 255 || pixel[pos + BLUE_PIXEL] != 255 ||
                            pixel[pos + ALPHA_PIXEL] != 0)
                            {
                                return true;
                            }
                    }

                }
            }
        }
        finally 
        {
            bmp.UnlockBits(bmData);
        }
        return false;

Если вы не можете использовать C #, то самый быстрый способ - использовать Marshal.Copy в качестве блока:

    Dim bmData As BitmapData = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat)

    Try

        Dim bytesPerPixel As Integer = If(bmp.PixelFormat = PixelFormat.Format24bppRgb, 3, 4)
        Dim stride As Integer = bmData.Stride
        Dim imageSize As Integer = stride * bmp.Height

        Dim pixel As Byte()
        ReDim pixel(imageSize)
        Marshal.Copy(bmData.Scan0, pixel, 0, imageSize)

        For y As Integer = 0 To bmp.Height - 1
            Dim yPos As Integer = y * stride
            For x As Integer = 0 To bmp.Width - 1
                Dim pos As Integer = yPos + (x * bytesPerPixel)

                If pixel(pos + RED_PIXEL) <> 255 OrElse pixel(pos + GREEN_PIXEL) <> 255 OrElse pixel(pos + BLUE_PIXEL) <> 255 OrElse pixel(pos + ALPHA_PIXEL) <> 0 Then
                    Return
                End If

            Next
        Next
    Finally
        bmp.UnlockBits(bmData)
    End Try
    Return
1 голос
/ 02 июня 2010

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

Создать событие, которое запускается (и устанавливает флаг), только если обнаружен непустой пиксель. Попросите каждый поток проверить этот флаг (в основном цикл while).

1 голос
/ 02 июня 2010

Использование Marshal.ReadInt64 () даст вам немедленное увеличение скорости в 8 раз. Не упустите Width, хотя вам понадобится ReadByte () для последних нескольких пикселей в строке сканирования. Написание этого кода на C # во вспомогательной сборке, вероятно, является самым быстрым решением, позволяющим использовать указатель.

0 голосов
/ 27 мая 2014

Я бы использовал GDI + для преобразования PNG-файла в BMP и сохранения его во временном местоположении. Затем я использовал бы его несжатый характер, искал за пределами заголовка пиксели, подготовил временную строку среднего размера (скажем, 16384 B), заполненную нулевыми байтами, и затем прочитал куски 16384B до конца файла, сравнивая их с временной строкой. Поскольку Windows XP и выше дает нулевые байты при чтении за концом файла, никакой специальной обработки конца не требуется, просто прочитайте немного за конец с вашей последней итерацией. Убедитесь, что растровое изображение сохранено в 32-разрядном режиме, иначе черные непрозрачные пиксели не будут обнаружены. Этот режим также позаботится о любых палитрах и других причудах, так что вы даже можете искать фиксированное смещение после заголовка.

0 голосов
/ 03 декабря 2013

Существует обертка c # для Image Magick:

http://sourceforge.net/projects/imagemagickapp/

Используйте функцию идентификации в ImageMagik CLI, как указано здесь:

http://www.imagemagick.org/script/identify.php

С командой:

identify -format "%#" source.png

Если количество цветов равно 1, у вас есть пустая страница.

Вы также можете использовать команду:

identify -verbose source.png

Стандартное отклонение, перекос и эксцесс будут равны 0 для пустого изображения.

0 голосов
/ 02 июня 2010

Наиболее эффективным способом было бы вручную проанализировать файл, напрямую перейти к потоку данных и прочитать сжатый поток zLib, пока не найдете пиксель, который не является белым и прозрачным.

В зависимости от того, откуда берутся картинки и насколько они используют различные «специальные» PNG (фильтры, специальная палитра ...), это может потребовать много усилий, поэтому читайте «эффективно» как «много работы, но очень быстро ".

Полезными ресурсами для этого являются спецификация PNG потока данных и спецификация ZLIB (или, что гораздо проще, библиотека zLib).

...