opencv-python 模板匹配
模板匹配:在给定的图像中查找和模板最相似的区域。模板匹配类似于卷积,模板在原图上从左上角原点(0,0)开始滑动,计算模板与滑动窗口的差别程度,计算方法有6种,每次计算的结果放在一个矩阵中,最后输出差别程度的矩阵。原始图像为A*B,模板大小是a*b的话,输出的矩阵大小为:(A-a+1)*(B-b+1)。
1 模板匹配
opencv中的模板匹配函数是:matchTemplate(img,template,method)
模板匹配计算方法(最好用归一化的参数):
TM_SQDIFF 计算平方不同,计算出的值越小,越相关
TM_CCORR 计算相关性,计算出来的值越大,越相关
TM_CCOEFF 计算相关系数,计算出来的值越大,越相关
TM_SQDIFF_NORMED 计算归一化平方不同,计算出来的值越接近0,越相关
TM_CCORR_NORMED 计算归一化相关性,计算出来的值越接近1,越相关
TM_CCOEFF_NORMED 计算归一化相关系数,计算出来的值越接近1,越相关
图像和对应的匹配图像如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread('./cat.jpg')
template = cv2.imread('./cat_face.jpg')
h,w = template.shape[:2]
res = cv2.matchTemplate(img,template,cv2.TM_CCORR_NORMED) #模板匹配
print(res)
min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(res) #获取匹配结果的最值和对应位置,方便计算后续矩形所需的坐标点
print(max_val,max_loc)
cv2.rectangle(img,max_loc,(max_loc[0]+w,max_loc[1]+h),color=[0,0,255]) #用矩形把匹配的结果显示出来
cv2.imshow('img',img)
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(121),plt.imshow(res,cmap='gray')
plt.subplot(122),plt.imshow(img2)
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()

把六种模板匹配计算方法都试一下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread('./cat.jpg')
template = cv2.imread('./cat_face.jpg') #匹配的模板图片
h,w = template.shape[:2] #获取模板的高宽
#定义模板匹配方法列表
methods = ['cv2.TM_SQDIFF','cv2.TM_CCORR','cv2.TM_CCOEFF','cv2.TM_SQDIFF_NORMED','cv2.TM_CCORR_NORMED','cv2.TM_CCOEFF_NORMED']
for meth in methods: #循环显示匹配的结果,把所有匹配方法都用plt显示出来
img_copy = img.copy() #把原始图片拷贝一下,保证后续的匹配方法不被影响
method = eval(meth) #取匹配方法的真值
res = cv2.matchTemplate(img_copy,template,method) #模板匹配
min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(res) #获取匹配结果的最值和对应位置
if method in [cv2.TM_SQDIFF,cv2.TM_SQDIFF_NORMED]: #如果是这两种匹配方法,计算出的值越小,越相关,其余的匹配方法相反
start_point = min_loc
end_point = (min_loc[0]+w,min_loc[1]+h)
else:
start_point = max_loc
end_point = (max_loc[0]+w,max_loc[1]+h)
cv2.rectangle(img_copy,start_point,end_point,color=[0,0,255]) #用矩形把匹配的结果显示出来
img2 = cv2.cvtColor(img_copy, cv2.COLOR_BGR2RGB) #用plt显示图片的时候要把通道转换成RGB格式
plt.subplot(121),plt.imshow(res,cmap='gray') #显示匹配结果的灰度图
plt.subplot(122),plt.imshow(img2)
plt.suptitle(meth) #显示匹配方法标题
plt.show()

2 匹配多个对象
首先介绍一下np.where函数
np.where 函数是三元表达式 x if condition else y 的向量化版本,它有两种用法:
1.np.where(condition,x,y) 当where内有三个参数时,第一个参数表示条件,当条件成立时where方法返回x,当条件不成立时where返回y
2.np.where(condition) 当where内只有一个参数时,那个参数表示条件,当条件成立时,where返回的是每个符合condition条件元素的坐标,返回的是以元组的形式
图像和对应的匹配图像如下:

import cv2
import numpy as np #匹配多个对象
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread('./mario.jpg')
template = cv2.imread('./mario_coin.jpg') #匹配的模板图片
h,w = template.shape[:2] #获取模板的高宽
res = cv2.matchTemplate(img,template,cv2.TM_CCORR_NORMED)
#print(res)
threshold = 0.8 #设定阈值
loc = np.where(res >= threshold) #返回res中值大于0.8的y轴,x轴的索引(分开的)
#print(loc)
# loc = np.argwhere(res >= threshold) #用argwhere可以直接获取坐标[y,x],但是坐标类型是list
# print(loc)
# for left_top in loc:
# left_top = tuple(left_top[::-1]) #把坐标list转换位元组
# bottom_right = (left_top[0]+w,left_top[1]+h)
# cv2.rectangle(img,left_top,bottom_right,[0,0,255],1)
for ptr in zip(*loc[::-1]): # *表示可选参数 因为loc是先y坐标再x坐标,所以用loc[::-1]翻转一下,然后再用zip函数拼接一下
end_point = (ptr[0]+w,ptr[1]+h)
cv2.rectangle(img,ptr,end_point,[0,0,255],1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
匹配结果如下:


浙公网安备 33010602011771号