在过去几年中,我从事的最有趣的项目之一是关于图像处理的项目。目标是开发一个能够识别可口可乐“罐头”的系统(请注意,我强调的是“罐头”这个词,你马上就会明白为什么)。您可以在下面看到一个示例,在带有缩放和旋转的绿色矩形中识别出罐头。
项目的一些限制:
- 背景可能非常嘈杂。
- 罐头可以有任何比例或旋转甚至方向(在合理的范围内)。
- 图像可能有一定程度的模糊(轮廓可能不完全笔直)。
- 图像中可能有可口可乐瓶,算法应该只检测罐头!
- 图像的亮度可能会有很大差异(因此您不能“过多地”依赖颜色检测)。
- 罐子可以部分隐藏在侧面或中间,也可能部分隐藏在瓶子后面。
- 图像中可能根本没有罐子,在这种情况下,您必须什么也没找到并写一条消息说。
所以你最终可能会遇到这样棘手的事情(在这种情况下,我的算法完全失败了):
不久前我做了这个项目,做起来很有趣,而且我有一个不错的实现。以下是有关我的实现的一些细节:
语言:使用OpenCV库在 C++ 中完成。
预处理:对于图像预处理,即将图像转换为更原始的形式以提供给算法,我使用了两种方法:
- 将色域从 RGB 更改为HSV并基于“红色”色调进行过滤,饱和度高于某个阈值以避免类似橙色的颜色,并过滤低值以避免暗色调。最终结果是二值黑白图像,其中所有白色像素都表示与此阈值匹配的像素。显然,图像中仍然有很多废话,但这减少了您必须处理的维度数量。
- 噪声过滤使用中值滤波(取所有邻居的中值像素值并以此值替换像素)来降低噪声。
- 使用Canny 边缘检测过滤器在 2 个先例步骤后获取所有项目的轮廓。
算法:我为这项任务选择的算法本身取自这本很棒的关于特征提取的书,称为广义霍夫变换(与常规霍夫变换完全不同)。它基本上说了几件事:
- 您可以在不知道其解析方程的情况下描述空间中的物体(这里就是这种情况)。
- 它可以抵抗缩放和旋转等图像变形,因为它基本上会针对缩放因子和旋转因子的每种组合测试您的图像。
- 它使用算法将“学习”的基本模型(模板)。
- 根据从模型中学到的知识,轮廓图像中剩余的每个像素都会投票给另一个像素,该像素应该是对象的中心(就重力而言)。
最后,你会得到一张投票的热图,例如这里的罐子轮廓的所有像素都会投票给它的重心,所以你会在对应的同一个像素中有很多票中心,并将在热图中看到一个峰值,如下所示:
一旦你有了这个,一个简单的基于阈值的启发式可以给你中心像素的位置,你可以从中得出比例和旋转,然后在它周围绘制你的小矩形(最终的比例和旋转因子显然是相对于你的原始模板)。至少理论上...
结果:现在,虽然这种方法在基本情况下有效,但在某些领域严重缺乏:
- 它非常慢!我没有足够强调这一点。处理这 30 张测试图像几乎需要一整天,显然是因为我有一个非常高的旋转和平移比例因子,因为有些罐子非常小。
- 当瓶子出现在图像中时它完全丢失了,并且由于某种原因几乎总是找到瓶子而不是罐子(也许是因为瓶子更大,因此有更多的像素,因此有更多的选票)
- 模糊图像也不好,因为投票最终以像素形式出现在中心周围的随机位置,因此以非常嘈杂的热图结束。
- 实现了平移和旋转的不变性,但没有实现方向性,这意味着无法识别未直接面向相机目标的罐头。
你能帮我改进我的特定算法,使用专门的 OpenCV功能来解决提到的四个特定问题吗?
我希望有些人也能从中学到一些东西,毕竟我认为不只是提问的人应该学习。:)