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