什么是一种有效的方法来判断位图是否完全是黑色的?

Mat*_*ley 21 .net c# image bitmap

我想知道是否有一种确保Image对象引用完全黑色图像的超高效方法,因此位图中的每个像素都是ARGB(255,0,0,0).

你会推荐什么?这些位图中的大多数将是1024 x 6000像素(尽管假设它们总是那么大,这是不安全的).

我需要这个,因为我们遇到了PrintWindow API的问题.我们发现近20%的时间,至少图像的某些部分将是黑色方块(后续捕获将成功).我想解决这个问题的方法是在每个子窗口中调用PrintWindow或WM_PRINT,然后将窗口的整个图像重新组合在一起.如果我能找到一种有效的方法来检测PrintWindow为特定子窗口返回黑色图像,那么我可以在该捕获上再次快速调用PrintWindow.它很糟糕,但PrintWindow是捕获适用于所有窗口(我想要的)窗口的唯一方法,并支持捕获隐藏和/或屏幕外的窗口.

当PrintWindow失败时,它不会设置错误代码或返回任何指示失败的内容.当它出现这个黑色方块问题时,它总是整个窗口或子窗口返回黑色.因此,通过分别捕获每个子窗口,我可以确定每个捕获都有效,只要它包含至少一个非黑色像素.

显然,PrintWindow在Vista及更高版本中更好,但在这种情况下,我们仅限于Server 2003.

小智 20

我建议你使用System.Drawing.Bitmap类型的LockBits方法锁定内存中的位图.此方法返回BitmapData类型,您可以从中接收指向锁定内存区域的指针.然后遍历内存,搜索非零字节(通过扫描Int32甚至Int64值,实际上,更快,具体取决于您使用的平台).代码如下所示:

// Lock the bitmap's bits.  
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData =bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);

// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;

// Declare an array to hold the bytes of the bitmap.
int bytes  = bmpData.Stride * bmp.Height;
byte[] rgbValues = new byte[bytes];

// Copy the RGB values into the array.
Marshal.Copy(ptr, rgbValues, 0, bytes);

// Scanning for non-zero bytes
bool allBlack = true;
for (int index = 0; index < rgbValues.Length; index++)
    if (rgbValues[index] != 0) 
    {
       allBlack = false;
       break;
    }
// Unlock the bits.
bmp.UnlockBits(bmpData);
Run Code Online (Sandbox Code Playgroud)

考虑使用不安全的代码和直接内存访问(使用指针)来提高性能.

  • 如果可能的话,对于大多数像素来说,像int []和然后值| = 0xFF000000一样,也会加速.Marshal.Copy可能很慢.. (3认同)
  • 是的,在DWORD组中检查值0xFF000000比一次检查一个字节要好得多. (3认同)

tva*_*son 7

如果您对图像非黑色的条件有更多了解,那就更容易了.例如,当图像的非黑色时,图像的边缘或中心是什么样的.从本质上讲,您创建的是启发式,可以猜测非黑色图像,并对那些能够为您提供最快读取的区域进行采样.如果您的启发式指示全黑图像,那么您可以决定它是全黑的还是对所有像素进行全面检查.但这很大程度上取决于你的图像.如果您必须能够在随机位置区分全黑图像和包含单个非黑像素的图像,则必须全部检查它们.


小智 7

这篇文章的第一个答案是Awesome.我修改了代码以更一般地确定图像是否都是一种颜色(全黑,全白,所有洋红等等).假设您有一个包含4个颜色值ARGB的位图,请将每种颜色与左上角的颜色进行比较(如果有任何不同),则图像不是全部一种颜色.

private bool AllOneColor(Bitmap bmp)
{
    // Lock the bitmap's bits.  
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);

    // Get the address of the first line.
    IntPtr ptr = bmpData.Scan0;

    // Declare an array to hold the bytes of the bitmap.
    int bytes = bmpData.Stride * bmp.Height;
    byte[] rgbValues = new byte[bytes];

    // Copy the RGB values into the array.

    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

    bool AllOneColor = true;
    for (int index = 0; index < rgbValues.Length; index++)
    {
        //compare the current A or R or G or B with the A or R or G or B at position 0,0.
        if (rgbValues[index] != rgbValues[index % 4])
        {
            AllOneColor= false;
            break;
        }
    }
    // Unlock the bits.
    bmp.UnlockBits(bmpData);
    return AllOneColor;
}
Run Code Online (Sandbox Code Playgroud)


Cra*_*ntz 6

将位图锁定到内存中并使用按位操作进行扫描.不要使用GetPixel等; 那很慢.