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

时间:2012-04-16 04:23:16

标签: c++ algorithm image-processing opencv

过去几年我参与过的最有趣的项目之一是关于image processing的项目。我们的目标是开发一个系统,以便能够识别可口可乐&can;' (请注意,我强调“罐头”这个词,'你会在一分钟内看到原因。您可以在下面看到一个示例,其中可以使用缩放和旋转在绿色矩形中识别。

Template matching

项目的一些限制:

  • 背景可能非常嘈杂。
  • 可以可以有比例轮换甚至方向(在合理范围内)。
  • 图像可能有一定程度的模糊性(轮廓可能不完全笔直)。
  • 图片中可能有可口可乐瓶,算法应该只检测 can
  • 图像的亮度可能会有很大差异(因此您无法依赖"太多"颜色检测)。
  • 可以部分隐藏在侧面或中间,可能部分隐藏在瓶子后面。
  • 图片中根本没有可以,在这种情况下,您不得不找到任何内容并写下这样的消息。

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

Total fail

我刚刚做了这个项目,并且做了很多乐趣,我有一个不错的实现。以下是有关我的实施的一些细节:

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

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

  1. 将颜色域从RGB更改为HSV并根据" red"进行过滤色调,饱和度超过一定的阈值,以避免橙色的颜色,并过滤低值,以避免暗色调。最终结果是二进制黑白图像,其中所有白色像素将表示与该阈值匹配的像素。显然,图像中仍有很多废话,但这会减少您必须使用的维度数量。 Binarized image
  2. 使用中值滤波进行噪声滤波(取所有邻居的中间像素值并用此值替换像素)以减少噪音。
  3. 使用Canny Edge Detection Filter在2个先例步骤之后获取所有项目的轮廓。 Contour detection
  4. 算法:我为此任务选择的算法本身取自this关于特征提取的精彩书籍,并称为Generalized Hough Transform(与常规Hough变换完全不同)。它基本上说了几件事:

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

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

    GHT

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

    结果:现在,虽然这种方法适用于基本情况,但在某些方面却严重缺乏:

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

    您能否使用专门的OpenCV 功能帮助我改进特定算法,以解决上述四个特定的问题?

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

24 个答案:

答案 0 :(得分:619)

另一种方法是使用scale-invariant feature transform(SIFT)或Speeded Up Robust Features(SURF)提取要素(关键点)。

它在OpenCV 2.3.1。

中实施

您可以使用 Features2D + Homography to find a known object

中的功能找到一个很好的代码示例

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

Enter image description here

图片来源:教程示例

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

原始论文

答案 1 :(得分:357)

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

Signature scan line

在目标图像中搜索此签名是一个简单的问题,即以水平条纹扫描图像。寻找红色通道中的高频(指示从红色区域移动到白色区域),并且一旦找到,查看它是否跟随训练期间识别的频率节奏之一。找到匹配后,您将立即知道扫描线在徽标中的方向和位置(如果您在训练期间跟踪这些内容),那么从那里识别徽标的边界是微不足道的。

如果这不是一个线性有效的算法,或者差不多这样,我会感到惊讶。它显然没有解决你的罐装歧视,但至少你会有你的标志。

(更新:对于瓶子识别,我会寻找与徽标相邻的焦炭(棕色液体) - 也就是说,里面瓶子。或者,如果是空瓶子,我会寻找一个,它总是与徽标具有相同的基本形状,大小和距离,通常都是白色或红色。搜索一个纯色的椭圆形状,其中一个帽应该相对于徽标。当然不是万无一失,但你的目标应该是快速找到 easy

(我的图像处理时间已经过去了几年,所以我保持这个建议的高级和概念性。我认为这可能会略微接近人眼的操作方式 - 或者至少我的大脑是如何操作的!)< / p>

答案 2 :(得分:148)

有趣的问题:当我瞥了一眼你的瓶子图像时,我觉得它也是可以的。但是,作为一个人,我所做的就是告诉我们不同之处在于我注意到它也是一个瓶子......

那么,为了区分罐头和瓶子,如何简单地先扫描瓶子?如果你找到一个,在寻找罐头之前屏蔽标签。

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

答案 3 :(得分:117)

即使人类在第二张图片中区分瓶子和罐头也不困难(假设瓶子的透明区域是隐藏的)?

它们几乎是相同的,除了一个非常小的区域(也就是说,罐子顶部的宽度有点小,而瓶子的包装纸在整个宽度上是相同的宽度,但是稍微改变了吗?)

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

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

特别注意这一点,看看它们检测玻璃的准确程度如何:

查看他们的实施结果:

Enter image description here

他们说这是论文"A Geodesic Active Contour Framework for Finding Glass" by K. McHenry and J. Ponce, CVPR 2006的实施。

在您的情况下可能会有所帮助,但如果瓶子已经装满,问题就会再次出现。

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

Enter image description here

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

无论如何,这个解决方案也存在与其他解决方案不同的问题。

  1. 只有在您的瓶子是空的时候它才有效。在这种情况下,您将不得不搜索两种黑色之间的红色区域(如果可口可乐液体是黑色的)。
  2. 如果涵盖透明部分,则会出现另一个问题。
  3. 但无论如何,如果图片中没有上述问题,这似乎是更好的方法。

答案 4 :(得分:47)

我真的很喜欢Darren Cook'sstacker's answers这个问题。我正在把我的想法投入到评论中,但我相信我的方法太过于回答,不能离开这里。

简而言之,您已经确定了一种算法,以确定在太空中的特定位置存在可口可乐徽标。您现在正在尝试确定任意方向和任意缩放因子,适用于区分可口可乐与其他对象的启发式,包括: bottle 广告可口可乐用具。您没有在问题陈述中调出许多其他案例,但我认为它们对您算法的成功至关重要。

这里的秘诀在于确定可以包含哪些视觉特征,或者通过负空间确定哪些特征存在于罐头不存在的其他可乐产品中。为此,the current top answer草拟了一种选择“罐头”的基本方法,当且仅当“瓶子”未被识别时,无论是通过瓶盖,液体还是其他类似的视觉启发法。

问题是这会破裂。例如,瓶子可能是空的并且没有盖子,导致假阳性。或者,它可能是部分瓶,其中包含额外的功能损坏,再次导致错误检测。毋庸置疑,这不是优雅的,也不是对我们的目的有效。

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

  • 对象轮廓的形状(you sketched out in your question)是否正确?如果是,请+1。
  • 如果我们假设存在天然或人造光,我们是否检测到瓶子的铬轮廓,表明这是否是由铝制成的?如果是,请+1。
  • 相对于我们的光源(specular properties上的illustrative video link),我们是否确定对象的light source detection是正确的?如果是,请+1。
  • 我们可以确定关于对象的任何其他属性,将其标识为罐头,包括但不限于徽标的拓扑图像倾斜,对象的方向,对象的并置(例如,像桌子一样的平面或在其他罐子的背景下,还有拉片的存在?如果是,则为每个+1。

您的分类可能如下所示:

  • 对于每个候选比赛,如果检测到可口可乐标志,请画一个灰色边框。
  • 对于超过+2的每场比赛,绘制一个红色边框。

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

对每个属性的检测具有非常不同的时间和空间复杂度,并且对于每种方法,快速通过http://dsp.stackexchange.com对于确定用于您的目的的最正确和最有效的算法来说是合理的。我的目的是纯粹而简单地强调通过使候选检测空间的一小部分无效来检测某些东西是否是罐头并不是解决这个问题的最有效或最有效的方法,理想情况下,你应该采取相应的行动。

嘿,恭喜the Hacker News posting!总的来说,这是一个非常了不起的问题,值得宣传它。 :)

答案 5 :(得分:39)

看着形状

将罐子放在罐子/瓶子的红色部分的形状上。注意罐子的顶部是如何逐渐变细,而瓶子标签是直的。您可以通过比较红色部分的长度来区分这两者。

关注精彩内容

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

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

答案 6 :(得分:35)

请看看Zdenek Kalal的Predator tracker。它需要一些培训,但它可以主动了解被跟踪物体在不同方向和比例下的表现,并实时进行!

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

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

答案 7 :(得分:30)

如果你不仅限于一个不在你的约束条件下的相机,也许你可以转向使用像Xbox Kinect这样的范围传感器。使用此功能,您可以执行基于深度和颜色的图像匹配分割。这允许更快地分离图像中的对象。然后,您可以使用ICP匹配或类似技术来匹配罐的形状,而不仅仅是它的轮廓或颜色,并且假设它是圆柱形的,如果您对目标进行了先前的3D扫描,则这可能是任何方向的有效选项。这些技术通常非常快,特别是在用于解决速度问题的特定目的时。

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

答案 8 :(得分:21)

我会检测到红色矩形:RGB - &gt; HSV,过滤红色 - &gt;二进制图像,close(扩张然后侵蚀,在matlab中称为imclose

然后查看从最大到最小的矩形。在已知位置/比例中具有较小矩形的矩形都可以被移除(假设瓶子比例是恒定的,较小的矩形将是瓶盖)。

这将为您留下红色矩形,然后您需要以某种方式检测徽标,以判断它们是红色矩形还是可乐。像OCR一样,但有一个已知的标志?

答案 9 :(得分:20)

这可能是一个非常幼稚的想法(或者可能根本不起作用),但所有可乐罐的尺寸都是固定的。因此,如果相同的图像同时包含罐头和瓶子,那么您可以通过尺寸考虑将它们分开(瓶子会更大)。现在由于缺少深度(即3D映射到2D映射),瓶子可能看起来缩小并且没有尺寸差异。您可以使用stereo-imaging恢复一些深度信息,然后恢复原始大小。

答案 10 :(得分:18)

嗯,我实际上认为我已经某事(这就像有史以来最有趣的问题一样 - 所以如果不继续尝试找到&#,那将是一种耻辱34;完美&#34;回答,即使找到了可接受的答案)......

找到徽标后,您的麻烦就完成了一半。然后,您只需要弄清楚徽标的 之间的区别。此外,我们希望尽可能少地做。我认为这实际上就是这个简单的部分......

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

在这里,徽标上方和下方的内容是完全黑暗的,颜色一致。在这方面比较容易。

在这里,上面和下面的内容是光线,但颜色仍然一致。它全银,全银金属实际上看起来非常罕见,而且一般都是银色。此外,它处于一个薄的滑动位置并且与已经识别的红色足够接近,因此您可以在其整个长度上追踪其形状,以计算可以被视为罐的金属环的百分比。实际上,你只需要沿着罐头的任何一小部分来说明它是它的一部分,但你仍然需要找到一个平衡点,以确保它不仅仅是一个空瓶子,后面有金属。

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

(最后一个是我能找到的最好的一个空的大可口可乐瓶 - 有趣的是帽子和戒指是黄色的,表明帽子的红色可能不应该依赖)< /强>

在罕见的情况下,在瓶子后面有类似的银色阴影,即使在取出塑料后,或者瓶子以某种方式填充了相同的银色液体,我们可以回到我们可以粗略估计的因为银的形状 - 正如我所提到的,是圆形的并且遵循罐的形状。但即使我在图像处理方面缺乏某些知识,这听起来也很慢。更好的是,为什么不一次检查一下徽标的以确保那里没有相同的银色?啊,但如果在罐子后面有相同的银色,怎么办?然后,我们确实需要更多地关注形状,再次看到罐头的顶部和底部。

取决于所有这些都需要完美无瑕,它可能会非常缓慢,但我想我的基本概念是首先检查最简单和最接近的东西。在努力计算出其他元素的形状之前,先考虑已经匹配的形状(这似乎是最无聊的部分)周围的颜色差异。要列出它,它会:

  • 找到主要景点(红色徽标背景,可能还有徽标本身用于定位,但如果罐头被拒之外壳,则需要专注于红色)
  • 通过非常鲜明的红色验证形状和方向
  • 检查形状周围的颜色(因为它快速且无痛)
  • 最后,如果需要,请验证主要景点周围的那些颜色的形状以获得正确的圆度。

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

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


作为一个免责声明,我没有经验,也没有考虑过这个问题以外的图像处理,但它非常有趣,让我深入思考它,在阅读完所有其他答案后,我认为这个可能是最简单的最有效的完成方式。就我个人而言,我很高兴我

修改

bad drawing of a can in MS paint 另外,看看我在MS Paint中所做的这幅画......它非常糟糕且非常不完整,但仅仅基于形状和颜色,你可以猜出它可能会是什么。从本质上讲,这些是人们需要进行扫描的唯一内容。当你看到那种非常独特的形状和颜色组合如此接近时,还有什么可能呢?我没有画的那个,白色的背景,应该被认为是#34;任何不一致的东西&#34;。如果它有一个透明的背景,它几乎可以覆盖任何其他图像,你仍然可以看到它。

答案 11 :(得分:15)

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

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

答案 12 :(得分:13)

我喜欢这个挑战,想要给出答案,我认为这解决了这个问题。

  1. 提取徽标
  2. 的要素(关键点,描述符,如SIFT,SURF)
  3. 将点与徽标的模型图像匹配(使用匹配器,如Brute Force)
  4. 估计刚体的坐标(PnP问题 - SolvePnP)
  5. 根据刚体评估帽位置
  6. 做反投影并计算瓶盖的图像像素位置(ROI)(我假设你有相机的内在参数)
  7. 检查方法是否存在。如果有,那就是瓶子
  8. 检测上限是另一个问题。它可以是复杂的也可以是简单的。如果我是你,我只需检查ROI中的颜色直方图,以便做出简单的决定。

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

答案 13 :(得分:10)

有许多用于识别物体的颜色描述符,下面的论文比较了很多。当与SIFT或SURF结合使用时,它们特别强大。单独的SURF或SIFT在可口可乐图像中不是很有用,因为它们不识别很多兴趣点,需要颜色信息来帮助。我在项目中使用带有SURF的BIC(边界/内部像素分类),它可以很好地识别物体。

Color descriptors for Web image retrieval: a comparative study

答案 14 :(得分:10)

回答这个问题已经晚了几年。随着CNN在过去5年中将技术发展到极限,我现在不会使用OpenCV来完成这项任务! (我知道你在问题中特别想要OpenCv功能)我认为像Faster-RCNN,YOLO,SSD等对象检测算法会比OpenCV功能带来更大的利益。如果我现在要解决这个问题(6年后!!)我绝对会使用 Faster-RCNN

答案 15 :(得分:10)

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

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

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

How to Retrain Inception's Final Layer for New Categories

在这种情况下,您将训练一个卷积神经网络,将一个物体归类为可口可乐。或者不可以。

答案 16 :(得分:9)

我喜欢你的问题,无论是否偏离主题:P

有趣的一边;我刚刚完成了我的学位课程,其中包括机器人和计算机视觉。我们这个学期的项目与你描述的项目非常相似。

我们必须开发一种机器人,使用Xbox Kinect在各种照明和环境条件下检测任何方向的焦炭瓶和罐。我们的解决方案涉及在Hue通道上结合霍夫圆变换使用带通滤波器。我们能够稍微限制环境(我们可以选择在何处以及如何定位机器人和Kinect传感器),否则我们将使用SIFT或SURF变换。

您可以在my blog post on the topic上了解我们的方法:)

答案 17 :(得分:8)

深度学习

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

除非您收集非常大的数据集,否则请执行针对小型数据集使用深度学习功能的技巧。理想情况下使用支持向量机(SVM)与深度神经网络的组合。

一旦您将图像提供给先前训练的深度学习模型(例如GoogleNet),而不是使用神经网络的决策(最终)层来进行分类,请使用之前的图层&#39;数据作为训练分类器的功能。

OpenCV和Google Net: 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

答案 18 :(得分:6)

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

仅提取罐头可以很有用,并且可以与透明物体的检测结合使用。

答案 19 :(得分:3)

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

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

答案 20 :(得分:0)

如果您对它是实时感兴趣,那么您需要的是添加预处理过滤器以确定使用重载物品扫描的内容。一个快速,非常实时的预处理过滤器,可以让你扫描更可能是可口可乐的东西,而不是在转移到更多的东西之前是这样的:搜索图像的最大补丁与可口可乐的sqrt(pow(red,2) + pow(blue,2) + pow(green,2))相比具有一定耐受性的颜色。从非常严格的颜色容差开始,逐步实现更宽松的颜色容差。然后,当您的机器人在规定的时间内用完以处理当前帧时,它会将当前找到的瓶子用于您的目的。请注意,您必须调整sqrt(pow(red,2) + pow(blue,2) + pow(green,2))中的RGB颜色以使它们恰到好处。

另外,这看起来真的很笨,但你确定在编译C代码时打开-oFast编译器优化吗?

答案 21 :(得分:0)

我要寻找的第一件事就是颜色 - 就像RED,在图像中进行红眼检测时 - 有一定的颜色范围需要检测,考虑到周围区域的一些特征,例如与其他区域的距离如果在图像中确实可见,请注意。

1:第一个特征是颜色,红色占主导地位。在检测到可口可乐红之后,有几个感兴趣的项目 1A:这个红色区域有多大(是否有足够的数量来确定真实的能否--10个像素可能还不够), 1B:它是否包含标签的颜色 - &#34;可口可乐&#34;或挥手。 1B1:是否足以考虑它是一个标签的概率很高。

第1项是一种捷径 - 如果图像中存在鼻涕,则进行预处理 - 继续进行。

因此,如果是这种情况,我可以利用我的图像片段并开始更多地缩小相关区域 - 基本上看看周围的区域/边缘......

2:给定上面的图像区域ID&1; - 验证所讨论项目的周围点[边缘]。 - 答:有没有看起来可以顶部或底部 - 银? B:一个瓶子看起来可能是透明的,但玻璃桌也是如此 - 玻璃桌/架子或透明区域也是如此 - 如果是这样的话,可能会出现多种可能性。 A MIGHT有一个红色的帽子,它可能没有,但它应该有瓶顶/螺纹螺丝的形状,或帽子。 C:即使A和B失败,它仍然可以是一个部分.. 当它是部分的时,这会更复杂,因为部分瓶子/部分可能看起来相同,所以更多的处理测量红色区域的边缘到边缘。小瓶子的大小可能相似..

3:经过上面的分析,我会看到刻字和波浪标志 - 因为我可以找到单词中的一些字母,因为你可能没有所有的文字,因为没有所有的能量,波将在某些点对齐文本(距离明智),这样我就可以搜索该概率,并知道在距离x的波点处应该存在哪些字母。

答案 22 :(得分:0)

可能晚了太多年了,但仍然是一个尝试的理论。

红色徽标区域的边界矩形与瓶子/罐的整体尺寸的比率是不同的。在罐子的情况下,应该是1:1,而瓶子的不同(有或没有盖子)。 这应该可以很容易地区分这两者。

更新: 由于它们各自的尺寸差异,徽标区域的水平曲率在Can和Bottle之间将是不同的。如果您的机器人需要拿起罐子/瓶子,并且您相应地决定了握把,这可能特别有用。

答案 23 :(得分:0)

这是我从事的旧项目。 MAP图像非常容易与javascript一起使用。我为您提供对象,您阅读并知道如何使用它。我们不需要JQuery和其他系统来使用MAP图像。

    //Copyright Cherif yahiaoui, by ELEBAN.FR

//variables de flottement.
var myInstOne = null;
var globalize = null;

var eleban_preload_images = function (name, imgs, url){
try{
    var oThis = this;
    this.images = new Array();
    this.imageshover = new Array();
    this.imagesNames = new Array(imgs.split(";"));


        for(var i=0; i < this.imagesNames[0].length; i++){
            this.images[i] = new Image();
            this.imageshover[i] = new Image();
        }

    this.url = url;

    this.GetAbsoluteurl = function () {

    var img = new Image(); img.src = url;
    url = img.src; img = null; 
        this.url = url; 

    };

    this.Preload = function () {

        for(var i=0; i < this.imagesNames[0].length; i++){
            this.images[i].src = this.url+("btn-"+this.imagesNames[0][i]+".png");
            this.imageshover[i].src = this.url+("btn-"+this.imagesNames[0][i]+"-hover.png");
        }

    };
    this.GetAbsoluteurl();
    this.Preload();
}
finally {return;}
}

var g_preloaderhover = new eleban_preload_images("loaderhover","menu;malette;reservation;cabine;facebook;map;amis","./images/");


//variable arret flottement
var g_stopflo = false;

var myObjfloater = function(name, idname, itop, differ ) {
var oThis = this; // création d'une référence vers l'objet courant
this.name = name;
this.id =idname;
this.xstep= 0.3;
this.itime = 30;
this.obj = null;
this.y = itop;
this.yadd = 0;
this.up = true;
this.pause = false;
this.differ = differ;
this.coordsimage = null;
this.objimg = null;
this.initimages = false;
this.compteur = 0;
this.over = false;
this.timeoutstop = null;
try{
this.initimage = function(){
var img = this.obj.getElementsByTagName('img')[0];
this.coordsimage = new Array(img.width, img.height);
this.objimg = img;
this.initimages = true;
};


this.myMethod = function() {
if(!g_stopflo){
    if(this.differ != 0){ 
this.differ=this.differ-0.1; 
}else{

if(this.obj){
if(this.over == false){
    this.yadd=this.yadd+0.1; this.itime = this.itime + 10;
this.obj.style.visibility = "hidden";
this.y = ((this.up)? this.y - this.yadd : this.y + this.yadd);
this.obj.style.marginTop = this.y +"%" ;
this.obj.style.visibility = "visible";

if (this.yadd > this.xstep){ 
    this.up = (this.up)? false : true;
    this.yadd = -0.1; this.itime=180;
}
}
}else{
    if (document){
        if(document.getElementById) {
         this.obj = document.getElementById(this.id); 
        //this.y = this.obj.offsetTop;
        }else{
        if(document.getElementByTagName) { this.obj = document.getElementByTagName(this.id); this.y = this.obj.offsetTop;}
        }

    }
}
}
this.timeoutstop=setTimeout(function() { oThis.myMethod(); }, this.itime);
}    
};

this.callDelayed = function() {
    // utilisation de la référence vers l'objet
if(!g_stopflo){
    this.timeoutstop=setTimeout(function() { oThis.myMethod(); }, this.itime);
}
};
}
finally {return;}
};

// special creation des zones AREA
function eleban_createallarea(){
try{
var measur = new Array("w", "h");
measur["w"] = new Array(330,570,185,300,115,390,225);
measur["h"] = new Array(460,570,295,450,100,190,115);
var ititle = new Array("Voir les menus  et nos suggestions","Repas &agrave; emporter","R&eacute;servation d&rsquo;une table","Nous contacter","Nous rejoindre sur FaceBook","Calculer votre trajet","liste des amis");
var ihref = new Array("menus.html","emporter.html","reservation.html","contact.html","likebox.html","google.html","amis.html");
var b_map = new Array(0,1,2,3,4,5,6);
b_map[0] = "71,32,240,32,249,43,289,352,280,366,102,385,90,371,51,38";
b_map[1] = "66,52,95,14,129,56,115,91,100,93,112,273,128,284,122,366,176,343,193,296,191,194,147,189,145,166,201,111,199,84,545,105,532,354,509,388,412,478,32,401,77,383,87,375,82,286,95,269,94,221,24,195,11,165,9,120,89,123,89,94,78,92,77,92,77,93,75,93,77,93,76,93,79,92";
b_map[2] = "19,25,169,38,173,112,161,113,105,103,90,125,91,262,121,269,124,281,96,293,62,289,49,281,56,268,83,264,84,121,71,98,16,90";
b_map[3] = "60,0,216,1,226,20,225,403,168,421,42,410,45,10";
b_map[4] = "31,7,72,10,82,18,88,45,88,71,76,81,29,80,17,68,16,18";
b_map[5] = "91,40,141,38,178,27,184,4,211,5,223,24,240,23,386,135,229,121,103,180,6,156,49,94";
b_map[6] = "6,32,69,18,79,6,118,7,141,2,149,10,211,17,202,28,209,30,189,62,195,70,178,74,180,90,164,90,154,107,68,101,34,104,34,98,18,97,28,84,15,84,30,65";

if (document.getElementById){
for (var i=0; i<b_map.length;i++){
var obj = document.getElementById("pc_menu"+i);
    if(obj){
    var ct = '<img class=\"pc_menu\" src=\"'+g_preloaderhover.images[i].src+'\" alt=\"\" width=\"'+measur["w"][i]+'\" height=\"'+measur["h"][i]+'\" usemap=\"#MAP_INDEX'+i+'\" \/>';
    ct+='<map name=\"MAP_INDEX'+i+'\">';
    ct+='<area shape=\"poly\" coords=\"'+b_map[i]+'\" title=\"'+ititle[i]+'\" href=\"'+ihref[i]+'\" \/>';
    ct+='<\/map>';
    obj.innerHTML = ct;
    }
}
}
}
finally {return;}
}

//preload, creation et gestion de tous les evenements


var image_resizer = function(g_layer){


    b_org_elm = new Array("w",  "h");
    b_org_elm["w"] = new Array(330,570,185,300,115,390,225);
    b_org_elm["h"] = new Array(460,570,295,450,100,190,115);

    b_map = new Array(0,1,2,3,4,5,6);
    b_map[0] = new Array(71,32,240,32,249,43,289,352,280,366,102,385,90,371,51,38);
    b_map[1] = new Array(66,52,95,14,129,56,115,91,100,93,112,273,128,284,122,366,176,343,193,296,191,194,147,189,145,166,201,111,199,84,545,105,532,354,509,388,412,478,32,401,77,383,87,375,82,286,95,269,94,221,24,195,11,165,9,120,89,123,89,94,78,92,77,92,77,93,75,93,77,93,76,93,79,92);
    b_map[2] = new Array(19,25,169,38,173,112,161,113,105,103,90,125,91,262,121,269,124,281,96,293,62,289,49,281,56,268,83,264,84,121,71,98,16,90);
    b_map[3] = new Array(60,0,216,1,226,20,225,403,168,421,42,410,45,10);
    b_map[4] = new Array(31,6,70,10,78,18,84,23,88,44,88,70,78,80,75,81,33,82,23,76,18,69,16,22,21,13);
    b_map[5] = new Array(91,40,141,38,178,27,184,4,211,5,223,24,240,23,386,135,229,121,103,180,6,156,49,94);
    b_map[6] = new Array(6,32,69,18,79,6,118,7,141,2,149,10,211,17,202,28,209,30,189,62,195,70,178,74,180,90,164,90,154,107,68,101,34,104,34,98,18,97,28,84,15,84,30,65);


    b_layer = g_layer;

//gere mouseover
    this.mouseover = function(e){
        if (!e) var e = window.event;
        var tg = (window.event) ? e.srcElement : e.target
            if (tg.nodeName){
                if(tg.nodeName == "AREA"){
                var divpar = (tg.parentNode)? tg.parentNode.parentNode : tg.parentElement.parentElement;
                    if (divpar){
                        if(divpar.nodeName == "DIV"){
                            var iiobjimg = divpar.getElementsByTagName('img');
                                if (iiobjimg){
                                    ii = parseInt(divpar.id.substring(divpar.id.length-1,divpar.id.length));
                                    iiobjimg[0].src = g_preloaderhover.imageshover[ii].src;
                                }
                        }
                    }
                }
            }
    };

//gere mouseout
    this.mouseout = function(e){
        if (!e) var e = window.event;
        tg = (window.event) ? e.srcElement : e.target
            if (tg.nodeName){
                if(tg.nodeName == "AREA"){
                divpar = (tg.parentNode)? tg.parentNode.parentNode : tg.parentElement.parentElement;
                    if (divpar){
                        if(divpar.nodeName == "DIV"){
                            var iiobjimg = divpar.getElementsByTagName('img');
                                if (iiobjimg){
                                    ii = parseInt(divpar.id.substring(divpar.id.length-1,divpar.id.length));
                                    iiobjimg[0].src = g_preloaderhover.images[ii].src;
                                }
                        }
                    }
                }
            }
    };

//ajout evenements entree sortie à la page web lors du chargement de la page
    this.init = function () {

        for(var i=0; i<b_org_elm["w"].length;i++){
            w = document.getElementById("pc_menu"+i).offsetWidth;
            h = document.getElementById("pc_menu"+i).offsetHeight;

            xa = w/parseFloat(b_org_elm["w"][i]);
            ya = h/parseFloat(b_org_elm["h"][i]);

            area = document.getElementById("pc_menu"+i).getElementsByTagName('area')[0];

            b_map2 = area.coords.split(",");
            yswitch = true;
                for(m=0; m<b_map2.length;m++){
                b_map2[m] = Math.round(parseFloat(b_map[i][m]) * ((yswitch)? xa: ya));
                yswitch = (yswitch)? false :  true;
                }
            area.coords = b_map2.join(',');
        }
    }; 


    this.resize = function () {
    clearTimeout(myInstOne.timeoutstop);
    g_stopflo=true;

    globalize.init();
    g_stopflo=false;
    myInstOne.obj = null;
    myInstOne.callDelayed();
    };


    nar = document.getElementsByTagName('area').length;

        for(var i=0; i<nar;i++){
            var elem = document.getElementsByTagName('area')[i];
            if (elem.addEventListener){
                    elem.addEventListener("onmouseover",this.mouseover,true);
                elem.addEventListener("onmouseout",this.mouseout,true);
            }else if (elem.attachEvent) {
                    elem.attachEvent("onmouseover", this.mouseover);
                    elem.attachEvent("onmouseout", this.mouseout);
            }else{
                    elem["onmouseover"] = this.mouseover;
                    elem["onmouseout"] = this.mouseout;
            }
        }

            window.onresize = this.resize;
        window.onmouseover = this.mouseover;
        window.onmouseout = this.mouseout;
}


//permet de temporiser et éviter les erreurs de chargement des objets
function temporise_Init(Lastdiv){
if(document.getElementById){
    if(document.getElementById(Lastdiv)){

    eleban_createallarea();

    myInstOne = new myObjfloater('b_menumap11', 'pc_menu1', 1, 0);

    globalize = new image_resizer(document.getElementById('pc_redim'));
    globalize.init();
        globalize.resize();



    }else{
    setTimeout(temporise_Init(Lastdiv), 30);
    }
}
}


window.onload = function () {
temporise_Init("pc_bandeau");
}