图像处理模板匹配-Opencv实现

模板匹配

模板匹配顾名思义就是给定一幅影像(模板)然后在另一幅 图像中寻找这个模板的操作。它是一种用来在一幅大图中 寻找模板图像位置的方法。在OpenCV中有cv2.matchTemplate() 函数供我们方便调用。它的工作原理与2D卷积函数一样, 将模板图像在输入图像(大图)上滑动,并且在每一个位置对 模板图像和与其对应的输入图像的子区域进行比较。返回 的结果是一个灰度图像,每一个像素值表示了此区域与模板 的匹配程度。

匹配步骤

1.输入原图像(I)和模板图像(T)。在原图像中我们希望找到一块和模板匹配的区域
2.通过将模板在原图像上滑动来寻找最匹配的区域。 这里所谓的滑动是指模板图像块一次移动一个像素(从左往右,从上往下)。 在每一个位置,都进行一次度量计算,来判断该像素对应的原图像的特定区域 与模板图像的相似度。
3.对于模板T覆盖在I上的每个位置,把上一步计算的度量值保存在结果图像矩阵R中。 在R中每个位置都包含对应的匹配度量值。
4.在结果图像矩阵中寻找最值(最大或最小,根据算法不同而不同)。最值所对应的像素的位置即认为是最高的匹配。 以该点为顶点,长宽和模板大小图像一样的矩阵认为是匹配区域。在OpenCV中可以用cv2.minMaxLoc()函数获得最值坐标。

匹配算法

上面说了模板匹配的核心步骤。可以发现在步骤中有个核心问题。 那就是如何度量匹配程度,如何进行度量计算。在OpenCV中提供了 6中不同方法。这里就以这6种算法为基础介绍匹配算法。在下列公式中, T(x,y)表示模板,I(x,y)表示原图像,R(x,y)表示模板与原图相似度函数。 x、y表示某个像素,x’、y’表示循环变量,在模板那么大的范围内进行循环。
下面给出两个算法公式:
在这里插入图片描述

Opencv实现

如果输入图像大小是(W × H),模板大小是(w × h),输出结果大小就是(W-w+1, H-h+1)。 当得到这幅图之后,就可以使用函数cv2.minMaxLoc()来找到其中最小值和最大值位置了。 第一个值为矩形左上角的点(位置),(w,h)为模板矩形的宽和高。这个矩形就是找到的模板区域了。 下面是实例代码:

单个对象匹配


import numpy as np
import cv2
from matplotlib import pyplot as plt
# 依次读取原图与模板
plt.rcParams["font.family"] = "SimHei"#直接修改配置字典,设置默认字体
img = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/apple.png")
template = img [100:200,0:100,:]
plt.subplot(131),plt.imshow(template[:,:,::-1])
plt.axis("off"),plt.title("模板图像")
#依次获取模板的宽高,用于后续绘制矩形
h = template.shape[0]
w = template.shape[1]
"#调用匹配函数"
# 第一个参数是原图
# 第二个参数是模板
# 第三个参数是匹配算法
# 返回的结果是一个二维的float类型的数组,大小为W-w+1 * H-h+1
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF)

# 获取返回结果中最值及其在res中的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# 构造矩形并在原图上绘制
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img, top_left, bottom_right, (255, 255, 0), 5)

# 在使用Matplotlib显示之前,需要调整BGR的顺序
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
img = cv2.merge((r, g, b))

# 打印相关信息
"可以观察到图像,模板,R矩阵的大小符合公式"
print (img.shape,template.shape,res.shape,res.dtype,cv2.minMaxLoc(res))

# 利用Matplotlib绘图对比
plt.subplot(132), plt.imshow(img)
plt.axis("off"),plt.title("原图")
plt.subplot(133), plt.imshow(res, cmap='gray')
#匹配矩阵R的信息,最亮的点认为最匹配的点
plt.axis("off"),plt.title("R图像")
plt.show()

在这里插入图片描述

多个图像匹配

在上面的例子中,原图中只出现了一次模板中的对象,但有时更有可能一幅图像中出现多个模板对象,这时就需要多对象匹配了。 在OpenCV中cv2.minMaxLoc()只会返回最值的位置。所以显然现在不能使用这个函数了。我们需要设置一个阈值,当R值大于这个 阈值时,认为是模板对象,否则不是。所以这里显然用标准化的方法更加合适,否则我们无法确定阈值。代码如下:

import cv2
from matplotlib import pyplot as plt
import numpy as np

# 依次读取原图与模板
img = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/house.jpg")
template = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/house1.jpg")

# 依次获取模板的宽高,用于后续绘制矩形
h = template.shape[0]
w = template.shape[1]

"调用匹配函数"
# 第一个参数是原图
# 第二个参数是模板
# 第三个参数是匹配算法
# 返回的结果是一个二维的float类型的数组,大小为W-w+1 * H-h+1
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

# 设定阈值
threshold = 0.8

# 从res中提取大于阈值的像素的位置
loc = np.where(res >= threshold)

# 遍历不同位置,绘制矩形
# 在函数调用中使用*list/tuple,表示将list/tuple分开,作为位置参数传递给对应函数(前提是对应函数支持不定个数的位置参数)
# 切片[::-1]是将列表或字符倒过来
for pt in zip(*loc[::-1]):
    cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)

# 在使用Matplotlib显示之前,需要调整BGR的顺序
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
img = cv2.merge((r, g, b))

# 利用Matplotlib绘图对比
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.subplot(122), plt.imshow(img, cmap='gray')
plt.show()

左图是R图像,右图是匹配图像
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#模板匹配 import cv2 as cv import numpy as np def template_demo(): dog = cv.imread("E:/opencv/picture/dog.jpg") dog_nose = cv.imread("E:/opencv/picture/nose.jpg") cv.imshow("dog",dog) result = cv.matchTemplate(dog,dog_nose,cv.TM_CCORR_NORMED) h,w =dog_nose.shape[:2] min_val,max_val,min_loc,max_loc=cv.minMaxLoc(result) pt1 = max_loc pt2 = (pt1[0]+w,pt1[1]+h) cv.rectangle(dog,pt1,pt2,(0,255,0),2) cv.imshow("match",dog) print(result) #src = cv.imread("E:/opencv/picture/dog.jpg") #cv.imshow("inital_window",src) template_demo() cv.waitKey(0) cv.destroyAllWindows() 分析: 模板匹配通常用于目标检测。本文我们检测狗图片的鼻子。 • 我们需要两个主要组件: 1. 源图像(I):我们期望找到与模板图像匹配的图像 2. 模板图像(T):将与模板图像进行比较的补丁图像 1. result = cv.matchTemplate(dog,dog_nose,cv.TM_CCORR_NORMED) void cv::matchTemplate( cv::InputArray image, // 待匹配图像W*H cv::InputArray templ, // 模板图像,和image类型相同, 大小 w*h cv::OutputArray result, // 匹配结果图像, 类型 32F, 大小 (W-w+1)*(H-h+1) int method // 用于比较的方法 ); 其中method有: TM_SQDIFF_NORMED匹配数值越低表示匹配效果越好 TM_CCORR_NORMED,TM_CCOEFF_NORMED匹配数值越大表示匹配效果越好 result参数:(保存各个点匹配结果的参数) 模板匹配函数cvMatchTemplate依次计算模板与待测图片的重叠区域的相似度,并将结果存入映射图像result当中,也就是说result图像中的每一个点的值代表了一次相似度比较结果 模板在待测图像上每次在横向或是纵向上移动一个像素,并作一次比较计算 我们可以通过cv.minMaxLoc函数来确定结果矩阵的最大值和最小值的位置。 2. cv.minMaxLoc(result) 返回result数值中最小值以及最小值所在的位置和最大值以及最大值所在的位置。 3. 当知道哪个点匹配度最高时这个时候我们需要用矩阵把模板给标出来 C++: void rectangle(Mat& img, Point pt1,Point pt2,const Scalar& color, int thickness=1, int lineType=8, int shift=0) 第一个参数:要在哪个图像上画? 第二个参数:矩阵的左上角点坐标 第三个参数:矩阵的右下角点坐标 第四个参数:颜色
好的,以下是使用 Python OpenCV 进行模板匹配的基本流程: 1. 读取模板图像和待匹配图像: ```python import cv2 # 读取模板图像和待匹配图像 template = cv2.imread('template.png', cv2.IMREAD_GRAYSCALE) image = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE) ``` 2. 创建 linemod 模型: ```python # 创建 linemod 模型 num_modalities = 1 threshold = 90 detector = cv2.linemod.getDefaultLINE() detector = cv2.linemod.createLINE(detector, num_modalities, threshold) ``` 3. 添加模板: ```python # 添加模板到 linemod 模型中 template_id = 0 template_modality = 0 detector.addTemplate(template, 'template', template_modality, [template_id]) ``` 4. 进行模板匹配: ```python # 进行模板匹配 matches = detector.match(image, threshold, [cv2.linemod.DEFAULT_NORM]) ``` 5. 处理匹配结果: ```python # 处理匹配结果 for match in matches: template_id, _, (x, y) = match print('Template ID: {}, Location: ({}, {})'.format(template_id, x, y)) ``` 完整代码如下: ```python import cv2 # 读取模板图像和待匹配图像 template = cv2.imread('template.png', cv2.IMREAD_GRAYSCALE) image = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE) # 创建 linemod 模型 num_modalities = 1 threshold = 90 detector = cv2.linemod.getDefaultLINE() detector = cv2.linemod.createLINE(detector, num_modalities, threshold) # 添加模板到 linemod 模型中 template_id = 0 template_modality = 0 detector.addTemplate(template, 'template', template_modality, [template_id]) # 进行模板匹配 matches = detector.match(image, threshold, [cv2.linemod.DEFAULT_NORM]) # 处理匹配结果 for match in matches: template_id, _, (x, y) = match print('Template ID: {}, Location: ({}, {})'.format(template_id, x, y)) ``` 注意,这只是一个简单的示例。在实际应用中,可能需要对 linemod 模型进行更复杂的配置,以获得更好的匹配效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值