c++ - 图像处理:“可口可乐罐”识别的算法改进




opencv introduction (16)

MVTec有一个名为HALCON的计算机视觉软件包,其演示可以为您提供良好的算法思路。 有很多类似于您的问题的示例,您可以在演示模式下运行,然后查看代码中的运算符,并了解如何从现有的OpenCV运算符实现它们。

我已经使用这个包来快速为这类问题建立复杂的算法原型,然后找到如何使用现有的OpenCV特性来实现它们。 特别是对于你的情况,你可以尝试在OpenCV中实现嵌入在运算符find_scaled_shape_model的功能。 一些运营商指出了关于算法实现的科学论文,它可以帮助找出如何在OpenCV中做类似的工作。 希望这可以帮助...

过去几年中我最感兴趣的项目之一就是一个关于图像处理的项目。 我们的目标是建立一个能够识别可口可乐'罐'的系统 (请注意,我强调'罐'这个词,你会在一分钟内看到为什么。 您可以在下面看到一个示例,其中可以通过缩放和旋转在绿色矩形中识别。

项目的一些限制:

  • 背景可能非常嘈杂。
  • 可以具有任何比例旋转或甚至定向(在合理范围内)。
  • 图像可能有一定程度的模糊性(轮廓可能不完全是直的)。
  • 图像中可能有可口可乐瓶,算法只应检测罐头
  • 图像的亮度可能会有很大的差异(所以你不能在颜色检测上“过多”)。
  • 罐子可以部分隐藏在侧面或中间,并且可能部分隐藏在瓶子后面。
  • 在图像中完全没有可能 ,在这种情况下,你必须找不到任何东西,并写出一条消息说明。

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

我前段时间做过这个项目,并且做了很多乐趣,并且我有一个体面的实现。 以下是关于我的实现的一些细节:

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

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

  1. 将颜色区域从RGB更改为HSV并根据“红色”色调进行过滤,在特定阈值以上进行饱和以避免类橙色的颜色,并对低值进行过滤以避免产生深色调。 最终结果是二进制黑白图像,其中所有白色像素都代表与此阈值匹配的像素。 很明显,图像中仍然有很多垃圾,但是这会减少你需要处理的尺寸数量。
  2. 使用中值滤波进行噪声滤波(取所有邻居的中值像素值并用此值替换像素)以减少噪声。
  3. 使用Canny边缘检测滤波器在2个先例步骤之后获取所有项目的轮廓。

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

  • 您可以在不知道其分析方程的情况下描述空间中的物体(这里就是这种情况)。
  • 它可抵抗像缩放和旋转等图像变形,因为它将基本上针对缩放因子和旋转因子的每种组合来测试图像。
  • 它使用算法将“学习”的基础模型(模板)。
  • 基于从模型中学到的内容,轮廓图像中剩余的每个像素将投票给另一个像素,该像素将被视为对象的中心(就重力而言)。

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

一旦你有了这个,一个简单的基于阈值的启发式可以给你的中心像素的位置,从中可以导出比例和旋转,然后绘制你的小矩形(最终比例和旋转因子显然是相对于你的原始模板)。 理论上至少...

结果 :现在,虽然这种方法适用于基本案例,但在一些地区却严重缺乏:

  • 非常慢 ! 我没有足够强调这一点。 需要几乎整整一天来处理30个测试图像,显然是因为我有很高的旋转和平移比例因子,因为一些罐子很小。
  • 当图像中的瓶子完全丢失时,由于某种原因,几乎总是找到瓶子而不是罐子(也许是因为瓶子更大,因此像素更多,因此投票更多)
  • 模糊的图像也不是很好,因为选票以中心周围随机位置的像素结束,因此以非常嘈杂的热图结束。
  • 翻译和旋转方面的差异已达到,但不是定向的,这意味着没有直接面对相机目标的罐头未被识别。

您能否帮助我改进我的特定算法,仅使用OpenCV功能来解决上述四个具体问题?

我希望有些人也会从中学到一些东西,毕竟我不仅认为提出问题的人应该学习。 :)


深度学习

收集至少几百张包含可乐罐头的图像,将它们周围的边界框注释为正面课程,包括可乐瓶和其他可乐产品将它们标记为负面课程以及随机对象。

除非你收集一个非常大的数据集,否则就要使用小数据集的深度学习功能。 理想情况下,使用支持向量机(SVM)与深度神经网络的组合。

一旦将图像提供给以前训练过的深度学习模型(例如GoogleNet),而不是使用神经网络的决策(最终)图层进行分类,则可以使用先前图层的数据作为特征来训练分类器。

OpenCV和Google Net: http://docs.opencv.org/trunk/d5/de7/tutorial_dnn_googlenet.html : http://docs.opencv.org/trunk/d5/de7/tutorial_dnn_googlenet.html

OpenCV和SVM: http://docs.opencv.org/2.4/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html : http://docs.opencv.org/2.4/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html


If you are interested in it being realtime, then what you need is to add in a pre-processing filter to determine what gets scanned with the heavy-duty stuff. A good fast, very real time, pre-processing filter that will allow you to scan things that are more likely to be a coca-cola can than not before moving onto more iffy things is something like this: search the image for the biggest patches of color that are a certain tolerance away from the sqrt(pow(red,2) + pow(blue,2) + pow(green,2)) of your coca-cola can. Start with a very strict color tolerance, and work your way down to more lenient color tolerances. Then, when your robot runs out of an allotted time to process the current frame, it uses the currently found bottles for your purposes. Please note that you will have to tweak the RGB colors in the sqrt(pow(red,2) + pow(blue,2) + pow(green,2)) to get them just right.

Also, this is gona seem really dumb, but did you make sure to turn on -oFast compiler optimizations when you compiled your C code?


Maybe too many years late, but nevertheless a theory to try.

The ratio of bounding rectangle of red logo region to the overall dimension of the bottle/can is different. In the case of Can, should be 1:1, whereas will be different in that of bottle (with or without cap). This should make it easy to distinguish between the two.

Update: The horizontal curvature of the logo region will be different between the Can and Bottle due their respective size difference. This could be specifically useful if your robot needs to pick up can/bottle, and you decide the grip accordingly.


为了加快速度,我会利用这样一个事实,即不要求您找到任意图像/对象,但是特别是带有可口可乐徽标的图像/对象。 这很重要,因为这个标识非常有特色,并且它在频域中应该有一个特征,尺度不变的特征,特别是在RGB的红色通道中。 也就是说,水平扫描线(在水平对齐的徽标上训练)遇到的红色到白色到红色的交替模式在穿过徽标的中心轴时将具有独特的“节奏”。 该节奏将在不同的尺度和方向上“加速”或“放慢速度”,但仍将按比例相等。 您可以识别/定义几十条这样的扫描线,横向和纵向穿过徽标,还有几个对角线,以星爆图案。 称这些为“签名扫描线”。

在目标图像中搜索此签名是以水平条扫描图像的简单方法。 在红色通道中寻找高频(指示从红色区域移动到白色区域),一旦找到,看它是否跟随在培训课程中确定的一个频率节奏。 一旦找到匹配,您将立即知道扫描线在徽标中的方向和位置(如果您在训练过程中记录了这些事情),那么从中识别徽标的边界是微不足道的。

如果这不是线性有效的算法,或者几乎如此,我会感到惊讶。 它显然没有解决你的瓶子歧视问题,但至少你会有你的标识。

(更新:为了识别瓶子,我会在标识附近寻找可乐(棕色液体) - 也就是说, 瓶子内部 。或者,如果是空瓶子,我会寻找一个总是会有相同的基本形状,大小和距离的标志,通常是全白色或红色。搜索一个纯色椭圆形的帽子应该是,相对于标志,当然不是万无一失,但你的目标应该是快速找到容易的人。)

(从我的图像处理时代开始已经有几年了,所以我保留了这个高层次和概念性的建议,我认为它可能略微接近人眼可能的运作方式 - 或者至少我的大脑是如何运作的!)


作为所有这些优秀解决方案的替代方案,您可以训练您自己的分类器,并使您的应用程序对错误有效。 例如,您可以使用哈尔训练 ,为您的目标提供大量正面和负面图像。

只提取罐头可以是有用的,并且可以结合透明物体的检测。


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

它在OpenCV 2.3.1中实现。

您可以在Features2D + Homography中使用功能找到一个很好的代码示例来查找已知对象

这两种算法对缩放和旋转都是不变的。 由于它们可以处理特征,因此您还可以处理occlusion (只要有足够的关键点可见)。

图片来源:教程示例

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

原始文件


嗯,我真的认为我正在做一些事情 (这就像有史以来最有趣的问题 - 所以尽管找到了可以接受的答案,但不会继续试图找到“完美”的答案是很遗憾的).. 。

一旦你找到了标志,你的麻烦就完成了一半。 那么你只需要弄清楚标志周围的区别。 另外,我们希望尽可能少做一点。 我认为这实际上是这个简单的部分...

徽标周围有什么? 对于罐头,我们可以看到尽管有照明效果的金属,其基本颜色也不会改变。 只要我们知道标签的角度,我们就可以知道它的正上方,所以我们看看它们之间的区别:

在这里,标志的上方和下方是完全黑暗的,颜色一致。 在这方面相对容易。

在这里,上面和下面的内容很简单,但颜色仍然一致。 这是全银色的,全银色的金属看起来很罕见,以及一般的银色。 此外,它的厚度很薄,足够接近已经识别出来的红色,因此您可以在整个长度上追踪其形状,以计算可以视为罐的金属环的百分比。 真的,你只需要罐子里任何地方的一小部分就可以知道它是其中的一部分,但你仍然需要找到一个平衡点,以确保它不仅仅是一个带有金属物的空瓶子。

最后,那个棘手的问题。 但不是那么棘手,一旦我们只能通过我们可以直接看到红色包装上面(和下面)看到的东西。 它的透明度,这意味着它会显示它背后的一切。 这很好,因为它背后的东西不可能像罐子的银色圆形金属一样颜色一致。 背后可能有很多不同的东西,它会告诉我们它是一个空的(或装满了清澈的液体)瓶子,或一致的颜色,这可能意味着它充满液体或瓶子只是在纯色。 我们正在处理最接近顶部和底部的东西,而正确的颜色在正确的位置的机会相对较小。 我们知道这是一个瓶子,因为它没有获得罐子的关键视觉元素,与瓶子后面的可能元素相比,这是相对简单的。

(最后一个是我能找到的最大的一个空的大型可口可乐瓶 - 有趣的是,瓶盖和环是黄色的,这表明可能不应该依赖瓶盖的发红)

在极少数情况下,瓶子后面有类似的银色阴影,即使在塑料的抽象化后,或者瓶子以某种方式填充了相同的银色液体的阴影,我们也可以回到我们可以粗略估计的是正如我所提到的,银的形状是圆形的,并且遵循罐的形状。 但即使我在图像处理方面缺乏一定的知识,这听起来也很慢。 更好的是,为什么不通过一次检查徽标的两侧来确保这里没有相同的银色? 啊,但如果罐子后面有同样的银色阴影呢? 然后,我们确实必须更多地关注形状,再次查看罐的顶部和底部。

取决于这一切应该如何完美无缺,它可能非常缓慢,但我想我的基本概念是首先检查最简单和最接近的事情。 在着手研究其他元素的形状之前,通过已经匹配的形状周围的颜色差异(这看起来是最无关紧要的部分)。 列出它,它会:

  • 找到主要景点(红色标志背景,可能还有标志本身的方向),但如果罐子被转走,则需要专注于红色)
  • 验证形状和方向,再次通过非常鲜明的发红
  • 检查形状周围的颜色(因为它是快速和无痛的)
  • 最后,如果需要,请验证主要景点周围那些颜色的形状以获得正确的圆度。

如果你无法做到这一点,这可能意味着罐头的顶部和底部被覆盖,而人类可能用来可靠地区分罐头和瓶子的唯一可能的事情是封闭和反射的罐头,这将是一个难以处理的战斗。 然而,为了更进一步,您可以使用其他答案中提到的半透明扫描技术,按照罐头/瓶子的角度来检查更多瓶状特征。

有趣的额外噩梦可能包括一个便利的坐在瓶子后面的距离,它的金属恰好显示在标签的上方和下方,只要你沿着红色的整个长度扫描,它仍然会失败标签 - 这实际上更像是一个问题,因为您没有在可能的位置检测到罐子,而不是考虑到您实际上是在检测瓶子,包括罐子在内。 在这种情况下,杯子是半空的!

作为一个免责声明,我没有经验也没有想过在这个问题之外的图像处理,但它是如此有趣,它让我对它深思熟虑,在阅读所有其他答案后,我认为这可能是最简单最有效的方式来完成它。 就个人而言,我只是很高兴我实际上不必考虑编程!

编辑

另外,看看我在MS Paint中做过的这张图画......这绝对是可怕的,并且很不完整,但是仅仅基于形状和颜色,你可以猜测它可能会是什么。 从本质上讲,这是唯一需要打扰扫描的东西。 当你仔细观察这种非常独特的形状和颜色组合时,还有什么可能呢? 我没有画的那一点,白色背景,应该被认为是“任何不一致的东西”。 如果它有一个透明的背景,它可以覆盖几乎任何其他图像,你仍然可以看到它。


您需要一个能够从经验中有机地学习和提高分类准确性的程序。

我会建议深入学习,深入学习这将变成一个微不足道的问题。

您可以在Tensorflow上重新训练初始v3模型:

如何重新设定新类别的最初层次

在这种情况下,您将会训练卷积神经网络来将对象分类为可口可乐或不可口可乐。


我不知道OpenCV,但从逻辑上看问题,我认为你可以通过改变你正在寻找的图像即可口可乐来区分瓶子和罐头。 你应该加入到罐头的顶部,因为在可口可乐的顶部有银色衬里的情况下,并且在瓶子的情况下不会有这样的银色衬里。

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


我喜欢你的问题,不管它是否与主题无关:P

一个有趣的旁白; 我刚刚完成了我的学位课程,涵盖了机器人和计算机视觉。 我们这个学期的项目与你描述的那个非常相似。

我们不得不开发一种机器人,它使用Xbox Kinect来检测各种照明和环境条件下任何方向的可乐瓶和罐头。 我们的解决方案包括在Hue通道上结合hough circle变换使用带通滤波器。 我们能够限制环境(我们可以选择在何处以及如何定位机器人和Kinect传感器),否则我们将使用SIFT或SURF变换。

你可以在我的博客文章中阅读关于该主题的方法 :)


我喜欢这个挑战,并且想要给出一个解决问题的答案,我想。

  1. 提取徽标的特征(关键点,描述符,如SIFT,SURF)
  2. 将这些点与标志的模型图像匹配(使用匹配器如Brute Force)
  3. 估计刚体的坐标(PnP问题 - SolvePnP)
  4. 根据刚体估算帽盖位置
  5. 做背投并计算瓶盖的图像像素位置(ROI)(我假设你有相机的固有参数)
  6. 用方法检查盖子是否在那里。 如果有的话,那就是瓶子

检测瓶盖是另一个问题。 它可以是复杂的或简单的。 如果我是你,我会简单地检查ROI中的颜色直方图。

如果我错了,请提供反馈。 谢谢。


我真的很喜欢达伦库克和堆垛机对这个问题的答案 。 我正在将自己的想法投入到对这些问题的评论中,但我相信我的方法太复杂,不能离开这里。

简而言之,您已经确定了一种算法来确定可口可乐徽标存在于空间中的特定位置。 对于任意方向和任意比例因子,您现在试图确定一种适合将可口可乐与其他物体进行区分的启发式方法,包括与此标志性标识相关的瓶子广告牌广告可口可乐用具 。 你在问题陈述中没有提到很多这些额外的案例,但是我认为它们对于算法的成功至关重要。

这里的秘诀在于确定可以包含哪些视觉特征,或者通过负面空间确定其他可口可乐产品中不存在的可乐罐的特征。 为此, 当前的最佳答案勾画出一个基本的方法来选择“罐子”,当且仅当“瓶子”没有被识别,或者是瓶盖,液体或其他类似的视觉启发式的存在。

问题是这个失败。 例如,瓶子可能是空的,并且缺少盖子,导致误报。 或者,它可能是一个部分瓶子,具有额外的功能,再次导致错误检测。 不用说,这不够高雅,对我们的目的也不是有效的。

为此,罐的最正确的选择标准似乎如下:

  • 正如你在问题中勾画出的那样,物体轮廓的形状是否正确? 如果是这样,+1。
  • 如果我们假设存在自然光或人造光,我们是否会检测到瓶子上的铬轮廓,表示这是否由铝制成? 如果是这样,+1。
  • 相对于我们的光源( 光源检测的 说明性视频链接 ),我们是否确定对象的镜面反射属性是正确的? 如果是这样,+1。
  • 我们是否可以确定任何有关将其标识为罐子的对象的其他属性,包括但不限于徽标的拓扑图像歪斜,对象的方向,对象的并置(例如,在平面表面上就像一张桌子或其他罐子一样),还有一个拉式标签? 如果是这样,每个+1。

您的分类可能如下所示:

  • 对于每个候选比赛,如果检测到可口可乐徽标的存在,绘制一个灰色边框。
  • 对于+2以上的每场比赛,绘制一个红色边框。

这在视觉上向用户突出显示检测到的内容,强调可能正确地检测为不合格罐头的弱阳性。

每个属性的检测都带有非常不同的时间和空间复杂性,对于每种方法,通过http://dsp.stackexchange.com进行快速传递对于为您的目的确定最正确和最有效的算法更合理。 我的意图纯粹而简单地强调, 通过使候选检测空间的一小部分无效检测是否是可以解决问题的方法并不是解决这个问题最有效的方法,理想情况下,您应该采取适当的措施因此。

嘿,祝贺黑客新闻发布! 总的来说,这是一个相当不错的问题值得它收到的宣传。 :)


有许多颜色描述符用于识别对象,下面的文章比较了很多。 与SIFT或SURF结合使用时,它们特别强大。 SURF或SIFT本身在可口可乐罐头图像中并不是很有用,因为它们不能识别很多兴趣点,所以需要颜色信息来帮助。 我在一个项目中使用BIC(边框/内部像素分类)和SURF,它很好地识别物体。

用于Web图像检索的颜色描述符:比较研究


请看看Zdenek Kalal的“ 捕食者”追踪器 。 它需要一些培训,但它可以主动了解跟踪对象如何看待不同的方向和尺度,并实时进行!

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

如果您对我的C#实现跟踪器感兴趣,请随时询问。


这个页面上的答案实际上等于:

  • “使用SIFT”

  • “使用Kinect”

如果您对图像识别的实际计算机科学不感兴趣,而您只是想“使用”某些东西(如SIFT或Kinect),

现在无处不在的就是使用常用的图像识别系统。

从2017年开始,多年来,图像识别功能广泛而平凡

您不会坐下来尝试从头开始实现图像识别,而是坐下来开始收集和显示地图,或者您可以从头开始渲染HTML,或从头开始编写SQL数据库。

您只需使用Google的张量流(他们已经达到了构建芯片的目的,为了善良,以更快地处理张量流),Clarifai,Bluemix或其他。

AWS刚刚发布了一个用于图像识别的好方法(2018年)。

例如,要使用这些服务中的任何一个,它只需几行代码....

func isItACokeCan() {

    jds.headers = ["Accept-Language":"en"]
    let h = JustOf<HTTP> ...use your favorite http library

    let u: String =
        "https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify"
        + "?api_key= ... your API key ..."
        + "&version=2016-05-20"
        + "&classifier_ids= ... your Classifier name ..."

    h.post( u,
        files: ["x.jpeg": .data("x.jpeg", liveImageData!, "image/jpeg")]

    ) { r in
        if r.ok { DispatchQueue.main.async { self.processResult(r.json) } }
        else { DispatchQueue.main.async { self.doResults("network woe?") } }
    }
}

func processResult(_ rr: Any?){
    let json = JSON(rr!)
    print("\(json)")
}

这将从字面上为您提供地球上最好的,现有的可口可乐认可 ,目前已经实现。

截至2018年,您无法坐下来“写出比Bluemix更好的焦炭识别能力”,而不是“坐下来写出比AlphaGo更好的Go程序”。

Siri,谷歌地图,BAAS等主要图像处理系统 - 显然是谷歌文本搜索本身 - 等系统正在改变游戏规则。

自从六年前问这个问题以来,注意到令人难以置信的差异。

通过一切手段, 如果你在图像识别的实际计算机科学 ,去为它。

但是这个质量保证似乎更多地是对技术的回顾。

尽管这里的答案是“使用SIFT库” - 你真的不会那么做。 (再次 - 只是由于某种原因,您从零开始难以编程一个Web服务器或SQL数据库!)

您只需连接众所周知的无处不在的图像识别“BAAS”系统 - 这是一行代码。







opencv