目录
19 模板匹配
19.1 模板匹配
定义:用模板图在目标图中不断滑动,通过某种方法来判断是否匹配成功,找到模板图所在位置。
特点:
- 不会有边缘填充。
- 类似于卷积,滑动比较,挨个比较像素。
- 返回结果大小是:目标图大小-模板图大小+1。
19.2 匹配方法
语法:
res = cv2.matchTemplate(image,templ,method)
参数说明:
-
image:原图像,灰度图像或彩色图像(匹配将在每个通道上独立进行)。
-
templ:模板图像,也是灰度图像或与原图像相同通道数的彩色图像。
-
method:匹配方法,可以是以下之一:
-
cv2.TM_CCOEFF
-
cv2.TM_CCOEFF_NORMED
-
cv2.TM_CCORR
-
cv2.TM_CCORR_NORMED
-
cv2.TM_SQDIFF
-
cv2.TM_SQDIFF_NORMED
-
返回值:
一个结果矩阵,这个矩阵的大小与原图像相同。矩阵的每个元素表示原图像中相应位置与模板图像匹配的相似度。
匹配方法不同,返回矩阵的值的含义也会有所区别。:
-
cv2.TM_SQDIFF
或cv2.TM_SQDIFF_NORMED
:返回值越接近0,表示匹配程度越好。最小值对应的最佳匹配位置。
-
cv2.TM_CCORR
或cv2.TM_CCORR_NORMED
:返回值越大,表示匹配程度越好。最大值对应的最佳匹配位置。
-
cv2.TM_CCOEFF
或cv2.TM_CCOEFF_NORMED
:返回值越大,表示匹配程度越好。最大值对应的最佳匹配位置。
19.2.1 平方差匹配
cv2.TM_SQDIFF
19.2.2 归一化平方差匹配
cv2.TM_SQDIFF_NORMED
与平方差匹配类似,只不过需要将值统一到0到1
19.2.3 相关匹配
cv2.TM_CCORR
19.2.4 归一化相关匹配
cv2.TM_CCORR_NORMED
19.2 5 相关系数匹配
cv2.TM_CCOEFF
19.2.6 归一化相关系数匹配
cv2.TM_CCOEFF_NORMED
19.3 绘制轮廓
找的目标图像中匹配程度最高的点,我们可以设定一个匹配阈值来筛选出多个匹配程度高的区域。
语法1:
loc = np.where(array>0.8) # loc包含array中所有大于0.8的**元素索引**的数组
np.where(condition) 是 NumPy 的一个函数,当条件为真时,返回满足条件的元素的索引。
语法2:
zip(*loc)
*loc
是解包操作,将loc
中的多个数组拆开,作为单独的参数传递给zip
。zip
将这些数组按元素一一配对,生成一个迭代器,每个元素是一个元组,表示一个坐标点。
案例:
x=list([[1,2,3,4,3],[23,4,2,4,2]])
print(list(zip(*x)))#[(1, 23), (2, 4), (3, 2), (4, 4), (3, 2)]
案例:
import numpy as np
import cv2 as cv
# 读图
img = cv.imread("./images/game.png")# 目标图
# print(img.shape)
temp = cv.imread("./images/temp.png")# 模板图
# print(temp.shape)
# 转灰度
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)# 目标图转灰度
temp_gray = cv.cvtColor(temp,cv.COLOR_BGR2GRAY)# 模板图转灰度
# 模板匹配
# cv2.matchTemplate(目标图,模板图,匹配方式)
res = cv.matchTemplate(img_gray,temp_gray,cv.TM_CCOEFF_NORMED)
print(res.shape)
# print(res)
# 设置阈值,使用np.where获取条件的坐标
threshold = 0.8
loc = np.where(res>=threshold)# loc ==> (y,x) 因为先行后列(会获取匹配程度大于等于阈值的结果的索引位置,[[y1,y2,...yn],[x1,x2,...xn]])
# print(loc,type(loc),res[loc[0][0],loc[1][0]])
# 获取模板宽高
h,w = temp.shape[:2]
# 解包,拿坐标
for pt in zip(*loc):# pt==>(y,x)
leftupper = pt[::-1] # (x,y)
rightbottom = (pt[1]+w,pt[0]+h) # (x+w,y+h)
# 绘制出匹配的部分,框出来
cv.rectangle(img,leftupper,rightbottom,(0,255,0),2,cv.LINE_AA)
cv.imshow("img",img)
cv.waitKey(0)
cv.destroyAllWindows()
输出:
练习:
import cv2 as cv
import numpy as np
# 读取图像
img = cv.imread("./my_image/image.jpg")
temp = cv.imread("./my_image/templ.jpg")
# 获取模板宽高
h,w = temp.shape[:2]
# 转灰度
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)# 目标图转灰度
temp_gray = cv.cvtColor(temp,cv.COLOR_BGR2GRAY)# 模板图转灰度
# 模板匹配
res = cv.matchTemplate(img,temp,cv.TM_CCOEFF_NORMED)
print(res)
# 设置阈值
threshold = 0.9
# 使用np.where获取条件的坐标
loc = np.where(res >= threshold)
print(loc)
# 解包,拿坐标
for pt in zip(*loc):
left_upper = pt[::-1]
right_bottom = (pt[1] + w , pt[0] + h)
# 绘制出匹配的部分,框出来
cv.rectangle(img,left_upper,right_bottom,(0,0,255),1)
# 显示图像
cv.imshow("img",img)
cv.waitKey()
cv.destroyAllWindows()
输出: