在图形屏幕上查找内容时,我目前对如何在图像中找到给定形状感到茫然。当然,图像中的形状可能具有不同的比例,并且在某个未知的x,y偏移处。
除了由不同比例产生的像素伪像外,两个图像中也有一点噪音,所以我需要一些宽容的搜索。
这是我要找的形象。
它应该出现在我的(双屏)缓冲区的屏幕转储中,大小约为3300 x 1200像素。我当然希望在浏览器窗口中找到它,但这些信息不是必需的。
本练习的目的(到目前为止)是提出一个结果:
(x1,y1)
到(x2,y2)
的矩形。我希望能够有效地防止缩放以及可能通过抖动引入的噪音。另一方面,我可以排除一些常见的CV挑战,例如旋转或非刚性。那个框架形状很容易被人类大脑辨认出来,对于一个专用的软件来说有多难?这是一个Adobe Flash应用程序,直到最近我才认为从游戏GUI中感知图像应该很容易。
我正在寻找能够找到针和干草堆之间最大可能重叠的x,y平移的算法,并且如果可能的话,无需通过一系列可能的比例因子进行迭代。理想情况下,算法可以抽象出" shape-ness"这些图像的方式与尺度无关。
我已经阅读了一些关于傅立叶变换的有趣事情来完成类似的事情:给定相同比例的目标图像,FFT和一些矩阵数学产生了与搜索模式相对应的较大图像中的点。但是我没有理论背景将其付诸实践,我也不知道这种方法是否会优雅地处理规模问题。帮助将不胜感激!
技术:我在Clojure / Java中进行编程,但可以在其他语言中调整算法。我想我应该能够与遵循C调用约定的库接口,但我更喜欢纯Java解决方案。
您可能能够理解为什么我不愿意提供实际图像。这只是一场愚蠢的游戏,但屏幕阅读的任务比我想象的更具挑战性。
我显然能够对我的屏幕缓冲区进行详尽的搜索,以查找构成我的图像的像素(不包括黑色),甚至可以在一分钟内完成。但我的目标是使用一种与形状相匹配的技术来发现木制框架,而不管缩放和抖动可能产生的差异。
事实上,抖动是我在这个项目中遇到的许多挫折之一。我一直致力于通过边缘提取来提取一些有用的矢量,但边缘非常难以捉摸,因为任何给定区域的像素都具有广泛不一致的颜色 - 因此很难从局部抖动伪像中分辨真实边缘。我不知道这么简单的游戏会产生很难让软件感知的图形。在开始寻找功能之前,我应该从本地平均像素开始吗?我应该通过丢弃像素颜色值的最低有效位来减少颜色深度吗?
我尝试获得纯Java解决方案(实际上是用Clojure / Java混合编程)所以我并不喜欢opencv(安装.DLL或者.so使用C代码)。请不要担心我选择的语言,学习经历对我来说比表演更有趣。
答案 0 :(得分:11)
作为一个计算机视觉人,我通常会指向特征提取和匹配(SIFT,SURF,LBP等),但这几乎肯定是一种矫枉过正,因为大多数这些方法提供了更多的不变性(=容差)反对转换)比实际需要(例如反对旋转,亮度变化,......)。此外,使用功能将涉及OpenCV或 lot 编程。
所以这是我提出的一个简单解决方案的建议 - 你判断它是否超过了智能阈值:
您正在寻找的图像看起来有一些非常独特的结构(字母,徽标等)。我建议你为每个可能的翻译做一个像素到像素的匹配,并且对于许多不同的比例(我假设比例范围是有限的) - 但仅针对一个小的独特补丁您正在寻找的图像(例如,黄色文本的正方形部分)。这比匹配整个事情要快得多。如果你想要一个奇特的名字:在图像处理中,它被称为模板匹配的相关性。 “模板”是您正在寻找的东西。
一旦你找到了一些小的独特补丁的候选位置,你可以验证你可以通过测试整个图像,或者更有效地测试一些其他< / strong>图像的独特补丁(当然,使用您找到的翻译/比例)。这使得您的搜索功能可以抵御原始补丁的意外匹配,而不会导致过多的性能损失。
关于抖动容差,我会对两个图像(您正在寻找的模板和作为搜索空间的图像)进行简单的预过滤。根据抖动的属性,您可以开始尝试使用简单的框模糊,如果不起作用,可能会使用小内核(3 x 3)进行中值过滤。这不会让您在模板和搜索图像之间获得100%的同一性,但您可以比较强大的数字分数。
根据评论进行编辑
我理解(1)你想要一些更强大,更像“类似CV”的东西,并且更加花哨作为解决方案,并且(2)你对通过简单地扫描大量堆栈来实现尺度不变性持怀疑态度不同的尺度。
关于(1),如上所述,规范方法是使用特征描述符。特征描述符不描述完整的图像(或形状),而是描述图像的一小部分,其方式对各种变换是不变的。查看SIFT和SURF,以及VLFeat,它具有良好的SIFT实施,并且还实现了MSER和HOG(并且远小于shape context和here OpenCV的)。 SURF比SIFT更容易实现,两者都获得了大量专利。两者都有一个“直立”版本,没有旋转不变性。这应该会增加您的稳健性。
您在评论中描述的策略在形状描述符的方向上比图像特征描述符更多。 确保您了解它们之间的区别! 2D形状描述符的目标是通常由轮廓或二元蒙版描述的形状。图像特征描述符(在上面的意义上使用)瞄准具有强度值的图像,通常是照片。一个有趣的形状描述符是scale space,很多其他的概括为original SIFT paper。我不认为你的问题最好通过形状描述符解决,但也许我误解了一些东西。我会非常小心图像边缘上的形状描述符,因为作为一阶导数的边可以通过抖动噪声来强烈改变。
关于(2):我想说服你,扫描一堆不同的尺度对于那些不懂计算机视觉的人来说不仅仅是一个愚蠢的黑客攻击!实际上,它在视觉上做了很多,我们只是有一个奇特的名称,它误导了那些不熟悉的{{3}}搜索。这有点过于简单了,但实际上只是一点点。在实践中使用的大多数图像特征描述符使用比例空间来实现比例不变性,该比例空间是越来越小的(和低通滤波的)图像的堆栈。他们添加的唯一技巧是在比例空间中寻找极值并仅在那些极值处计算描述符。但是,仍然会计算并遍历完整的比例空间以找到这些极值。请查看{{3}}以获得对此的详细解释。
答案 1 :(得分:0)
我正在回答我自己的问题,让大家知道我最终的目的是什么。
我没有找到或得到任何关于我所寻求的魔术规模不变形状描述符的提示,我决定采用DCS的建议并在整个屏幕上执行几乎直接的像素搜索。
首先,我搜索了一个512 x 60大块的徽标。但事实证明,最终成为四边形嵌套循环(完整图像的行/列,搜索图像的行/列)将运行超过一个小时,最糟糕的情况。不可接受的。
我能够通过选择较小的搜索图像(大约48 x 32像素的补丁)来线性缩放问题。我想,这让我接受了大约30秒,但仍然比我想要的要慢。此外,当我后来尝试搜索其他一些功能时,时间会增加。
我的解决方案是仅搜索我的搜索图像的单个扫描线,甚至是通过代理而不是完全搜索。由于我正在搜索的图像的漫画色性质,我认为平均色调会为我正在寻找的像素提供合适的代理。我选择了搜索图像的“中间”行,为每个像素提取了色调(作为0到7200之间的整数),并计算了这些色调值的总和。在屏幕图像中,我计算了与搜索图像的宽度相对应的像素数量的移动总数,因此对于每个像素位置,我只需要减去最旧的像素并添加一个新的像素。使用Java的Color.rgbToHSB
留下了一些优化潜力,特别是考虑到转换为float
并返回,但整个屏幕可以在几百毫秒内进行预采样。
所以我创建了一个屏幕色调总和与我的搜索图像中间线之间的差异列表,找到了最佳(即最小)差异,然后对那些共享第一名的位置进行了完整的逐像素比较最好的区别。这些最佳颜色总匹配通常少于10个,因此10个逐个像素的比较花费的时间可以忽略不计。
所以现在我在大约半秒钟内找到了我的搜索图像,其中一些优化潜力尚未开发。如果我需要“做”更多不同的尺度,希望不同的分辨率可以让我选择不同的搜索图像而无需反复试验,但在最坏的情况下,只有一小部分比较工作需要多次运行,而我预计仍然会停留在一秒钟之内。
我没有达到我最初的目标,即对我所寻找的图像的不同抖动(即细节像素再现)非常有抵抗力;我的算法需要在颜色上很好地匹配。但考虑到问题会有多严重,我决定如果必要的话,我会越过那座桥。