检测图像是否为空的有效方法

时间:2010-06-02 14:26:30

标签: .net gdi+

我需要一种非常快速的方法来检测图像是否为空。在我的情况下,所有像素都是白色和透明的。 图像是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 个答案:

答案 0 :(得分:2)

您可以将GDI +位图“映射”到固定的byte[](或int[]或甚至uint[]),然后直接使用该数组来读取和写入ARGB位图数据。

以下CodeProject文章介绍了如何执行此操作:http://www.codeproject.com/KB/GDI-plus/pointerlessimageproc.aspx

答案 1 :(得分:1)

使用Marshal.ReadInt64()将立即为您提供x 8速度提升。注意过度宽度,你需要ReadByte()来获取扫描线中的最后几个像素。在帮助器程序集中用C#编写此代码可能是最快的修复,它允许您使用指针。

答案 2 :(得分:1)

当然,将图像除以设定的量,对于每个组,启动一个新线程仅检查非空白像素(例如,不是白色/透明)。

仅在找到非空像素时才创建触发(并设置标志)的事件。让每个线程检查这个标志(基本上是一个while循环)。

答案 3 :(得分:1)

使用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

答案 4 :(得分:0)

最有效的方法是手动解析文件,直接跳转到数据流并读取压缩的zLib流,直到找到非白色和透明的像素。

取决于图片的来源以及它们使用各种PNG“特殊”(过滤器,特殊调色板......)的程度,这可能需要付出很多努力,因此将“高效”视为“大量工作,但很快“。

有用的资源是PNG datastream specificationZLIB specification(或者更简单的zLib库)。

答案 5 :(得分:0)

Image Magick有一个c#包装器:

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

使用ImageMagik CLI的识别功能,如下所示:

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

使用命令:

identify -format "%#" source.png

如果颜色数为1,则表示空白页。

您也可以使用命令:

identify -verbose source.png

空白图像的标准偏差,偏斜和峰度为0。

答案 6 :(得分:0)

我会使用GDI +将PNG文件转换为BMP并将其保存到临时位置。然后我将利用其未压缩的特性,在标题之外寻找像素,准备一个中等大小(比如16384 B)的零字节的临时字符串,然后读取16384B块直到文件结尾,将它们与临时字符串进行比较。由于Windows XP及更高版本在读取文件末尾时给出零字节,因此无需对末尾进行特殊处理,只需在最后一次迭代时读取一些内容即可。 确保位图以32位模式保存,否则将无法检测到黑色不透明像素。此模式还将处理任何调色板和其他怪癖,以便您甚至可以寻找固定的后标题偏移。