Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么';判断位图是否完全为黑色的有效方法是什么?_C#_.net_Image_Bitmap - Fatal编程技术网

C# 什么';判断位图是否完全为黑色的有效方法是什么?

C# 什么';判断位图是否完全为黑色的有效方法是什么?,c#,.net,image,bitmap,C#,.net,Image,Bitmap,我想知道是否有一种超级有效的方法来确认图像对象引用的是一个完全黑色的图像,因此位图中的每个像素都是ARGB(255,0,0,0) 你推荐什么?这些位图中的大多数都是1024 x 6000像素(尽管假设它们总是那么大是不安全的) 我需要这个,因为我们的PrintWindowAPI有问题。我们发现,近20%的情况下,图像至少有一部分是黑色正方形(后续捕获将成功)。我解决这个问题的想法是对每个子窗口调用PrintWindow或WM_PRINT,然后将窗口的整个图像重新拼接在一起。如果我能找到一种有效的

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

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

我需要这个,因为我们的PrintWindowAPI有问题。我们发现,近20%的情况下,图像至少有一部分是黑色正方形(后续捕获将成功)。我解决这个问题的想法是对每个子窗口调用PrintWindow或WM_PRINT,然后将窗口的整个图像重新拼接在一起。如果我能找到一种有效的方法来检测PrintWindow为特定子窗口返回的黑色图像,那么我可以在捕获时再次快速调用PrintWindow。它很糟糕,但PrintWindow是捕获在所有窗口上都能工作的窗口的唯一方法(无论如何,这是我想要的),并且支持捕获隐藏和/或屏幕外的窗口

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


显然,PrintWindow在Vista及更高版本中更好,但在本例中,我们仅限于Server2003

如果您对图像非黑色的条件了解得更多,就会更容易。例如,当图像为非黑色时,其边缘或中心看起来是什么样的。本质上,你所创建的是一个启发式的猜测,在一个非黑色的图像和样本,这些领域将给你最快的阅读。如果您的启发式指示一个全黑图像,那么您可以决定它是全黑的,或者对所有像素进行全面检查。不过,这在很大程度上取决于你的图像。如果您必须能够区分全黑图像和随机位置中包含单个非黑像素的图像,则必须对它们进行检查。

要完全确定图像的黑度,您必须检查每个像素,在不安全的块中访问像素数据可能是最快的方法。当然,可以针对非黑色情况进行优化,并尝试更早地找到这些情况,但在最坏的情况下,您必须始终检查每个像素。

并使用逐位操作对其进行扫描。不要使用
GetPixel
等;这太慢了。

我建议您使用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);
//锁定位图的位。
矩形rect=新矩形(0,0,bmp.Width,bmp.Height);
BitmapData bmpData=bmp.LockBits(rect,ImageLockMode.ReadWrite,bmp.PixelFormat);
//获取第一行的地址。
IntPtr ptr=bmpData.Scan0;
//声明一个数组以保存位图的字节。
int bytes=bmpData.Stride*bmp.Height;
字节[]rgbValues=新字节[字节];
//将RGB值复制到数组中。
Marshal.Copy(ptr,rgbvalue,0,字节);
//扫描非零字节
bool-allBlack=true;
for(int index=0;index

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

只是一些随机想法:

  • 也许你可以改成原版 位图(将其完全转换为 黑色)。然后将结果与测试结果进行比较 原著
  • 或者创建相同大小的位图 (充满纯黑色)然后 与原始位图进行比较

使用对角线为3 x 255的颜色矩阵绘制位图,这将使任何非黑色像素变成纯白色。然后将该位图绘制为较小的位图,其宽度为4的倍数,格式为24bpprgb。这消除了alpha,减小了大小,如果位图是真正的黑色,则只留下零


您必须进行实验以查看位图的大小,使用只有一个白色像素的示例来查看插值器何时使其消失。我猜你可以走得很远。

我有一个不切实际的想法

一辆汽车怎么样?您可以首先检查图像的尺寸,然后计算校验和,并将其与相同尺寸的全黑图像的已知(预先计算)校验和进行比较


编辑:我怀疑这会比@leonard的方法快。唯一的原因可能是原始文件不是位图,而是压缩图像格式。这样,CRC校验和算法就不必在运行之前解压缩图像。

一种合理可靠的方法是检查图像的文件大小。也就是说,如果不是全部黑色的图像具有相对正态的颜色分布

如果你知道文件类型,你就会知道一些关于平均压缩比的基本情况。您可以很容易地确定文件的尺寸,而无需在整个文件中循环

使用压缩文件格式的任何维度的全黑图像,与具有相当正态分布颜色的相同维度的图像相比,文件大小将非常小

这种方法需要花费一点时间来测试和建立一个知识库,了解全黑图像和非全黑图像的文件大小应该是多少,但是
public bool IsNotBlackImage()
{
    Assembly assembly = this.GetType().Assembly;
    var imgTest = new Bitmap(assembly.GetManifestResourceStream("TestImage.png"));
    var imgStatistics = new ImageStatistics(imgTest);             
    return imgStatistics.PixelsCountWithoutBlack != 0;
}
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;
}
    private bool AllOneColor(Bitmap bmp)
    {
        BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
        byte[] rgbValues = new byte[bmpData.Stride * bmpData.Height];
        System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, rgbValues, 0, rgbValues.Length);
        bmp.UnlockBits(bmpData);
        return !rgbValues.Where((v, i) => i % bmpData.Stride < bmp.Width && v != rgbValues[0]).Any();
    }