OpenCV—python模板匹配与图像特征匹配
⽂章⽬录
⼀、理论介绍与算法
模板匹配是在⼀幅图像中寻⼀个特定⽬标的⽅法之⼀,这种⽅法的原理⾮常简单,遍历图像中的每⼀个可能的位置,⽐较各处与模板是否“相似”,当相似度⾜够⾼时,就认为到了我们的⽬标
⽤T表⽰模板图像,I表⽰待匹配图像,切模板图像的宽为w⾼为h,⽤R表⽰匹配结果,匹配过程(图⽰如上):
通过 滑动, 我们的意思是图像块⼀次移动⼀个像素 (从左往右,从上往下). 在每⼀个位置, 都进⾏⼀次度量计算来表明它是 “好” 或“坏” 地与那个位置匹配 (或者说块图像和原图像的特定区域有多么相似).
(x.y)
对于 T 覆盖在 I 上的每个位置,你把度量值 保存 到 结果图像矩阵® 中. 在 R 中的每个位置都包含匹配度量值,红⾊椭圆框住的位置很可能是结果图像矩阵中的最⼤数值, 所以这个区域 (以这个点为顶点,长宽和模板图像⼀样⼤⼩的矩阵) 被认为是匹配的。
我们使⽤函数 来定位在矩阵 R 中的最⼤值点 (或者最⼩值, 根据函数输⼊的匹配参数)
OpenCV提供了6种模板匹配算法:
平⽅差匹配法CV_TM_SQDIFF(最好匹配为0.匹配越差,匹配值越⼤)归⼀化平⽅差匹配法CV_TM_SQDIFF_NORMED
相关匹配法CV_TM_CCORR 这类⽅法采⽤模板和图像间的乘法操作,所以较⼤的数表⽰匹配程度较⾼,0标识最坏的匹配效果归⼀化相关匹配法CV_TM_CCORR_NORMED
相关系数匹配法CV_TM_CCOEFF
这类⽅法将模版对其均值的相对值与图像对其均值的相关值进⾏匹配,1表⽰完美匹配,-1表⽰糟糕的匹配,0表⽰没有任何相关性(随机序列)。其中:归⼀化相关系数匹配法CV_TM_CCOEFF_NORMED
显然公式越来越复杂,计算量也很⼤,但是准确度也跟着提⾼,看如何取舍了。
⼆、算法代码
R(x,y)=[T(x ,y )−I(x +x ,y +y )]x ,y ′′∑′′′′2
R(x,y)=T(x ,y )⋅I(x +x ,y +y )∑x ,y ′′′′2∑x ,y ′′′′2
[T(x ,y )−I(x +x ,y +y )]∑x ,y ′′′′′′2
R(x,y)=[T(x ,y )⋅I(x +x ,y +y )]
x ,y ′′∑′′′′R(x,y)=T(x ,y )⋅I(x +x ,y +y )∑x ,y ′′′′2∑x ,y ′′′′2rectangle函数opencv
[T(x ,y )⋅I (x +x ,y +y )]
∑x ,y ′′′′′′′R(x,y)=[T (x ,y )⋅I(x +x ,y +y )]
x ,y ′′∑′′′′′T (x ,y )=T(x ,y )−⋅T(x ,y )′′′′′w⋅h 1
∑x ,y ′′′′′′′′I (x +x ,y +y )=I(x +x ,y +y )−⋅I(x +x ,y +y )
′′′′′w⋅h 1∑x ,y ′′′′′′′′R(x,y)=T (x ,y )⋅I (x +x ,y +y )∑x ,y ′′′′′2∑x ,y ′′′′′2
[T (x ,y )⋅I (x +x ,y +y )]
∑x ,y ′′′′′′′′
如下参考代码中是直接操作像素,显然速度⾮常慢,我在如上(左)图⽚中匹配上(右)图。我使⽤numpy矩阵运算⽅式重写了以上算法。
import numpy as np
import time
import cv2
def EM_EM2(temp):
array = shape(1,-1)
EM_sum = np.double(np.sum(array[0]))
square_arr = np.square(array[0])
EM2_sum = np.double(np.sum(square_arr))
return EM_sum,EM2_sum
def EI_EI2(img, u, v,temp):
height, width = temp.shape[:2]
roi = img[v:v+height, u:u+width]
array_roi = shape(1,-1)
EI_sum = np.double(np.sum(array_roi[0]))
square_arr = np.square(array_roi[0])
EI2_sum = np.double(np.sum(square_arr))
return EI_sum,EI2_sum
def EIM(img, u, v, temp):
height, width = temp.shape[:2]
roi = img[v:v+height, u:u+width]
product = temp*roi*1.0
product_array = shape(1,-1)
sum= np.double(np.sum(product_array[0]))
return sum
def Match(img, temp):
imgHt, imgWd = img.shape[:2]
height, width = temp.shape[:2]
uMax = imgWd-width
vMax = imgHt-height
temp_N = width*height
match_len =(uMax+1)*(vMax+1)
MatchRec =[0.0for _ in range(0, match_len)]
k =0
EM_sum, EM2_sum = EM_EM2(temp)
for u in range(0, uMax+1):
for v in range(0, vMax+1):
EI_sum, EI2_sum = EI_EI2(img, u, v, temp)
IM = EIM(img,u,v,temp)
numerator=( temp_N * IM - EI_sum*EM_sum)*(temp_N * IM - EI_sum * EM_sum)
denominator=(temp_N * EI2_sum - EI_sum**2)*(temp_N * EM2_sum - EM_sum**2)
ret = numerator/denominator
MatchRec[k]=ret
MatchRec[k]=ret
k+=1
print('进度==》[{}]'.format(u/(vMax+1)))
val =0
k =0
x = y =0
for p in range(0, uMax+1):
for q in range(0, vMax+1):
if MatchRec[k]> val:
val = MatchRec[k]
x = p
y = q
k+=1
print("val: %f"%val)
return(x, y)
def main():
img = cv2.imread('./gggg/001A12.png', cv2.IMREAD_GRAYSCALE)
temp = cv2.imread('./gggg/001A1.png', cv2.IMREAD_GRAYSCALE)
tempHt, tempWd = temp.shape
(x, y)= Match(img, temp)
cv2.imshow("temp", temp)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ =='__main__':
start = time.time()
main()
end = time.time()
print("Total Spend time:",str((end - start)/60)[0:6]+"分钟")
'''
val: 1.000025
Total Spend time: 0.0866分钟
'''
为了更快的进⾏算法验证,⽤上述代码进⾏验证时请尽量选⽤较⼩的匹配图像及模板图像:单⽬标匹配
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('./gggg/001.png',0)
template = cv2.imread('./gggg/001A1.png',0)
w, h = template.shape[::-1]
methods =['cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED',
'cv2.TM_CCORR','cv2.TM_CCORR_NORMED',
'cv2.TM_CCOEFF','cv2.TM_CCOEFF_NORMED']
for meth in methods:
method =eval(meth)
res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)#到最⼤值和最⼩值print('{}:cv2.minMaxLoc(res):\t{} '.format(meth,cv2.minMaxLoc(res)))
if method in[cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right =(top_left[0]+ w, top_left[1]+ h)
plt.subplot(121),plt.imshow(res,cmap ='gray')
plt.title('Matching Result'), icks([]), icks([])
plt.subplot(122),plt.imshow(img,cmap ='gray')
plt.title('Detected Point'), icks([]), icks([])
plt.suptitle(meth)
plt.show()
多⽬标匹配
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论