目前我在C#/ .NET中寻求一种相当快速且相当准确的算法来在代码中执行以下步骤:
我已经说明了我想要实现的目标:
我能想象的是将像素的颜色设置为(0,0),然后逐行/逐列逐行遍历所有像素直到我遇到一个像素用另一种颜色,然后切掉边框。
我只是担心这真的很慢。
所以我的问题是:
您是否了解任何快速算法(理想情况下没有任何第三方库)从内存中的图像/位图中删除“空”边框?
旁注:算法应该“合理准确”,而不是100%准确。像一条线太多或太少裁剪的一些宽容都可以。
加法1:
我刚刚以最简单的方式完成了我的强力算法。 See the code over at Pastebin.com
答案 0 :(得分:4)
如果你知道你的图像居中,你可以尝试对角行走(即(0,0),(1,1),...(n,n))直到你有一个命中,然后回溯一行检查时间,直到找到“空”行(在每个维度中)。对于您发布的图像,它会进行大量的比较。
你应该能够同时从两个对立的角落做到这一点,以获得一些多核心的行动。
当然,希望你不要在图像中心的1像素宽线的情况下:)或图像中断开对象的双重病态情况,使整个图像居中,但没有任何东西穿过对角线。
你可以做的一个改进是给你的“命中颜色”一些容忍度(可调节吗?)
答案 1 :(得分:1)
您建议的算法是强力算法,并且可以为所有类型的图像一直工作。
但是对于特殊情况,例如,主题图像居中并且是连续的颜色斑点(如您在示例中所示),可以应用二进制排序类型的算法。
从中心线(0,长度/ 2)开始,一次从一个方向开始,像在二进制搜索中一样检查线条。
为所有方面做。
这将降低将log n记录到基数2的复杂性
答案 2 :(得分:1)
首先,您当前的算法基本上是最好的。
如果您希望它运行得更快,可以用c ++编写代码。这比管理的不安全代码更有效。
如果您使用c#,则可以并行扩展以在多个核心上运行它。这不会减少机器上的负载,但如果有的话,它会减少延迟。
如果您碰巧有图像的预先计算缩略图,您可以先在缩略图上应用算法以获得一个粗略的想法。
答案 3 :(得分:1)
首先,您可以使用byte[]
将位图转换为LockBits()
,这将比GetPixel()
快得多,并且不需要您unsafe
。< / p>
只要您不天真地搜索整个图像而不是一次搜索一侧,就可以将算法钉入95%。只是让你没有搜索已经被裁剪的像素,因为如果你有两个相邻的边缘裁剪很多,这可能实际上使算法比天真的更差。
二进制搜索可以改善一点点,但它并不重要,因为在最佳情况下它可能会为每个方向节省一行搜索。
答案 4 :(得分:1)
虽然我更喜欢Tarang的答案,但我想通过引用给定的前景色和背景色(这称为“分段”)来提供一些关于如何“隔离”图像中对象的提示,并在工作时使用“光学检测”领域,其中图像不仅被裁剪到某个被检测物体上,而是对象被计数和测量,你可以在物体上测量的东西是面积,轮廓,直径等。
首先,通常你会开始真正地从x / y坐标0,0开始走过你的图像,然后从左到右,从上到下走,直到你找到一个有另一个值的像素作为背景。通过定义背景的灰度值以及前景的灰度值来给出分割的灵敏度。您可能会按照坐标来浏览图像,但是从程序视图中您只需要遍历一系列像素。这意味着您必须处理计算像素阵列中像素索引的x / y坐标的公式。这个公式确实需要图像的宽度和高度。
考虑到你对裁剪的关注,我认为当你找到前景物体的所谓“枢轴点”时,你通常会使用检测相同前景值的相邻像素的公式沿着找到的物体走路。 。如果在您的情况下只有一个对象可以检测,则很容易存储最北,最东,最南和最西的像素坐标。这4个坐标标记对象所适合的矩形。使用此信息,您可以计算新图像(裁剪图像)的宽度和高度。