opencv第10天

模板匹配

目标

在本章中,您将学习 - 使用模板匹配在图像中查找对象 - 你将看到以下功能:cv.matchTemplate(),cv.minMaxLoc()

理论

模板匹配是一种用于在较大图像中搜索和查找模板图像位置的方法。为此,OpenCV带有一个函数**cv.matchTemplate**()。 它只是将模板图​​像滑动到输入图像上(就像在2D卷积中一样),然后在模板图像下比较模板和输入图像的拼图。 OpenCV中实现了几种比较方法。(您可以检查文档以了解更多详细信息)。它返回一个灰度图像,其中每个像素表示该像素的邻域与模板匹配的程度。

如果输入图像的大小为(WxH),而模板图像的大小为(wxh),则输出图像的大小将为(W-w + 1,H-h + 1)。得到结果后,可以使用**cv.minMaxLoc**()函数查找最大/最小值在哪。将其作为矩形的左上角,并以(w,h)作为矩形的宽度和高度。该矩形是您模板的区域。

注意 如果使用**cv.TM_SQDIFF**作为比较方法,则最小值提供最佳匹配。

OpenCV中的模板匹配

作为示例,我们将在梅西的照片中搜索他的脸。所以我创建了一个模板,如下所示: 

 我们将尝试所有比较方法,以便我们可以看到它们的结果如何:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
img2 = img.copy()
template = cv.imread('template.jpg',0)
w, h = template.shape[::-1]#[::-1]相当于倒转shape的shape是[行数,列数,通道数]
#由于是gray,所以通道数不显示,为单通道,所以w也就是宽度在数值上等于列数
# 列表中所有的6种比较方法
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
            'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
'''①TM_SQDIFF是平方差匹配;TM_SQDIFF_NORMED是标准平方差匹配。利用平方差来进行匹配,最好匹配为0.匹配越差,匹配值越大。

②TM_CCORR是相关性匹配;TM_CCORR_NORMED是标准相关性匹配。采用模板和图像间的乘法操作,数越大表示匹配程度较高, 0表示最坏的匹配效果。

③TM_CCOEFF是相关性系数匹配;TM_CCOEFF_NORMED是标准相关性系数匹配。将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。

总结:随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价)。
--相关性是越接近1越大越好
--平方差是越小越好
所以TM_SQDIFF在使用时和其他的是有所区别的'''
for meth in methods:
    img = img2.copy()
    method = eval(meth)#由于meth是字符串,所以要进行处理, 后面有eval函数详解
    # 应用模板匹配
    res = cv.matchTemplate(img,template,method)
'''cv.matchTemplate其实质是将待匹配的小图像img1在img2上滑动,计算匹配度,得到不同区域的匹配度大小。res就是前文提到的匹配度的分布'''
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
'''opencv的函数minMaxLoc:在给定的矩阵中寻找最大和最小值,并给出它们的位置。 该功能不适用于多通道阵列。 如果您需要在所有通道中查找最小或最大元素,要先将阵列重新解释为单通道。'''
    # 如果方法是TM_SQDIFF或TM_SQDIFF_NORMED,则取最小值
    if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv.rectangle(img,top_left, bottom_right, 255, 2)
    plt.subplot(121),plt.imshow(res,cmap = 'gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(img,cmap = 'gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()

解析:eval函数

eval()函数
eval() 函数用来执行一个字符串表达式,并返回表达式的值。

语法
eval(expression[, globals[, locals]])

expression – 表达式。
globals – 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
locals–变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
返回值:返回表达式计算结果。

实例
我们在从键盘输入数据时,Python接收的是字符串类型,这时我们可以使用eval()函数,将输入的数据进行还原

实例1
 

n = input()
m = eval(input())
# type()函数可以用来检测数据类型
print(type(n))
print(type(m))
#利用eval()将字符串类型转为整形
print(type(eval(n)))

输出结果:

 在这里插入图片描述

使用eval()函数,将字符串还原为数字类型,和int()函数的作用类似

实例2

# 输入[1,2,3,4]
m = input()  # 得到一个字符串
n = eval(input())  # 得到一个列表
print(type(m))
print(type(n))
print(type(n[0]))


输出结果

在这里插入图片描述

将输入的字符串转为对应的数据类型,列表、元组等数据类型都可以使用这种方式输入

实例3

# 表达式
s1 = '3*7'
s2 = 'pow(2,3)'
n = eval(s1)
m = eval(s2)
print(n, m)


输出结果:

在这里插入图片描述

查看以下结果:

  • cv.TM_CCOEFF

  • cv.TM_CCOEFF_NORMED 

  • cv.TM_CCORR 

  • cv.TM_CCORR_NORMED 

  • cv.TM_SQDIFF 

  • cv.TM_SQDIFF_NORMED 

您会看到,使用**cv.TM_CCORR**的结果并不理想。

多对象的模板匹配

在上一节中,我们在图像中搜索了梅西的脸,该脸在图像中仅出现一次。假设您正在搜索具有多次出现的对象,则**cv.minMaxLoc**()不会为您提供所有位置。在这种情况下,我们将使用阈值化。因此,在此示例中,我们将使用著名游戏**Mario**的屏幕截图,并在其中找到硬币。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img_rgb = cv.imread('mario.png')
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread('mario_coin.png',0)
w, h = template.shape[::-1]
res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
threshold = 0.8#阈值,超过0.8则认为匹配成功
loc = np.where( res >= threshold)#np.where用法在后面
for pt in zip(*loc[::-1]):
    cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
cv.imwrite('res.png',img_rgb)

结果:

np.where有两种用法
1.np.where(condition,x,y) 当where内有三个参数时,第一个参数表示条件,当条件成立时where方法返回x,当条件不成立时where返回y
2.np.where(condition) 当where内只有一个参数时,那个参数表示条件,当条件成立时,where返回的是每个符合condition条件元素的坐标,返回的是以元组的形式
代码示例

#用法一
#当self.net_input(X)返回的值大于等于0.0时,where返回1,否则返回0
np.where(self.net_input(X) >= 0.0, 1, 0)

#用法二
a = np.array([2,4,6,8,10])
#只有一个参数表示条件的时候
np.where(a > 5)

输出:
array([ 6,  8, 10])


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值