计算机视觉之多模板匹配

简介

计算机视觉第一课opencv(四)保姆级教学

之前说过模糊匹配只是对于单个目标进行匹配,今天我们就来学习一下如何对多个目标进行匹配

一、多目标匹配

对于这个图片我们要匹配下面那个箭头,我们可以发现图中是有两个位置相同的箭头,之前我们说的模糊匹配是寻找匹配值最大的,那两个怎么寻找呢?

1.基本步骤

1.图像准备

模板图像:需要被匹配的目标图像,通常是一个较小的图像块。

输入图像:在其中进行搜索以找到与模板图像相似的多个区域的图像。
2.图像预处理

转换为灰度图像:在进行模板匹配之前,通常需要将输入图像和模板图像转换为灰度图像,因为灰度图像中的像素值仅表示亮度,不受颜色影响,更适合进行匹配。

降噪和增强:根据需要,可以对图像进行降噪处理以提高匹配准确性,或进行增强处理以突出目标特征。
3.执行模板匹配

使用模板匹配算法(如OpenCV中的cv2.matchTemplate()函数)在输入图像中搜索与模板图像相似的区域。

模板匹配算法会生成一个结果图像,其中每个像素的值表示该位置与模板图像的匹配程度。
4.定位匹配区域

使用cv2.minMaxLoc()等函数在结果图像中找到匹配度最高的区域(或多个区域,如果设置了适当的阈值)。

根据匹配位置在原图中绘制矩形框或其他标记,以指示匹配到的目标。
5.处理多个匹配

如果需要匹配多个目标,并且这些目标在图像中可能以不同的尺寸、方向或旋转角度出现,则可能需要使用更复杂的算法,如尺度不变特征变换(SIFT)、加速稳健特征(SURF)或ORB等。

对于简单的多目标匹配,可以通过设置较低的匹配阈值来找到多个匹配区域,并分别处理它们。
6.优化和验证

根据需要调整模板匹配算法的参数(如匹配方法、阈值等),以优化匹配结果。

对匹配结果进行验证,确保它们确实是所需的目标,并排除误匹配。

python 复制代码
# 导入必要的库:cv2用于图像处理,numpy用于数值计算
import cv2
import numpy as np

# 读取原始彩色图像(默认读取为BGR格式,而非RGB)
img_rgb = cv2.imread('beijing.jpg')
# 将彩色图像转为灰度图:模板匹配通常在单通道灰度图上进行,减少计算量和干扰
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
# 读取模板图像:flags=0表示以灰度模式读取(直接得到单通道图像)
template = cv2.imread('jiantou.jpg', flags=0)

# 获取模板的高和宽:shape返回(高, 宽, 通道数),[:2]取前两个值(高h和宽w)
h, w = template.shape[:2]

# 执行模板匹配:在灰度图上滑动模板,计算每个位置的匹配度
# 参数说明:
# - img_gray:待匹配的灰度图像(大图像)
# - template:模板图像(小图像)
# - cv2.TM_CCOEFF_NORMED:匹配方法(归一化相关系数匹配)
# 返回值res:是一个矩阵,每个元素表示模板在对应位置的匹配度(范围[-1,1],1为完美匹配)
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)

# 设定匹配阈值:只有匹配度≥0.9的区域才被认为是有效匹配(过滤低匹配度的干扰)
threshold = 0.9

# 获取所有符合阈值的匹配点坐标:
# np.where(res >= threshold)返回满足条件的索引,格式为(行坐标数组, 列坐标数组)
# 例如:(array([5, 10]), array([3, 7]))表示有两个匹配点,坐标为(5,3)和(10,7)
loc = np.where(res >= threshold)

# 遍历所有匹配点,在原图上绘制矩形框标记
# zip(*loc[::-1])的作用:将坐标从(行,列)转为(列,行)(OpenCV中坐标是(x,y)即列在前,行在后)
for pt in zip(*loc[::-1]):
    # 绘制矩形:
    # - img_rgb:要绘制的图像(原始彩色图,方便直观查看)
    # - pt:矩形左上角坐标(x,y)
    # - (pt[0]+w, pt[1]+h):矩形右下角坐标(左上角x+模板宽,左上角y+模板高)
    # - color=(0,0,255):矩形颜色(BGR格式,这里是红色)
    # - thickness=1:矩形线宽
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), color=(0, 0, 255), thickness=1)

# 显示标记后的图像:第一个参数是窗口名称(空字符串表示默认窗口),第二个参数是图像
cv2.imshow('', img_rgb)
# 等待用户按键输入:0表示无限等待(直到按下任意键关闭窗口)
cv2.waitKey(0)

局限性

只能匹配与模板方向、大小完全一致的目标。如果目标在图像中旋转了(比如箭头方向变了),则无法检测到。那我们就继续探索一下如何去匹配旋转的目标

二、图像旋转

为了解决上述局限性,需要先掌握如何旋转图像。这部分提供了两种旋转方法,用于后续生成不同角度的模板。

python 复制代码
import cv2
import numpy as np

# 方法一:使用numpy的rot90函数旋转(按90度倍数旋转)
img = cv2.imread('../kele.png')  # 读取图像(以彩色模式)
# np.rot90参数说明:
# - 第一个参数:要旋转的图像
# - k:旋转次数(每次90度),k=1表示逆时针转90度,k=-1(或3)表示顺时针转90度
rotated_image1 = np.rot90(img, k=-1)  # 顺时针旋转90度
rotated_image2 = np.rot90(img, k=1)   # 逆时针旋转90度

# 显示原图和旋转后的图像
cv2.imshow('yuantu', img)  # 原图窗口
cv2.imshow('rotated_image1', rotated_image1)  # 顺时针90度窗口
cv2.imshow('rotated_image2', rotated_image2)  # 逆时针90度窗口
cv2.waitKey(0)  # 等待按键
cv2.destroyAllWindows()  # 关闭所有窗口,释放资源

# 方法二:使用OpenCV的rotate函数旋转(更直观,支持固定角度)
rotated_image = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)  # 顺时针90度
rotated_image1 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)  # 逆时针90度
rotated_image2 = cv2.rotate(img, cv2.ROTATE_180)  # 旋转180度

# 显示旋转结果
cv2.imshow('shun90', rotated_image)    # 顺时针90度窗口
cv2.imshow('ni90', rotated_image1)     # 逆时针90度窗口
cv2.imshow('180', rotated_image2)      # 180度窗口
cv2.waitKey(0)  # 等待按键

两种方法对比

  • np.rot90:通过旋转次数控制(k=1/2/3/-1),适合 90 度倍数的旋转,但不够直观。
  • cv2.rotate:直接通过枚举值指定旋转方向(如ROTATE_90_CLOCKWISE),可读性更强,推荐使用。

三、支持旋转角度的模板匹配

结合多目标匹配与旋转的知识,我们就可以结合一下实现对旋转角度的模板匹配

python 复制代码
import cv2
import numpy as np

# 读取原始图像和模板
img_rgb = cv2.imread('beijing.jpg')  # 原始彩色图像
template = cv2.imread('jiantou.jpg', 0)  # 模板图像(以灰度模式读取)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)  # 原始图像转灰度

# 方法二(cv2.rotate)生成不同角度的模板(方法一被注释,原理相同)
template_rot90_clockwise_cv = cv2.rotate(template, cv2.ROTATE_90_CLOCKWISE)  # 顺时针90度
template_rot90_counterclockwise_cv = cv2.rotate(template, cv2.ROTATE_90_COUNTERCLOCKWISE)  # 逆时针90度
template_rot180_cv = cv2.rotate(template, cv2.ROTATE_180)  # 180度

# 定义模板列表:包含原始模板和所有旋转后的模板(需要检测的角度)
templates = [
    template,  # 原始模板(0度)
    template_rot90_clockwise_cv,  # 顺时针90度
    template_rot90_counterclockwise_cv,  # 逆时针90度
    template_rot180_cv  # 180度
]

# 设定匹配阈值:从0.9降低到0.8
# 原因:旋转后的模板与目标的匹配度可能略低(边缘、细节可能有偏差),降低阈值避免漏检
threshold = 0.8

# 遍历每个模板,分别进行匹配
for temp in templates:
    h, w = temp.shape[:2]  # 获取当前模板的高和宽(不同旋转角度的模板尺寸可能变化)
    # 对当前模板执行匹配
    res = cv2.matchTemplate(img_gray, temp, cv2.TM_CCOEFF_NORMED)
    # 获取符合阈值的匹配点坐标
    loc = np.where(res >= threshold)
    # 遍历匹配点,绘制矩形框
    for pt in zip(*loc[::-1]):
        cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 1)

# 显示最终匹配结果
cv2.imshow('Result', img_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()  # 关闭窗口,释放资源

核心逻辑

通过生成模板的多个旋转版本(0°、90° 顺时针、90° 逆时针、180°),分别与原始图像匹配,从而覆盖目标可能的旋转角度。这样即使目标在图像中旋转了,也能被检测到。

相关推荐
AI 嗯啦3 小时前
计算机视觉----opencv----身份证号码识别案例
人工智能·opencv·计算机视觉
星期天要睡觉3 小时前
计算机视觉(opencv)——基于模板匹配的信用卡号识别系统
opencv·计算机视觉
Re_Yang093 小时前
2025年统计与数据分析领域专业认证发展指南
服务器·人工智能·数据分析
西猫雷婶3 小时前
pytorch基本运算-分离计算
人工智能·pytorch·python·深度学习·神经网络·机器学习
数新网络3 小时前
PyTorch
人工智能·pytorch·python
程序员miki3 小时前
RNN循环神经网络(一):基础RNN结构、双向RNN
人工智能·pytorch·rnn·深度学习
自信的小螺丝钉3 小时前
【大模型手撕】pytorch实现LayerNorm, RMSNorm
人工智能·pytorch·python·归一化·rmsnorm·layernorm
深耕AI3 小时前
PyTorch图像预处理:ToTensor()与Normalize()的本质区别
人工智能·pytorch·python
moonsims3 小时前
SKYTRAC-无人机、无人机系统和城市空中交通卫星通信 – BVLOS 和 C2 卫星通信终端和任务服务器
人工智能