模糊模板匹配?

Zac*_*ack 16 opencv computer-vision

我试图围绕简历的基础知识.最初让我感兴趣的是模板匹配(在与CV无关的Pycon谈话中提到过),所以我想我会从那里开始.

我从这张图片开始:

来自SMB3的场景

其中我想检测马里奥.所以我把他剪掉了:

水管工

我理解在图像周围滑动模板以查看最合适的概念,并按照教程,我可以使用以下代码找到mario:

def match_template(img, template):
    s = time.time()
    img_size = cv.GetSize(img)
    template_size = cv.GetSize(template)

    img_result = cv.CreateImage((img_size[0] - template_size[0] + 1, 
                            img_size[1] - template_size[1] + 1), cv.IPL_DEPTH_32F, 1)
    cv.Zero(img_result)

    cv.MatchTemplate(img, template, img_result, cv.CV_TM_CCORR_NORMED)
    min_val, max_val, min_loc, max_loc = cv.MinMaxLoc(img_result)
    # inspect.getargspec(cv.MinMaxLoc)
    print min_val
    print max_val 
    print min_loc 
    print max_loc
    cv.Rectangle(img, max_loc, (max_loc[0] + template.width, max_loc[1] + template.height), cv.Scalar(120.), 2)
    print time.time() - s
    cv.NamedWindow("Result")
    cv.ShowImage("Result", img)
    cv.WaitKey(0)
    cv.DestroyAllWindows()
Run Code Online (Sandbox Code Playgroud)

到目前为止一直很好,但后来我意识到这是非常脆弱的.它只会找到具有该特定背景的Mario,并且会显示特定的动画帧.

所以我很好奇,因为马里奥将始终拥有相同的马里奥主义属性,(大小,颜色)是否有一种技术,我可以找到他,无论他的当前框架是静止不动,还是其中一种运行循环精灵?有点像模糊匹配,你可以对字符串,但对于图像.

也许因为他是唯一的红色东西,有一种简单跟踪红色像素的方法吗?

另一个问题是从模板中删除背景.也许这会帮助MatchTemplate函数找到马里奥,即使他不完全符合模板?截至目前,我并不完全确定它是如何工作的(我看到MatchTemplate中有一个掩码参数,但我还需要进一步调查)

我的主要问题是模板匹配是否是检测大多数相同但变化的图像的方式(比如他走路时),还是我应该研究另一种技术?

更新:

试图匹配其他马里奥斯


关于mmgp的建议,它应该可以用于匹配其他东西,我做了几个测试.

我用它作为匹配的模板:

超级马里奥

然后拍了几张屏幕截图来测试匹配.

首先,我成功找到了Mario,并获得了最大值1.

在此输入图像描述

然而,试图找到跳跃马里奥导致完全失火.

失火

现在被授予,模板中的马里奥,以及场景中的马里奥面向相反的方向,以及不同的动画帧,但我认为它们仍然比图像中的任何其他东西更匹配- 如果只是为了单是颜色.但它将平台作为与模板最接近的匹配.

请注意,这个的最大值是0.728053808212.

接下来,我尝试了一个没有马里奥的场景,看看会发生什么.

在此输入图像描述

但奇怪的是,我得到了具有跳跃马里奥的图像的确切结果 - 直到相似值:0.728053808212.马里奥在照片中的表现与他不在画面中一样准确.

真奇怪!我不知道基础算法的实际细节,但我想,从标准偏差的角度来看,场景中的框至少与模板中的红色匹配Mario的套装将比蓝色更接近平均距离平台,对吗?所以,令人费解的是,它甚至不在我期望它的一般领域.

我猜这是我的用户错误,或者可能只是一个误解.

为什么有类似马里奥的场景与没有马里奥的场景有太多匹配?

mmg*_*mgp 12

没有方法是绝对可靠的,但模板匹配确实有很好的机会在那里工作.它可能需要一些预处理,直到有更大的样本(例如一个简短的视频)来演示可能的问题,尝试更高级的方法没有多大意义,因为有些库为你实现它们 - 尤其是如果你不知道他们应该在哪些条件下工作.

例如,以下是我使用模板匹配(红色矩形)获得的结果 - 所有这些都使用模板http://i.stack.imgur.com/EYs9B.png,即使是最后一个:

在此输入图像描述 在此输入图像描述 在此输入图像描述 在此输入图像描述

为了实现这一点,我开始只考虑模板和输入图像的红色通道.由此我们可以轻松计算内部形态梯度,然后才进行匹配.为了在Mario不存在时不获取矩形,需要为匹配设置最小阈值.这是模板和这两个转换之后的图像之一:

在此输入图像描述 在此输入图像描述

这里有一些示例代码来实现:

import sys
import cv2
import numpy

img = cv2.imread(sys.argv[1])

img2 = img[:,:,2]
img2 = img2 - cv2.erode(img2, None)
template = cv2.imread(sys.argv[2])[:,:,2]
template = template - cv2.erode(template, None)

ccnorm = cv2.matchTemplate(img2, template, cv2.TM_CCORR_NORMED)
print ccnorm.max()
loc = numpy.where(ccnorm == ccnorm.max())
threshold = 0.4
th, tw = template.shape[:2]
for pt in zip(*loc[::-1]):
    if ccnorm[pt[::-1]] < threshold:
        continue
    cv2.rectangle(img, pt, (pt[0] + tw, pt[1] + th),
            (0, 0, 255), 2)

cv2.imwrite(sys.argv[2], img)
Run Code Online (Sandbox Code Playgroud)

我希望它能在更多种情况下失败,但还有一些简单的调整要做.


Fro*_*oyo 10

模板匹配并不总能产生良好的效果.你应该研究Keypoints匹配.

第1步:查找关键点

让我们假设你设法削减马里奥或获得马里奥的ROI图像.将此图像设为模板图像.现在,在主图像和模板中查找关键点.所以现在你有两组关键点.一个用于图像,另一个用于Mario(模板).

您可以根据自己的喜好使用SIFT,SURF,ORB.

[编辑]:

这就是我使用这种方法与SIFT和基于flann的knn匹配.我还没有完成边界框部分.

在此输入图像描述

由于您的模板非常小,SIFT和SURF不会提供很多关键点.但是为了获得大量的特征点,你可以尝试使用Harris Corner探测器.我在图像上应用了哈里斯的角落,我在马里奥身上得到了很好的分数.

在此输入图像描述

第2步:匹配关键点

如果您使用过SIFT或SURF,则会有图像和模板的描述符.使用KNN或其他一些有效的匹配算法匹配这些关键点.如果您正在使用OpenCV,我建议您查看基于flann的匹配器.匹配关键点后,您可能希望过滤掉不正确的匹配项.您可以通过K-最近邻居执行此操作,并且根据最近匹配的距离,您可以进一步过滤掉关键点.您可以使用前向后向错误进一步过滤匹配.

前向后向误差估计:

  1. 将模板关键点与图像关键点匹配这将为您提供一组匹配.
  2. 将图像关键点与模板关键点匹配.这将为您提供另一组匹配.
  3. 这两个集合的通用集合将过滤掉不正确的匹配.

在此输入图像描述

[编辑]:如果你使用Harris Corner探测器,你只能获得积分,而不是关键点.您可以将它们转换为关键点,也可以编写自己的蛮力数学运算符.这并不困难.

第3步:估算

过滤关键点后,您的对象附近有一组关键点(在本例中为Mario),并且几乎没有分散的关键点.要消除这些分散的关键点,您可以使用群集.DBSCAN群集将帮助您获得良好的积分群.

step4:边界框估计

现在你有了一组关键点.使用k-means,您应该尝试找到群集的中心.获得群集的中心后,您可以估计边界框.

我希望这有帮助.

[编辑]

尝试使用Harris Corners匹配积分.在过滤哈里斯角落之后,我使用强力方法来匹配这些点.一些更好的算法可能会给你更好的结果.

在此输入图像描述