python学opencv|读取图像(五十三)原理探索:使用cv.matchTemplate()函数实现最佳图像匹配
【1】引言
前序学习进程中,已经探索了使用cv.matchTemplate()函数实现最佳图像匹配的技巧,并且成功对两个目标进行了匹配。
相关文章链接为:python学opencv|读取图像(五十二)使用cv.matchTemplate()函数实现最佳图像匹配-CSDN博客
实际上,我们在这篇文章中重点体会了匹配效果,却没有真正剖析代码背后的运行逻辑。今天这篇文章的目标就是对代码背后逻辑稍微追溯一下。
【2】官网教程
【2.1】cv2.matchTemplate()函数
点击下方链接,直达cv2.matchTemplate()函数官网链接:
图1 cv2.matchTemplate()函数官网说明
图1所示的cv2.matchTemplate()函数官网说明中,有三处做了标记,它们彼此交织在一起。需要解读:
a.待匹配的大图像I大小为W X H,使用的模板T像素大小为w x h,获得的匹配效果R对应的的矩阵大小为(W-w+1,H-h+1);
b.使用不同的匹配方法后,再用minMaxLoc函数读取最佳匹配效果对应的左上角坐标时,有时候取最小值,如TM_SQDIFF,有时候取最大值,如TM_CCORR和TM_CCOEFF。
c.解读匹配方法请看第2.2节。
【2.2】cv2.matchTemplate()函数
点击链接,直达函数对匹配方法的解读:OpenCV: Object Detection
在这个页面,会看到不同的函数说明:
图2 匹配方法的数学公式
由图2可见,TM_SQDIFF采用的是减法计算,而TM_CCORR和TM_CCOEFF采用的乘法计算,所以相似度高的时候,TM_SQDIFF方法的计算值往往会接近0,而TM_CCORR和TM_CCOEFF方法就会在因为平方而取得更大的值。
所以“用minMaxLoc函数读取最佳匹配效果对应的左上角坐标时,有时候取最小值,如TM_SQDIFF,有时候取最大值,如TM_CCORR和TM_CCOEFF”就获得了解释。
【3】代码测试
【3.1】代码回顾
首先直接引用前一篇文章的完整代码:
import cv2 as cv # 引入CV模块
import numpy as np #引入numpy模块
# 读取图片
srcm = cv.imread('srcm.png') #读取图像srcx.png
srcg = cv.imread('srcg.png') #读取图像srcp.png
srcc = cv.imread('srcc.png') #读取图像srcp.png
rows,cols,cans=srcg.shape #读取图像属性
rowsc,colsc,cansc=srcc.shape #读取图像属性
#匹配结果
results=cv.matchTemplate(srcm,srcg,cv.TM_CCORR_NORMED)
results1=cv.matchTemplate(srcm,srcc,cv.TM_CCORR_NORMED)
#取值
minValue,maxValue,minLoc,maxLoc=cv.minMaxLoc(results)
minValuec,maxValuec,minLocc,maxLocc=cv.minMaxLoc(results1)
#取最大坐标
resultPoint1=maxLoc
print("resultPoint1=",resultPoint1)
#取最大坐标
resultPoint2=maxLocc
print("resultPoint2=",resultPoint2)
#定义新坐标
resultPoint3=(resultPoint1[0]+cols,resultPoint1[1]+rows)
print("resultPoint3=",resultPoint3)
#定义新坐标
resultPoint4=(resultPoint2[0]+colsc,resultPoint2[1]+rowsc)
print("resultPoint4=",resultPoint4)
#作标记
cv.circle(srcm,(250,250),30,(0,255,0))
cv.rectangle(srcm,resultPoint1,resultPoint3,(0,255,0),2)
cv.rectangle(srcm,resultPoint2,resultPoint4,(200,180,55),2)
# 显示结果
cv.imshow('srcm ', srcm)
cv.imshow('srcg ', srcg)
cv.imshow('srcc ', srcc)
cv.imwrite('srcgc.png',srcm)
#窗口控制
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
待匹配的图像I为:
图3 待匹配图像I:srcm.png
图4 模板T1 srcg.png
图5 模板T2 srcc.png
图6 匹配效果 srcgc.png
上述代码全部使用了cv2.TM_CCORR_NORMED方法,所以需要调用最大值来代表最佳匹配效果的左上角坐标。
未验证不用方法对应最佳匹配效果的左上角坐标,现在应增加匹配方法。
【3.2】代码扩展
在直接引用前一篇文章的完整代码的基础上,不仅要增加匹配方法,还要显示出匹配结果。
#匹配计算
results=cv.matchTemplate(srcm,srcg,cv.TM_SQDIFF_NORMED) #TM_SQDIFF匹配方法
results1=cv.matchTemplate(srcm,srcc,cv.TM_CCORR_NORMED) #TM_CCORR匹配方法
print("result=",results) #输出匹配结果
print("result1=",results1) #输出匹配结果
代码先后使用了TM_SQDIFF和TM_CCORR两种方法,并且要求输出了匹配结果。
然后读取了调用minMaxLoc()函数对结果渠道的各个参数值:
#取值
minValue,maxValue,minLoc,maxLoc=cv.minMaxLoc(results)
minValuec,maxValuec,minLocc,maxLocc=cv.minMaxLoc(results1)
print("result.minValue=",minValue)
print("result1.minValuec=",minValuec)
print("result.maxValue=",maxValue)
print("result1.maxValuec=",maxValuec)
print("result.minLoc=",minLoc)
print("result1.minLocc=",minLocc)
print("result.maxLoc=",maxLoc)
print("result1.maxLocc=",maxLocc)
然后根据先前的分析思路,取最佳匹配矩阵的左上角坐标。
这时候TM_SQDIFF取最小值,TM_CCORR方法取最大值,之后还要叠加模板的大小,来画出整个匹配区域:
#取最小坐标
resultPoint1=minLoc
print("resultPoint1=",resultPoint1)
#取最大坐标
resultPoint2=maxLocc
print("resultPoint2=",resultPoint2)
#定义新坐标
resultPoint3=(resultPoint1[0]+cols,resultPoint1[1]+rows)
print("resultPoint3=",resultPoint3)
#定义新坐标
resultPoint4=(resultPoint2[0]+colsc,resultPoint2[1]+rowsc)
print("resultPoint4=",resultPoint4)
之后为了突出匹配点,以最小和最大坐标Wie圆心,分别绘制半径为10和20的圆形:
#作标记
cv.circle(srcm,(minLoc),10,(255,255,0))
cv.circle(srcm,(maxLoc),20,(255,255,0))
cv.circle(srcm,(minLocc),10,(0,255,255))
cv.circle(srcm,(maxLocc),20,(0,255,255))
cv.circle(srcm,(250,250),30,(0,255,0))
cv.rectangle(srcm,resultPoint1,resultPoint3,(0,255,0),2)
cv.rectangle(srcm,resultPoint2,resultPoint4,(200,180,55),2)
然后输出所有图像:
# 显示结果
cv.imshow('srcm ', srcm)
cv.imwrite('srcgcw.png',srcm)
#窗口控制
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
代码运行后,获得的匹配效果为:
图7 匹配效果srcgcw.png
由图7可见,TM_SQDIFF取最小值,TM_CCORR方法取最大值获得的最佳匹配图像实现了预期效果。
【4】细节说明
上述3.2节读取到的部分匹配结果矩阵为:
图8 匹配结果矩阵
由图8可见,每个矩阵内部给出了很多值,这表明在矩阵内部,图像和模板是按照像素点逐个进行比对匹配。
【5】总结
掌握了python+opencv调用使用cv.matchTemplate()函数实现最佳图像匹配的执行原理和过程。