模板匹配

1. 模板匹配步骤

  模板匹配是一种基于图像的技术,用于在图像中寻找与给定模板图像相似的部分。由于模板图像的尺寸小于待匹配图像的尺寸,同时又需要比较两幅图像的每一个像素的灰度值,因此常采用在待匹配图像中选择与模板相同的尺寸的滑动窗口,通过比较滑动窗口与模板的相似程度,判断待匹配图像中是否含有与模板图像相同的内容。

以下是模板匹配的基本步骤:

  1. 准备模板和目标图像:首先,需要准备一个模板图像(即要在目标图像中寻找的图案)和一个目标图像(即待搜索的图像)。

  2. 选择匹配方法:选择适当的匹配方法来度量模板和图像局部区域之间的相似度。常用的匹配方法包括平方差匹配、归一化平方差匹配、相关系数匹配等。

  3. 滑动模板:在目标图像上滑动模板,并在每个位置上应用所选的匹配方法计算相似度得分。

  4. 找到最佳匹配位置:根据相似度得分找到目标图像中与模板最匹配的位置。

  5. 绘制结果:可选的步骤,可以将最佳匹配位置标记在目标图像上,并进行可视化展示。

2. 常见的模板匹配方法

  opencv中的标志参数与方法名称如下:

标志参数
简记 方法名称
TM_SQDIFF 0 平方差匹配法
TM_SQDIFF_NORMED 1 归一化平方差匹配法
TM_CCORR 2 相关匹配法
TM_CCORR_NORMED 3 归一化相关匹配法
TM_CCOEFF 4 系数匹配法
TM_CCOEFF_NORMED 5 归一化相关系数匹配法

3.  公式及其说明

  T表示模板图像,I表示原始图像。

  TM_SQDIFF:平方差匹配法,公式如下:

 

  计算了图像中每个位置的像素值与模板对应位置的像素值之间的差的平方,并对所有差值求和。值越小表示匹配程度越高。值为0时,表示完全匹配。

  TM_SQDIFF_NORMED:归一化平方差匹配法,公式如下:

  将平方差方法进行归一化,使得输入结果归一化到0~1,当模板与华东窗口完全匹配时,计算值为0.

  TM_CCORR:相关匹配法,公式如下:

  采用模板和图像间的乘法操作,值越大,匹配效果越好,0表示最坏匹配结果。

  TM_CCORR_NORMED:归一化相关匹配法,公式如下:

  结果为0~1范围,完全匹配时,值为1,完全不匹配时,值为0.

  TM_CCOEFF:系数匹配法,公式如下:

 

  其中,

  这种方法是将相关匹配法对模板减去均值的结果和原始图像减去均值的结果进行匹配,可以很好的解决模板图像和原始图像之间由于亮度不同而产生的影响。值可以为负数,值越大匹配越好,越小,匹配越差。

  TM_CCOEFF_NORMED:归一化相关系数匹配法,公式如下:

  值为-1~1,为1时表示完全匹配,为-1时,表示完全不匹配。TM_CCOEFF_NORMED也是用得最常用的一种方法。

4.  python代码示例

  原图如下:

  模板图如下(是从上图中裁剪下来的最右边的那个格子。)

   现在使用模板匹配TM_CCOEFF_NORMED方法寻找最优的匹配位置。

import cv2
import numpy as np

# 读取原始图像和模板图像
original_image = cv2.imread(r'example.png', 1)
gray_image=cv2.cvtColor(original_image,cv2.COLOR_BGR2GRAY)
template = cv2.imread(r'template.png', 0)#模板图以灰度读取
template_height, template_width = template.shape[:2]# 获得模板图像的高度和宽度
result = cv2.matchTemplate(gray_image, template, cv2.TM_CCOEFF_NORMED)# 使用 TM_CCOEFF_NORMED 方法进行模板匹配
threshold = 0.85# 设置匹配阈值,这里设定为0.85
locations = np.where(result >= threshold)# 获取匹配结果大于阈值的位置
#获取最优
best_score = -np.inf
best_loc = None
for loc in zip(*locations[::-1]):
    score = result[loc[1], loc[0]]  # loc[1] 对应行坐标,loc[0] 对应列坐标
    if score > best_score:
        best_score = score
        best_loc = loc

print("Best score:", best_score)#0.99999994
print("Best location:", best_loc)# (237, 83)左上角x,y
if best_loc is not None:
    bottom_right = (best_loc[0] + template_width, best_loc[1] + template_height)
    cv2.rectangle(original_image, best_loc, bottom_right, (0,255,0), 1)#1表示绘制线条的宽度
    cv2.imwrite('./test.png',original_image)

  匹配结果保存的图如下:

  获取全部满足阈值的代码及匹配结果如下:

import cv2
import numpy as np

original_image = cv2.imread(r'example.png', 1)
gray_image=cv2.cvtColor(original_image,cv2.COLOR_BGR2GRAY)
template = cv2.imread(r'template.png', 0)
template_height, template_width = template.shape[:2]# 获得模板图像的高度和宽度
result = cv2.matchTemplate(gray_image, template, cv2.TM_CCOEFF_NORMED)# 使用 TM_CCOEFF_NORMED 方法进行模板匹配
threshold = 0.85# 设置匹配阈值,这里设定为0.85
locations = np.where(result >= threshold)# 获取匹配结果大于阈值的位置
for loc in zip(*locations[::-1]):# 在原始图像中标记匹配的位置
    bottom_right = (loc[0] + template_width, loc[1] + template_height)
    cv2.rectangle(original_image, loc, bottom_right, (0,255,0), 1)
cv2.imwrite('./test.png',original_image)

  仔细观察,发现这个图比上面的获得最优位置的匹配图绘制的绿色矩形框的线条变粗了,这是因为匹配过程中,满足阈值的匹配结果很多,也就是说图中并不只是三个位置匹配到了,对于同一个位置,匹配的多个结果矩形框之间位置挨得很近,所以绘制绿色矩形框就呈现粗的现象。实际上在for循环中打印loc就知道绘制了多少次了。

 

小结:如果匹配不需要那么严格,TM_CCOEFF_NORMED模板匹配可以通过调小阈值来达到要求,但是由于模板匹配是由公式计算来完成的,对于背景差异很大,尽管前景目标一致,也很难匹配到。就比如上图中如果这个棋子在图中白色格子也出现了,可能就匹配不到了。

 

  若存在不足或错误之处,欢迎指出与评论,谢谢!

posted @ 2024-04-20 18:33  wancy  阅读(232)  评论(0编辑  收藏  举报