在过去几年里,我做过的最有趣的项目之一是一个关于图像处理的项目。目标是开发一种能够识别可口可乐“罐”的系统(请注意,我强调的是“罐”这个词,你会在一分钟内看到原因)。您可以看到下面的一个示例,其中可以在绿色矩形中识别,带有缩放和旋转。

项目的一些限制:

背景可能非常嘈杂。罐可以有任何刻度或旋转,甚至可以有方向(在合理的范围内)。图像可能具有一定程度的模糊性(轮廓可能不完全笔直)。图像中可能有可口可乐瓶子,算法应该只检测到罐子!图像的亮度可能会有很大的变化(所以你不能“太依赖”颜色检测)。罐子可以部分隐藏在侧面或中间,也可能部分隐藏在瓶子后面。图像中可能根本就没有罐头,在这种情况下,你必须什么都找不到,然后写一条消息这样说。

所以你可能会遇到这样棘手的事情(在这种情况下,我的算法完全失败了):

我不久前做过这个项目,做得很开心,我有一个不错的实现。以下是关于我的实现的一些细节:

语言:使用OpenCV库在C++中完成。

预处理:对于图像预处理,即将图像转换为更原始的形式以提供给算法,我使用了两种方法:

将颜色域从RGB更改为HSV,并基于“红色”色调进行过滤,饱和度高于一定阈值以避免类似橙色的颜色,低值过滤以避免暗色调。最终的结果是一个黑白二值图像,其中所有的白色像素都将表示符合此阈值的像素。显然,图像中仍然有很多垃圾,但这减少了您必须处理的维度的数量。使用中值滤波(取所有邻居的中值像素值并用该值替换像素)进行噪声滤波,以减少噪声。使用Canny边缘检测滤波器在两个前一步骤后获得所有项目的轮廓。

算法:我为这项任务选择的算法本身取自这本关于特征提取的很棒的书,称为广义霍夫变换(与常规霍夫变换截然不同)。它基本上说了几件事:

你可以在不知道其解析方程的情况下描述空间中的物体(这里就是这种情况)。它可以抵抗图像变形,例如缩放和旋转,因为它基本上会测试图像的缩放因子和旋转因子的每一种组合。它使用算法将“学习”的基础模型(模板)。轮廓图像中剩余的每个像素将根据从模型中获得的信息,投票给另一个像素,该像素可能是对象的中心(按重力计算)。

最后,你会得到一张选票的热图,例如,在这里,罐子轮廓的所有像素都会投票给它的引力中心,所以你会在与中心相对应的同一个像素中获得很多选票,并且会在热图中看到一个峰值,如下所示:

一旦你做到了这一点,一个简单的基于阈值的启发式方法可以为你提供中心像素的位置,你可以从中导出缩放和旋转,然后围绕它绘制你的小矩形(最终的缩放和旋转因子显然是相对于你的原始模板的)。至少在理论上。。。

结果:现在,虽然这种方法在基本案例中有效,但在某些领域严重缺乏:

它非常慢!我没有充分强调这一点。几乎需要整整一天的时间来处理30张测试图像,显然是因为我的旋转和平移比例非常高,因为有些罐子非常小。当瓶子出现在图像中时,它完全丢失了,出于某种原因,几乎总是找到瓶子而不是罐子(可能是因为瓶子更大,因此像素更多,因此投票更多)模糊图像也不好,因为投票结果以像素形式出现在中心周围的随机位置,从而以非常嘈杂的热图结束。在平移和旋转方面实现了差异,但在方向上没有,这意味着没有直接面对摄像机目标的罐子无法被识别。

你能帮我改进我的特定算法吗,专门使用OpenCV特性,来解决上面提到的四个特定问题吗?

我希望有些人也能从中学到一些东西,毕竟我认为不仅仅是提问的人应该学习


当前回答

如果您对它的实时性感兴趣,那么您需要添加一个预处理过滤器,以确定哪些内容会被重负荷扫描。一个很好的快速、非常实时的预处理过滤器,它可以让你扫描更可能是可口可乐罐的东西,然后再移动到更棘手的东西上,它是这样的:在图像中搜索与可口可乐罐sqrt(pow(红色,2)+pow(蓝色,2)+pow(绿色,2))有一定公差的最大色块。从非常严格的颜色容差开始,然后逐步降低到更宽松的颜色容差。然后,当您的机器人在处理当前帧的分配时间内用完时,它会将当前找到的瓶子用于您的目的。请注意,您必须调整sqrt中的RGB颜色(pow(红色,2)+pow(蓝色,2)+pow(绿色,2)),以使其恰到好处。

此外,这看起来真的很愚蠢,但在编译C代码时,是否确保启用了-oFast编译器优化?

其他回答

请看一下Zdenek Kalal的捕食者跟踪器。它需要一些训练,但它可以主动学习被跟踪对象在不同方向和尺度上的外观,并实时进行操作!

源代码可以在他的网站上找到。它在MATLAB中,但也许社区成员已经完成了一个Java实现。我已经成功地在C#中重新实现了TLD的跟踪器部分。如果我没记错的话,TLD使用费尔斯作为关键点检测器。我使用SURF或SIFT(@stacker已经建议)来重新获取被跟踪器丢失的对象。跟踪器的反馈可以很容易地随时间建立一个筛选/冲浪模板的动态列表,随着时间的推移,可以以非常高的精度重新获取对象。

如果你对我的跟踪器的C#实现感兴趣,欢迎提问。

另一种方法是使用尺度不变特征变换(SIFT)或加速鲁棒特征(SURF)提取特征(关键点)。

您可以在这个页面上找到一个用Java、C++和Python编写的OpenCV代码示例:Features2D+同态查找已知对象

这两种算法对缩放和旋转都是不变的。因为它们与特征一起工作,所以也可以处理遮挡(只要有足够多的关键点可见)。

图像来源:教程示例

SIFT的处理需要几百毫秒,SURF速度更快,但不适合实时应用。ORB使用FAST,FAST在旋转不变性方面较弱。

原始文件

SURF:加速强大功能独特的图像特征来自比例不变关键点ORB:SIFT或SURF的有效替代方案

如果您对它的实时性感兴趣,那么您需要添加一个预处理过滤器,以确定哪些内容会被重负荷扫描。一个很好的快速、非常实时的预处理过滤器,它可以让你扫描更可能是可口可乐罐的东西,然后再移动到更棘手的东西上,它是这样的:在图像中搜索与可口可乐罐sqrt(pow(红色,2)+pow(蓝色,2)+pow(绿色,2))有一定公差的最大色块。从非常严格的颜色容差开始,然后逐步降低到更宽松的颜色容差。然后,当您的机器人在处理当前帧的分配时间内用完时,它会将当前找到的瓶子用于您的目的。请注意,您必须调整sqrt中的RGB颜色(pow(红色,2)+pow(蓝色,2)+pow(绿色,2)),以使其恰到好处。

此外,这看起来真的很愚蠢,但在编译C代码时,是否确保启用了-oFast编译器优化?

这可能是一个非常幼稚的想法(或者根本不起作用),但所有焦炭罐的尺寸都是固定的。因此,如果同一张图片中同时包含一个罐子和一个瓶子,那么你可以根据尺寸来区分它们(瓶子会更大)。现在,由于缺少深度(即3D映射到2D映射),瓶子可能会缩小,并且没有尺寸差异。您可以使用立体成像恢复一些深度信息,然后恢复原始大小。

即使是人类也很难在第二张图片中区分瓶子和罐子(前提是瓶子的透明区域是隐藏的)吗?

除了一个很小的区域外,它们几乎是一样的(也就是说,罐子顶部的宽度有点小,而瓶子的包装纸整个宽度相同,但有一个小变化,对吗?)

我想到的第一件事是检查瓶子的红色顶部。但是,如果瓶子没有顶部,或者瓶子部分隐藏(如上所述),这仍然是一个问题。

我想到的第二件事是关于瓶子的透明度。OpenCV在查找图像中的透明对象方面有一些工作。检查以下链接。

OpenCV会议记录2012-03-19OpenCV会议记录2012-02-28

特别是看看这个,看看他们如何准确地检测玻璃:

OpenCV会议记录2012-04-24

查看其实施结果:

他们说这是K.McHenry和J.Ponce在CVPR 2006年发表的论文《寻找玻璃的大地测量活动轮廓框架》的实施。

这可能会对你的情况有所帮助,但如果瓶子装满了,问题就会再次出现。

所以我认为在这里,你可以先搜索瓶子的透明主体,或者搜索一个红色区域,该区域与两个透明物体横向连接,这显然就是瓶子。(理想情况下,图像如下。)

现在,您可以删除黄色区域,即瓶子的标签,并运行您的算法来查找罐子。

无论如何,这个解决方案和其他解决方案一样也有不同的问题。

只有当你的瓶子是空的时候,它才起作用。在这种情况下,您必须搜索两种黑色之间的红色区域(如果可口可乐液体是黑色的)。如果透明部分被覆盖,则另一个问题。

但无论如何,如果图片中没有上述问题,这似乎是一个更好的方法。