什么是模板匹配?
所谓模板匹配就是给出一个模板图片和一个搜索图片,在搜索图片中找到与模板图片最为相似的部分。
怎么实现?
简单来说,就是让模板图片在搜索图片上滑动,以像素点为单位,计算每一个位置上的相似度,最终得到相似度最高的像素点的位置,以该像素点为原定,模板图片为大小,对应在搜索图片上的位置即为匹配度最高的部分。
有哪些匹配算法?
在opencv中 可以通过函数matchTemplate实现模板匹配,同时有六种相关的匹配算法
T
(
x
,
y
)
T(x,y)
T(x,y) 用来表示我们的模板。
I
(
x
,
y
)
I(x,y)
I(x,y) 是我们的目标图像 ,
R
(
x
,
y
)
R(x,y)
R(x,y) 是用来描述相似度的函数。
-
平方差匹配 method=CV_TM_SQDIFF
这类方法利用平方差来进行匹配,最好匹配为0.匹配越差,匹配值越大.
R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) 2 R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2 R(x,y)=∑x′,y′(T(x′,y′)−I(x+x′,y+y′))2 -
标准平方差匹配 method=CV_TM_SQDIFF_NORMED
这个方法其实和平方差匹配算法是类似的。只不过对图像和模板进行了标准化操作。
R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) 2 ∑ x ′ , y ′ T ( x ′ , y ′ ) 2 ⋅ ∑ x ′ , y ′ I ( x + x ′ , y + y ′ ) 2 R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} R(x,y)=∑x′,y′T(x′,y′)2⋅∑x′,y′I(x+x′,y+y′)2∑x′,y′(T(x′,y′)−I(x+x′,y+y′))2 -
相关匹配 method=CV_TM_CCORR
这类方法采用模板和图像间的乘法操作,所以较大的数表示匹配程度较高,0标识最坏的匹配效果.
R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y')) R(x,y)=∑x′,y′(T(x′,y′)⋅I(x+x′,y+y′)) -
标准相关匹配 method=CV_TM_CCORR_NORMED
这个方法和 标准化差值平方和匹配 类似,都是去除了亮度线性变化对相似度计算的影响。可以保证图像和模板同时变亮或变暗k倍时结果不变。
R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ′ ( x + x ′ , y + y ′ ) ) ∑ x ′ , y ′ T ( x ′ , y ′ ) 2 ⋅ ∑ x ′ , y ′ I ( x + x ′ , y + y ′ ) 2 R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I'(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} R(x,y)=∑x′,y′T(x′,y′)2⋅∑x′,y′I(x+x′,y+y′)2∑x′,y′(T(x′,y′)⋅I′(x+x′,y+y′)) -
相关匹配 method=CV_TM_CCOEFF
这类方法将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列).
R ( x , y ) = ∑ x ′ , y ′ ( T ′ ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I(x+x',y+y')) R(x,y)=∑x′,y′(T′(x′,y′)⋅I(x+x′,y+y′))
在这里
T ′ ( x ′ , y ′ ) = T ( x ′ , y ′ ) − 1 / ( w ⋅ h ) ⋅ ∑ x ′ ′ , y ′ ′ T ( x ′ ′ , y ′ ′ ) I ′ ( x + x ′ , y + y ′ ) = I ( x + x ′ , y + y ′ ) − 1 / ( w ⋅ h ) ⋅ ∑ x ′ ′ , y ′ ′ I ( x + x ′ ′ , y + y ′ ′ ) \begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array} T′(x′,y′)=T(x′,y′)−1/(w⋅h)⋅∑x′′,y′′T(x′′,y′′)I′(x+x′,y+y′)=I(x+x′,y+y′)−1/(w⋅h)⋅∑x′′,y′′I(x+x′′,y+y′′) -
标准相关匹配 method=CV_TM_CCOEFF_NORMED
这是 OpenCV 支持的最复杂的一种相似度算法。这里的相关运算就是数理统计学科的相关系数计算方法。具体的说,就是在减去了各自的平均值之外,还要各自除以各自的方差。经过减去平均值和除以方差这么两步操作之后,无论是我们的待检图像还是模板都被标准化了,这样可以保证图像和模板分别改变光照亮不影响计算结果。计算出的相关系数被限制在了 -1 到 1 之间,1 表示完全相同,-1 表示两幅图像的亮度正好相反,0 表示两幅图像之间没有线性关系。
R ( x , y ) = ∑ x ′ , y ′ ( T ′ ( x ′ , y ′ ) ⋅ I ′ ( x + x ′ , y + y ′ ) ) ∑ x ′ , y ′ T ′ ( x ′ , y ′ ) 2 ⋅ ∑ x ′ , y ′ I ′ ( x + x ′ , y + y ′ ) 2 R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} } R(x,y)=∑x′,y′T′(x′,y′)2⋅∑x′,y′I′(x+x′,y+y′)2∑x′,y′(T′(x′,y′)⋅I′(x+x′,y+y′))
通常,随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价). 最好的办法是对所有这些设置多做一些测试实验,以便为自己的应用选择同时兼顾速度和精度的最佳方案.
代码实现:
模板图片
搜索图片
代码:
import cv2
import numpy as np
def model_match(search_image, model_image, threshold):
search_img = cv2.imread(search_image)
model_img_gray = cv2.imread(model_image, 0)#读取模板图片的灰度图
search_img_gray = cv2.cvtColor(search_img, cv2.COLOR_BGR2GRAY)#将搜索图片转化为灰度图
h, w = model_img_gray.shape
res = cv2.matchTemplate(search_img_gray, model_img_gray, cv2.TM_CCOEFF_NORMED)#采用标准相关匹配 方法度量相似度
print(res.shape)
loc = np.where(res>threshold)#返回每一个维度的坐标值, 比如返回值为[1, 2, 3],[1, 2, 4] 表明(1, 1)(2, 2)(3, 4)这三个坐标点的相似度大于阈值
print(loc)
for pt in zip(*loc):#zip(*loc)反解析为坐标值
print(pt)
cv2.rectangle(search_img, pt[::-1], (pt[1] + w, pt[0] + h), (7,249,151), 2) #在搜索图片上绘制矩形框
cv2.imshow('Detected',search_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
search_image = './data/car.jpg'
model_image = './data/car_model.jpg'
threshold = 0.95
model_match(search_image, model_image, threshold)
最终效果