7

我到处都看过,但似乎没有一个标准(我可以看到)如何检查图像是否为空白。在 C# 中

我有这样做的方法,但很想知道检查图像是否为空白的正确方法是什么,以便将来每个人都可以知道。

我不会复制粘贴一堆代码,如果您愿意,我会很高兴,但我首先想解释一下我如何检查图像是否为空白。

您拍摄 .jpg 图像,获取它的宽度。例如 500 像素然后你将它除以 2 得到 250

然后你检查每个像素的颜色在(250 宽度和 i 高度)的位置(你迭代认为图像的高度。

然后这样做只是垂直检查图像的中间像素线。它会检查所有像素以查看颜色是否为白色以外的任何颜色。我已经这样做了,因此您不必搜索所有 500* 高度的像素,因为您几乎总是会在页面中间遇到一种颜色。

它的工作......有点慢......必须有更好的方法来做到这一点?您可以将其更改为垂直搜索 2/3/4 行,以增加发现非空白页面的机会,但这将花费更长的时间。

(另请注意,在这种情况下,使用图像的大小来检查它是否包含某些内容将不起作用,因为带有两个句子的页面和空白页面的大小彼此太接近)

加入溶液后。

帮助实施和理解解决方案的资源。

(请注意,在第一个网站上,所述 Pizelformat 实际上是 Pixelformat) - 我知道的小错误,只是提到,可能会给某些人造成一些混淆。

在我实施了加快像素搜寻的方法后,速度并没有提高多少。所以我会认为我做错了什么。

旧时间 = 15.63,40 张图像。

新时间 = 40 张图像的 15.43

我在 DocMax引用的精彩文章中看到,代码“锁定”在一组像素中。(或者这就是我的理解)所以我所做的就是锁定每页的中间行像素。这是正确的做法吗?

private int testPixels(String sourceDir)
    {
         //iterate through images
        string[] fileEntries = Directory.GetFiles(sourceDir).Where(x => x.Contains("JPG")).ToArray();

        var q = from string x in Directory.GetFiles(sourceDir)
                where x.ToLower().EndsWith(".jpg")
                select new FileInfo(x);

        int holder = 1;
        foreach (var z in q)
        {
            Bitmap mybm= Bitmap.FromFile(z.FullName) as Bitmap;
            int blank = getPixelData2(mybm);
           
            if (blank == 0)
            {
                holder = 0;
                break;
            }
        }
        return holder;
    }

然后上课

private unsafe int getPixelData2(Bitmap bm)
        {
            BitmapData bmd = bm.LockBits(new System.Drawing.Rectangle((bm.Width / 2), 0, 1, bm.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);

            int blue;
            int green;
            int red;

            int width = bmd.Width / 2;
            for (int y = 0; y < bmd.Height; y++)
            {
                byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride);

                blue = row[width * 3];
                green = row[width * 2];
                red = row[width * 1];

                // Console.WriteLine("Blue= " + blue + " Green= " + green + " Red= " + red);
                //Check to see if there is some form of color
                if ((blue != 255) || (green != 255) || (red != 255))
                {
                    bm.Dispose();
                    return 1;
                }
            }
            bm.Dispose();
            return 0;
        }
4

3 回答 3

9

如果您可以容忍出错的机会,那么该方法似乎很好;在我的案例中,我做了一些非常相似的事情,尽管我总是有一个视觉确认来处理错误。

对于性能,关键的悬而未决的问题是如何让像素进行测试。如果你使用Bitmap.GetPixel,你肯定会遇到性能问题。(在 Google 中搜索“ Bitmap.GetPixel slow ”可以看到很多讨论。)

一次获取所有像素然后循环它们将获得更好的性能。为了清晰和完整,我个人喜欢Bob Powell 的 LockBits 讨论。使用这种方法,根据您的性能需求检查所有像素可能是合理的。

于 2012-10-02T05:34:41.697 回答
2

如果您使用的是 System.Drawing.Bitmap,您可以通过以下方式(基本上)加快速度:

  1. 不使用 GetPixel 访问像素,使用 LockBits 和 UnlockBits 将图像位图复制到常规内存。有关用法,请参阅MSDN 文档中的示例。
  2. 不在 for 循环中调用 Width、Height 或 Size 属性。调用 Size 一次,将值存储在局部变量中并在循环中使用它们。

笔记:

  1. 使用 System.Drawing.Bitmap 时,您的图像可能在设备内存中,访问它可能会很耗时。
  2. 我不记得将图像加载到位图中是否已经将其转换为 RGB 格式,因为其他格式更难以使用,但如果不是这种情况,您可以创建与原始图像大小相同的 RGB 位图,获取它的 Graphic 对象(Graphics.FromImage)并使用 DrawImage 在 RGB 位图中绘制原始图像。

编辑:被 DocMax 击败。

无论如何,为了速度,您还可以尝试使用替代库,例如包含 C# 包装器的优秀FreeImage 。

于 2012-10-02T05:49:02.017 回答
0

将图像缩放到 1x1,然后检查一个像素

新位图(previousImage, 新尺寸(1, 1));

于 2014-12-04T15:03:50.840 回答