opencv-python 模板匹配

发布时间 2023-08-01 22:27:09作者: 寒水浮云

模板匹配:在给定的图像中查找和模板最相似的区域。模板匹配类似于卷积,模板在原图上从左上角原点(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() 

 匹配结果如下: