【问题标题】:Recognizing similar shapes at random scale and translation以随机比例识别相似形状并进行平移
【发布时间】:2013-02-02 00:01:18
【问题描述】:

在图形屏幕上寻找东西,我目前不知道如何在图像中找到给定的形状。图像中的形状可能有不同的比例,当然会在某个未知的 x,y 偏移处。

除了不同尺度导致的像素伪影之外,两张图像中也有一点点噪点,所以我需要稍微宽容的搜索。

这是我要找的图片。

它应该显示在我的(双)屏幕缓冲区的屏幕转储中,大小约为 3300 x 1200 像素。我当然希望在浏览器窗口中找到它,但不需要这些信息。

这个练习的目的(到目前为止)是想出一个结果:

  • 是的,在我的屏幕上(或没有)找到了木制框架(颜色近似,形状可能略有截断);和
  • 游戏的客户区(框架内的黑色区域)占据了从(x1,y1)(x2,y2)的矩形。

我希望对缩放和抖动可能引入的噪声具有鲁棒性。另一方面,我可以排除一些常见的 CV 挑战,例如旋转或非刚性。这种框架形状对于人脑来说非常容易辨别,对于专用软件来说有多难?这是一个 Adob​​e Flash 应用程序,直到最近我还认为从游戏 GUI 中感知图像应该很容易。

我正在寻找一种算法,该算法能够找到针和干草堆之间发生最大可能重叠的 x、y 平移,并且如果可能的话,无需遍历一系列可能的比例因子。理想情况下,该算法可以以一种独立于比例的方式抽象出图像的“形状”。

我已经阅读了一些关于傅立叶变换的有趣内容以完成类似的操作:给定相同比例的目标图像,FFT 和一些矩阵数学在更大的图像中产生了与搜索模式相对应的点。但我没有将其付诸实践的理论背景,也不知道这种方法是否能优雅地处理规模问题。帮助将不胜感激!

技术:我正在使用 Clojure/Java 编程,但可以采用其他语言的算法。我认为我应该能够与遵循 C 调用约定的库进行交互,但我更喜欢纯 Java 解决方案。


您也许能够理解我为什么回避展示实际图像。这只是一个愚蠢的游戏,但事实证明,它的屏幕阅读任务比我想象的更具挑战性。

显然,我可以在屏幕缓冲区中彻底搜索构成图像的像素(不包括黑色),甚至可以在一分钟内完成搜索。但我的目标是找到使用一种技术来匹配形状的木制框架,而不管缩放和抖动可能产生的差异。

事实上,抖动是我在这个项目中遇到的诸多挫折之一。我一直在努力通过边缘提取来提取一些有用的向量,但是边缘非常难以捉摸,因为任何给定区域的像素具有广泛不一致的颜色 - 所以很难从局部抖动伪影中分辨出真正的边缘。我不知道这么简单的游戏会产生软件难以感知的图形。

在开始寻找特征之前,是否应该先对像素进行局部平均?我应该通过丢弃像素颜色值的最低有效位来减少颜色深度吗?

正在尝试纯 Java 解决方案(实际上是在 Clojure/Java 混合中编程),所以我对 opencv(它使用 C 代码安装 .DLL 或 .so)并不感兴趣。请不要担心我的语言选择,学习体验对我来说比表演更有趣。

【问题讨论】:

  • 不清楚您提到的频域使用类型。考虑到这个问题,我最好的猜测是用傅里叶描述符进行比较。这些可以很容易地使旋转、平移和比例不变,从而有助于解决您的问题。您首先提取二进制图像中连接分量​​的每个轮廓,然后对每个进行采样并确定傅立叶描述符。 “针”图像也是如此。然后,您可以尝试使用这些描述符匹配形状。但是,此任务还有许多其他方法,具体取决于其他隐藏(被遗忘)的要求。
  • 如果您不熟悉这些算法,也可以查看 SIFT 和 SURF; Gary Bradski 的《Learning OpenCV》一书可以提供一些指导。几个商业视觉库 ($$) 实现了简化设置的“稳健形状匹配”。 en.wikipedia.org/wiki/SURF
  • Carl,您能否发布一些原始示例图像(和/或示例图像存档的链接)?您是在寻找一个强大的解决方案、一个简单的解决方案、一个有趣/复杂的解决方案来测试,还是“最佳”解决方案(针对某些问题领域/市场)?有统计描述符、傅里叶描述符等,但也有一些技术可能更容易让你理解,并且可以很好地满足你的目的。 (我还重新标记了您的问题以添加“opencv”和“图像处理”,以便获得更多关注。)
  • @Rethunk,感谢您的关注和投入!我已经编辑了我的问题,以使任务的目的和参数更加清晰。希望这会有所帮助!
  • @CarlSmotricz:对于该领域的人来说,提出一个基于重量级库的超通用解决方案是微不足道的,但是找到一个不过度使用的简单解决方案是一个有趣的问题 - 请参阅我的回答以获取建议.

标签: opencv image-processing computer-vision fft image-recognition


【解决方案1】:

很好。我曾经通过捕获屏幕在 Flash 游戏上实现了一些作弊 :)。如果您需要找到您在图像中给出的确切边框,您可以创建一个颜色过滤器,从而删除所有其余部分,最终得到一个可以用于进一步处理的二进制图像(手头的任务是找到一个具有一定边框比例的匹配矩形。此外,您可以实现四个内核,以找到几个不同比例的角。

如果您有图像流,并且知道有运动,您还可以通过使用背景建模解决方案监控帧之间的差异以捕捉屏幕中的动作部分。结合这些,我猜你会走得很远,而无需诉诸更奇特的方法,比如多尺度分析之类的东西。

它的性能有问题吗?我的作弊使用了大约 20 fps,因为它需要足够快地点击一个球。

【讨论】:

  • 颜色过滤对我没有多大作用,因为该图像中的颜色非常“混合”。如果颜色非常均匀,我的问题就会少一些。 的作用 是直接的逐像素匹配,但我当然希望有一个比这更“智能”的解决方案。
【解决方案2】:

作为一名计算机视觉专家,我通常会指出特征提取和匹配(SIFT、SURF、LBP 等),但这几乎可以肯定是矫枉过正,因为这些方法中的大多数提供了更多的不变性(=tolerances反对转换)比你实际需要的(例如反对旋转,亮度变化,...)。此外,使用功能将涉及 OpenCV 或 大量 编程。

所以这是我的一个简单解决方案的建议 - 你判断它是否通过智能阈值:

看起来您要查找的图像具有一些非常独特的结构(字母、徽标等)。我建议您对每一种可能的翻译和许多不同的比例进行像素到像素匹配(我假设比例范围是有限的) - 但仅适用于一个小的独特补丁您正在寻找的图像(例如,黄色文本的正方形部分)。这比匹配整个事情要快得多。如果您想要一个花哨的名称:在图像处理中,它被称为相关性模板匹配。 “模板”就是您要寻找的东西。

一旦您为您的小独特补丁找到了几个候选位置,您就可以验证通过测试整个图像或更有效地测试几个其他 图像的独特补丁(当然,使用您找到的平移/比例)。这使您的搜索能够抵御原始补丁的意外匹配,而不会窃取太多性能。

关于抖动容限,我会对两个图像(您正在寻找的模板和作为您的搜索空间的图像)进行简单的预过滤。根据抖动的属性,您可以开始尝试简单的框模糊,如果不起作用,可能会继续使用小内核 (3 x 3) 的中值滤波器。这不会让您在模板和搜索图像之间获得 100% 的同一性,但您可以比较可靠的数字分数。

根据 cmets 编辑

我了解 (1) 您想要一些更强大、更“类似 CV”的解决方案,并且 (2) 您对通过简单地扫描一大堆数据来实现规模不变性持怀疑态度不同的尺度。

关于 (1),如上所述,规范方法是使用特征描述符。特征描述符不描述完整的图像(或形状),而是以一种对各种变换不变的方式描述图像的一小部分。看看SIFTSURF,以及VLFeat,它有很好的SIFT 实现,也实现了MSERHOG(并且比OpenCV 小得多)。 SURF 比 SIFT 更容易实现,两者都拥有大量专利。两者都有一个“直立”版本,没有旋转不变性。这应该会增加您案例的稳健性。

您在评论中描述的策略更倾向于形状描述符而不是图像特征描述符。 确保您了解它们之间的区别! 2D 形状描述符针对通常由轮廓或二进制掩码描述的形状。图像特征描述符(在上述意义上使用)针对具有强度值的图像,通常是照片。一个有趣的形状描述符是shape context许多 其他人总结了here。我不认为你的问题最好通过形状描述符来解决,但也许我误解了一些东西。我会非常小心图像边缘上的形状描述符,因为边缘是一阶导数,可以通过抖动噪声强烈改变。

关于 (2):我想说服您,对于不了解计算机视觉的人来说,通过一堆不同的尺度进行扫描不仅仅是一个愚蠢的 hack!实际上,它在视觉上做了很多,我们只是给它起了一个花哨的名字来误导外行 - scale space搜索。这有点过于简单化了,但实际上只是一点点。实践中使用的大多数图像特征描述符使用尺度空间来实现尺度不变性,尺度空间是不断缩小(和低通滤波)图像的堆栈。他们添加的唯一技巧是在尺度空间中寻找极值并仅在这些极值处计算描述符。但是,仍然会计算并遍历完整的尺度空间以找到那些极值。请查看original SIFT paper 以获得对此的详细解释。

【讨论】:

  • 感谢您的理解,以及一个非常明智的回答!由于我可能只在一台计算机上运行,​​因此精确的像素匹配将是快速而实用的。这个愚蠢的子问题实际上让我远离了我希望接下来攻击的更有趣的东西!我想“做”简历,因为我想避免觉得我的应用程序对图像中不可察觉的变化完全脆弱,并且因为我希望我所学到的东西对我以后有好处。目前我正在扫描 Szeliski 博士的书 (szeliski.org/Book) 以获取提示。接下来会出现方框模糊。
  • 要更直接地回答您的建议:直接像素匹配“感觉”对我来说太脆弱了,我很害怕提供比例猜测或任意缩放测试量表的精细进展。我希望有一种方法可以(或多或少)独立于尺度的方式来表示两个图像中的形状。我的最新方法是将检测到的边缘转换为一组向量,我将以极坐标(角度、幅度)形式存储和比较;然后我可以检查屏幕上的矢量集是否包含我的搜索图像中的子集。
  • 我根据您的 cmets 编辑了我的帖子。很长,抱歉,但我想解决您的问题。
  • 我将把复选标记推迟到周末,以防有其他 CV 大师突然出现,为我提供我一直希望的“神奇”简单但功能强大且灵活的解决方案- 提前关闭我的赏金将是一种耻辱。但是,鉴于您非常乐于助人的 cmets,您几乎肯定会“获胜”。再次感谢!
【解决方案3】:

我正在报告我自己的问题的答案,让人们知道我最终去了哪里。


在我寻求的魔法比例不变形状描述符上没有找到或得到任何提示,我决定按照 DCS 的建议在整个屏幕上执行几乎直接的像素搜索。

首先,我搜索了 512 x 60 的徽标块。但事实证明,最终成为四嵌套循环(完整图像的行/列 x 搜索图像的行/列)将运行一个多小时,最坏的情况。不可接受。

我能够通过选择一个较小的搜索图像(大约 48 x 32 像素的补丁)线性缩小问题。我认为这花了我大约 30 秒,但仍然比我希望的要慢。另外,当我后来尝试搜索其他一些功能时,时间会越来越长。

我的解决方案是仅搜索我的搜索图像的单个扫描线,甚至通过代理而不是完全搜索。由于我正在搜索的图像的漫画色彩性质,我认为平均色调可以很好地代表我正在寻找的像素。我选择了搜索图像的“中间”行,提取了每个像素的色调(作为 0 到 7200 之间的整数),并计算了这些色调值的总和。在屏幕图像中,我计算了与搜索图像宽度相对应的像素数的移动总数,因此对于每个像素位置,我只需减去最旧的像素并添加一个新像素。使用 Java 的 Color.rgbToHSB 留下了一些优化潜力,特别是考虑到与 float 的转换并返回,但整个屏幕可以在几百毫秒内进行预采样。

因此,我为我的搜索图像中间线创建了一个屏幕色调总和与我的搜索图像中间线之间的差异列表,找到了最佳(即最小)差异,然后对那些共享第一名的位置进行了完整的逐像素比较最好的区别。这些最佳颜色总匹配通常少于 10 个,因此 10 个逐个像素的比较花费的时间可以忽略不计。

所以现在我在大约半秒内找到了我的搜索图像,还有一些优化潜力尚未开发。如果我需要“做”更多不同的比例,希望不同的分辨率能让我选择不同的搜索图像而无需反复试验,但在最坏的情况下,只需要多次运行一小部分比较工作,我预计仍会停留在不到一秒钟。

我没有达到我最初的目标,即对我所寻找的图像的不同抖动(即细节像素再现)具有很强的抵抗力;我的算法需要颜色匹配。但考虑到这将是一个多么困难的问题,我决定如果有必要我会越过那座桥。

【讨论】:

  • 我对你报告的时间感到惊讶,尤其是 48x32 补丁的 30 秒(我认为这是一个很好的补丁大小)。但是,我没有使用 Java 进行图像处理的经验;我使用 C++,有时使用 Matlab。补丁相关(这就是你所做的)通常在 C++ 图像处理 API 中使用多线程、SSE、Cuda 等进行了高度优化/并行化。你可能对 Java API ImageJ 感兴趣,它声称是“世界上最快的纯 Java图像处理程序。它可以在 0.1 秒内过滤出 2048x2048 的图像。"。见rsb.info.nih.gov/ij
  • @DCS:很高兴看到你仍然感兴趣!时间是从我非常不完美的记忆中报告的,并且基于非常未优化的代码,该语言不完全是优化的典型代表。我觉得在做任何专门针对性能的事情之前,先了解基于粗糙代码的算法性能会很有帮助。但鉴于我目前的方法及其令人满意的性能,看起来我无论如何都可以省去微优化——理想的结果!再次感谢您的有益建议。我之前注意到 ImageJ,但想保留大的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
相关资源
最近更新 更多