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

项目的一些限制:

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

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

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

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

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

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

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

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

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

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

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

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

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

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


当前回答

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

其他回答

查看形状

看看罐子/瓶子红色部分的形状。请注意,罐的顶部略微变细,而瓶的标签是直的。您可以通过比较红色部分的宽度和长度来区分这两者。

查看亮点

区分瓶子和罐子的一种方法是材料。瓶子由塑料制成,而罐子由铝金属制成。在光线充足的情况下,观察镜面反射是区分瓶子标签和罐头标签的一种方法。

据我所知,这就是人类如何区分这两种标签的区别。如果照明条件较差,那么在区分这两个方面肯定会有一些不确定性。在这种情况下,您必须能够检测到透明/半透明瓶子本身的存在。

为了加快速度,我会利用这样一个事实,即您不需要找到任意的图像/对象,而是需要找到带有可口可乐标志的图像/物体。这一点非常重要,因为这个标志非常独特,并且在频域中,特别是在RGB的红色通道中,它应该具有特征性的、尺度不变的特征。也就是说,水平扫描线(在水平对齐的徽标上训练)所遇到的从红到白到红的交替图案在穿过徽标的中心轴时将具有独特的“节奏”。这种节奏将在不同的尺度和方向上“加速”或“减速”,但在比例上保持相等。您可以识别/定义几十条这样的扫描线,包括水平和垂直穿过徽标的扫描线以及多条对角的扫描线。称这些为“签名扫描线”

在目标图像中搜索该签名是以水平条扫描图像的简单问题。寻找红色通道中的高频(表示从红色区域移动到白色区域),一旦发现,查看是否跟随训练课程中确定的频率节律。一旦找到匹配项,您将立即知道扫描线在徽标中的方向和位置(如果您在训练过程中跟踪这些内容),因此从那里识别徽标的边界是微不足道的。

如果这不是一个线性有效的算法,或者几乎是这样,我会感到惊讶。它显然不能解决你的罐头瓶歧视问题,但至少你会有你的标志。

(更新:为了识别瓶子,我会在标志附近寻找可乐(棕色液体),也就是瓶子内部。或者,在一个空瓶子的情况下,我会寻找一个帽子,它将始终具有相同的基本形状、大小和与徽标的距离,通常都是白色或红色。搜索一个纯色椭圆形状,帽子应该在哪里,相对于徽标。当然不是万无一失,但你的目标应该是快速找到容易的。)

(我的图像处理时代已经过去几年了,所以我保持了这个建议的高度和概念性。我认为它可能稍微接近人眼的运作方式,或者至少我的大脑是如何运作的!)

如果你不局限于一个不受你限制的相机,也许你可以改用像Xbox Kinect这样的距离传感器。使用此功能,您可以对图像执行基于深度和颜色的匹配分割。这允许更快地分离图像中的对象。然后,您可以使用ICP匹配或类似技术来匹配罐子的形状,而不仅仅是它的轮廓或颜色,如果它是圆柱形的,如果您之前对目标进行过3D扫描,这可能是任何方向的有效选项。这些技术通常很快,特别是用于解决速度问题的特定目的时。

我还建议,不一定是为了准确性或速度,而是为了好玩,你可以在色调分割图像上使用经过训练的神经网络来识别罐子的形状。这些速度非常快,通常可以达到80/90%的准确率。培训需要一个很长的过程,因为您必须手动识别每个图像中的罐。

我不知道OpenCV,但从逻辑上看,我认为你可以通过改变你正在寻找的形象,即可口可乐,来区分瓶子和罐头。你应该一直到罐的顶部,因为如果是罐,可口可乐顶部有银色衬里,而如果是瓶子,则没有银色衬里。

但显然,这种算法在罐头顶部隐藏的情况下会失败,但在这种情况下,即使是人类也无法区分两者(如果只有可乐瓶/罐头的可口可乐部分可见)

有趣的问题:当我瞥了一眼你的瓶子图片时,我以为它也是一个罐子。但是,作为一个人,我所做的区别是,我注意到这也是一个瓶子。。。

那么,为了区分罐子和瓶子,先扫描瓶子怎么样?如果你找到了一个,在找罐头之前先把标签遮住。

如果你已经在做罐头,那么实施起来并不太困难。真正的缺点是它使处理时间加倍。(但考虑到现实世界中的应用程序,你最终还是会想做瓶子;-)