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