如何最佳地确定图像中的边缘?

我最近被置于裁剪和调整图像大小的问题面前。 我需要裁剪图像的“主要内容”,例如,如果我有一个类似于此的图像: alt text http://sofzh.miximages.com/c%23/

结果应该是msn内容没有白边(左和右)的图像。

我在X轴上搜索第一个和最后一个颜色变化,在Y轴上搜索相同的东西。 问题是逐行遍历图像需要一段时间…对于2000x1600px的图像,返回CropRect => x1,y1,x2,y2数据需要2秒钟。

我尝试为每个坐标进行遍历并在找到的第一个值上停止,但它在所有测试用例中都不起作用。有时返回的数据不是预期的,并且操作的持续时间类似。

任何想法如何减少遍历时间和发现围绕“主要内容”的矩形?

public static CropRect EdgeDetection(Bitmap Image, float Threshold) { CropRect cropRectangle = new CropRect(); int lowestX = 0; int lowestY = 0; int largestX = 0; int largestY = 0; lowestX = Image.Width; lowestY = Image.Height; //find the lowest X bound; for (int y = 0; y < Image.Height - 1; ++y) { for (int x = 0; x  Threshold)) { if (lowestX > x) lowestX = x; if (largestX  Threshold)) { if (lowestY > y) lowestY = y; if (largestY < y) largestY = y; } } } if (lowestX  0 ? lowestX - 3 : 0; else cropRectangle.X = 0; if (lowestY  0 ? lowestY - 3 : 0; else cropRectangle.Y = 0; cropRectangle.Width = largestX - lowestX + 8 > Image.Width ? Image.Width : largestX - lowestX + 8; cropRectangle.Height = largestY + 8 > Image.Height ? Image.Height - lowestY : largestY - lowestY + 8; return cropRectangle; } } 

一种可能的优化是使用Lockbits直接访问颜色值,而不是通过慢得多的GetPixel。

如果您搜索Lockbits,首先点击的是http://www.bobpowell.net/lockingbits.htm 。 这是一个很好的参考。

另一方面,我的测试表明,如果你试图将GetPixelFast等效于GetPixel并将其作为替代品放入,那么与Lockbits相关的开销会使该方法变慢。 相反,您需要确保所有像素访问都是在一次点击而不是多次点击中完成的。 如果您没有锁定/解锁每个像素,这应该很适合您的代码。

这是一个例子

 BitmapData bmd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, b.PixelFormat); byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride); // Blue Green Red Color c = Color.FromArgb(row[x * pixelSize + 2], row[x * pixelSize + 1], row[x * pixelSize]); b.UnlockBits(bmd); 

还有两点需要注意:

  1. 此代码不安全,因为它使用指针
  2. 此方法取决于位图数据中的像素大小,因此您需要从bitmap.PixelFormat派生pixelSize

GetPixel可能是你的主要罪魁祸首(我建议运行一些分析测试来跟踪它),但你可以像这样重构算法:

  1. 从左到右和从右到左扫描第一行(y = 0)并记录第一个和最后一个边缘位置。 没有必要检查所有像素,因为你想要极端边缘。
  2. 扫描所有后续行,但现在我们只需要向外搜索(从中心到边缘),从我们上一个已知的最小边缘开始。 我们想找到极端的边界,所以我们只需要在我们能找到新极值的区域进行搜索。
  3. 对列进行重复前两步,建立初始极值,然后使用这些极值迭代绑定搜索。

如果您的图像通常主要是内容,这应该会大大减少比较次数。 最糟糕的情况是完全空白的图像,对于这种情况,这可能不如穷举搜索效率低。

在极端情况下,图像处理也可以从并行性中受益(将图像拆分并在多核CPU上的多个线程中处理),但这是一项额外的工作,您还可以进行其他更简单的更改。 线程开销往往会限制此技术的适用性,如果您希望通过专用的传入数据重复处理(以弥补初始设置成本)来实现“实时”运行,则主要有用。

这不会使订单变得更好……但是如果你平衡你的门槛,你将不需要做一个非常昂贵的平方根。

这应该会显着提高速度。