opencv的模板匹配(Template Matching)学习笔记

1、基本应用(平移无形变场合)

OpenCV 提供了多种模板匹配方法,如平方差匹配(cv2.TM_SQDIFF)、标准化平方差匹配(cv2.TM_SQDIFF_NORMED)、相关匹配(cv2.TM_CCORR)、归一化相关匹配(cv2.TM_CCORR_NORMED)、相关系数匹配(cv2.TM_CCOEFF)和归一化相关系数匹配(cv2.TM_CCOEFF_NORMED)等。这些方法的基本思想是将模板图像在目标图像上滑动(平移),在每个位置计算模板图像和目标图像子区域之间的相似度。不同的方法采用不同的相似度度量方式。例如,平方差匹配是计算模板和目标子区域之间像素差的平方和,值越小表示匹配度越高;相关系数匹配是计算模板和目标子区域之间的相关系数,值越大表示匹配度越高。


归一化相关匹配(cv2.TM_CCORR_NORMED)的demo:

python 复制代码
import cv2

template = cv2.imread('template.jpg')  # 模板图像
target = cv2.imread('target.jpg')  # 目标图像

result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)   # 匹配方法选择归一化相关系数
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)   # 获取匹配结果的最大值和对应坐标
top_left = max_loc  # 假设使用的是归一化相关系数匹配方法
bottom_right = (top_left[0] + template.shape[1], top_left[1] + template.shape[0])
cv2.rectangle(target, top_left, bottom_right, (0, 0, 255), 2)  # 标注矩形框
cv2.imshow('Matched Image', target)
cv2.waitKey(0)
cv2.destroyAllWindows()
复制代码
目标图片:

模板图片:

运行结果:


2、当模板图片存在大小和角度偏差

如果模板和目标图片存在一定程度的尺寸和角度偏差,可以使用基于特征点的匹配方法。OpenCV 提供了多种特征检测和描述算法,如 SIFT(尺度不变特征变换)、SURF(加速稳健特征)、ORB(定向快速和旋转不变BRIEF)等。这些算法能够检测出图像中的关键点,并生成对应的描述子,然后通过匹配描述子来找到相似的特征点,从而实现对模板的定位。


SIFT 特征匹配方法

比如,当模板图片存在尺寸和角度的偏差(原目标图片不变):

SIFT(尺度不变特征变换)是一种经典的计算机视觉算法,核心目标是从图像中提取具有尺度、旋转、光照不变性的局部特征点,用于图像匹配、目标识别、全景拼接等场景,由 David Lowe 于 2004 年提出。其核心逻辑是 "让特征点不受图像缩放、旋转、亮度变化的影响,从而稳定识别同一物体 / 场景",

以下是使用 SIFT 特征匹配方法的实现步骤:

python 复制代码
import cv2
import numpy as np

template = cv2.imread('template2.jpg', cv2.IMREAD_GRAYSCALE)  # 模板图像,灰度模式读取
target = cv2.imread('target.jpg', cv2.IMREAD_GRAYSCALE)  # 目标图像,灰度模式读取

sift = cv2.SIFT_create()  # 创建SIFT特征提取器
kp1, des1 = sift.detectAndCompute(template, None)  # 模板图像的特征点和描述子
kp2, des2 = sift.detectAndCompute(target, None)    # 目标图像的特征点和描述子

FLANN_INDEX_KDTREE = 1   # FLANN算法的索引类型
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)   # FLANN算法的索引参数
search_params = dict(checks=50)   # FLANN算法的搜索参数
flann = cv2.FlannBasedMatcher(index_params, search_params)   # 创建FLANN匹配器
matches = flann.knnMatch(des1, des2, k=2)   # 使用FLANN算法进行匹配

good_matches = []   # 存储好的匹配点
for m, n in matches:
    if m.distance < 0.75 * n.distance:   # 过滤掉不好的匹配点
        good_matches.append(m)
if len(good_matches) > 4:
    src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)   # 模板图像的特征点
    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)   # 目标图像的特征点
    H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)   # 使用RANSAC算法计算单应性矩阵

img_matches = cv2.drawMatches(template, kp1, target, kp2, good_matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)   # 绘制匹配结果
cv2.imshow('Matches', img_matches)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果:

进一步的,绘制出模板在目标图片中的位置

python 复制代码
h, w = template.shape  # 模板图像的尺寸
pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)   # 模板图像的四个角点
dst = cv2.perspectiveTransform(pts, H)   # 将模板图像的四个角点变换到目标图像中
target = cv2.polylines(target, [np.int32(dst)], True, (0, 255, 0), 3, cv2.LINE_AA)   # 在目标图像中绘制变换后的模板图像
cv2.imshow('Located Template', target)
cv2.waitKey(0)
cv2.destroyAllWindows()

SURF方法

SURF加速稳健特征和 SIFT(尺度不变特征变换)类似,均为计算机视觉中用于特征检测与匹配的经典算法,核心目标是从图像中提取具有 "尺度不变性""旋转不变性" 的关键特征(如角点、边缘交点等),用于图像匹配、目标识别、拼接等场景,但 SURF 通过算法优化实现了更快的计算速度。 但是从opencv3.4以后SURF算法并不是直接包含在标准的 OpenCV 库中,而是作为额外的模块提供。可以使用ORB算法作为取代。


ORB方法

重点学习ORB方法。

ORB(Oriented FAST and Rotated BRIEF)是一种高效的特征检测与描述算法,专为解决实时场景下的图像特征提取需求设计,核心是结合两种经典算法的优势并弥补其缺陷,在计算机视觉领域(如目标跟踪、图像拼接、SLAM)应用广泛。

1. 核心设计逻辑:解决 "速度" 与 "旋转不变性" 痛点

ORB 的诞生源于对两种基础算法的改进:

  • FAST(Features from Accelerated Segment Test) :一种快速角点检测算法,通过比较像素与周围邻域像素的灰度差异来判断是否为角点,优势是速度极快 ,但缺点是不具备旋转不变性(图像旋转后特征点可能无法匹配),且特征点的 "方向"(主方向)未定义。
  • BRIEF(Binary Robust Independent Elementary Features) :一种二进制特征描述子,通过随机选取图像局部区域的像素对、比较灰度值生成 0/1 二进制串,优势是存储量小、匹配速度快 ,但同样缺乏旋转不变性(旋转后像素对的相对位置变化,导致描述子失效)。

ORB 的核心思路就是:用 "带方向的 FAST"(Oriented FAST)解决检测阶段的旋转问题,用 "旋转后的 BRIEF"(Rotated BRIEF)解决描述阶段的旋转问题,同时保留两者的速度优势。

2. 关键步骤解析

ORB 算法主要分为 "特征检测" 和 "特征描述" 两步:

(1)特征检测:Oriented FAST(带方向的角点检测)
  • 第一步:快速角点筛选沿用 FAST 的核心逻辑:在图像中任选像素 p,以 p 为中心取半径 3 像素的圆(共 16 个邻域像素),若存在连续 12 个(或更多)邻域像素的灰度值与 p 的灰度值差异超过阈值(排除噪声),则 p 为候选角点。(优化:通过先检测圆上 4 个正交像素(上下左右),若其中 3 个不满足差异阈值,直接排除 p,进一步提升速度)。

  • 第二步:计算特征点主方向(解决旋转不变性) 为每个 FAST 角点定义 "主方向":以角点为中心,取一个 31×31 的邻域,计算该邻域内所有像素的灰度质心(灰度加权的坐标均值);将 "角点坐标" 与 "质心坐标" 的连线方向,作为该角点的主方向。这一步让特征点具备了 "方向属性",后续描述子可围绕该方向旋转,确保旋转后特征一致。

(2)特征描述:Rotated BRIEF(旋转后的二进制描述子)
  • **第一步:预定义 "旋转不变的像素对集"**BRIEF 的缺陷是像素对随机选取,旋转后相对位置变化;ORB 则预先生成一组 "固定的像素对模板",并根据特征点的主方向 θ,将所有像素对围绕特征点旋转 θ 角,得到 "旋转后的像素对"。(优化:ORB 通过统计学习筛选出 128 对 "相关性低、区分度高" 的像素对,最终生成 128 位二进制描述子,平衡匹配精度与速度)。

  • 第二步:生成二进制描述子对旋转后的每对像素((x1,y1) 和 (x2,y2)),比较两者灰度值:若 x1 灰度>x2 灰度,描述子对应位记为 1,否则记为 0;最终生成 128 位二进制串,即 ORB 特征描述子。

3. 核心优势与应用场景
优势:
  • 高效性:检测(FAST)和描述(二进制)均为轻量计算,速度远超 SIFT、SURF 等传统算法,可满足实时需求(如嵌入式设备、实时跟踪)。
  • 鲁棒性 :通过 "主方向定义" 和 "旋转像素对",具备旋转不变性;同时对光照变化、尺度变化(通过图像金字塔实现)有一定抵抗能力。
  • 无专利限制:SIFT、SURF 受专利保护,ORB 为开源算法,可自由商用。
典型应用:
  • 实时目标跟踪(如视频中跟踪特定物体);
  • 图像拼接(如全景图合成,匹配不同图像的重叠区域);
  • SLAM(同步定位与地图构建,如无人机、机器人的环境感知);
  • 图像匹配(如物体识别、手势识别中的特征比对)。

简言之,ORB 是 "速度" 与 "鲁棒性" 平衡的经典特征算法,是实时计算机视觉任务中的核心工具之一。

demo:

python 复制代码
import cv2
import numpy as np

# 1. 读取图像
template = cv2.imread('template2.jpg', cv2.IMREAD_GRAYSCALE)
target = cv2.imread('target.jpg', cv2.IMREAD_GRAYSCALE)

# 确保图像读取成功
if template is None or target is None:
    raise ValueError("无法读取图像,请检查文件路径是否正确")

# 2. 初始化ORB检测器并提取特征
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(template, None)  # 模板特征
kp2, des2 = orb.detectAndCompute(target, None)    # 目标图像特征

# 3. 特征匹配与筛选(保留优质匹配)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)  # 按距离排序(距离越小越优)

# 筛选前N个优质匹配(可根据实际情况调整,建议10-50个)
good_matches = matches[:30]

# 4. 准备单应性矩阵计算所需的点集
# 获取匹配对对应的坐标(模板点:pts1,目标点:pts2)
pts1 = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
pts2 = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)

# 5. 计算单应性矩阵(使用RANSAC算法剔除异常值)
# 单应性矩阵H可将模板坐标映射到目标图像坐标
H, mask = cv2.findHomography(pts1, pts2, cv2.RANSAC, 5.0)
matches_mask = mask.ravel().tolist()  # 标记有效匹配点

# 6. 定义模板图像的边界框(四个角点)
h, w = template.shape  # 模板的高和宽
template_corners = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)

# 7. 将模板边界框投影到目标图像中
if H is not None:  # 确保单应性矩阵计算成功
    target_corners = cv2.perspectiveTransform(template_corners, H)
    # 转换为整数坐标(便于绘制)
    target_corners = np.int32(target_corners)
else:
    raise Exception("单应性矩阵计算失败,可能匹配点不足或质量太差")

# 8. 绘制结果(在彩色目标图像上绘制)
target_color = cv2.cvtColor(target, cv2.COLOR_GRAY2BGR)
# 绘制投影后的模板边界框(红色,线宽2)
cv2.polylines(target_color, [target_corners], isClosed=True, color=(0, 0, 255), thickness=2)

# 9. 绘制带有效匹配标记的匹配图(可选,用于验证匹配质量)
img_matches = cv2.drawMatches(
    template, kp1, target_color, kp2, good_matches, None,
    matchColor=(0, 255, 0),  # 有效匹配线:绿色
    singlePointColor=None,
    matchesMask=matches_mask,  # 只显示有效匹配点
    flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS
)

# 10. 显示结果
cv2.imshow('Template Matching Result (Target Image)', target_color)
cv2.imshow('Good Matches', img_matches)

# 等待按键关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()

# 可选:保存结果图像
cv2.imwrite('target_with_matching_box.jpg', target_color)
cv2.imwrite('good_matches.jpg', img_matches)

4、 调整参数,改进匹配结果

还是上面的demo代码,换了两张图后运行:

看得出,完全没有匹配得上。

将代码中的这一行:

python 复制代码
orb = cv2.ORB_create()

修改为下面内容后再次运行:

python 复制代码
orb = cv2.ORB_create(nfeatures=2000, scaleFactor=1.1, patchSize=51)

匹配效果大为改善。

https://blog.csdn.net/xulibo5828/article/details/155229381

相关推荐
美林数据Tempodata43 分钟前
李飞飞最新论文深度解读:从语言到世界,空间智能将重写AI的未来十年
人工智能·ai·空间智能
东哥说-MES|从入门到精通1 小时前
数字化部分内容 | 十四五年规划和2035年远景目标纲要(新华社正式版)
大数据·人工智能·数字化转型·mes·数字化工厂·2035·十四五规划
小殊小殊1 小时前
DeepSeek为什么这么慢?
人工智能·深度学习
极客BIM工作室1 小时前
从静态到动态:Sora与文生图潜在扩散模型的技术同异与AIGC演进逻辑
人工智能·aigc
松果财经1 小时前
长沙的青年友好,五年见“城”心
人工智能
秋邱1 小时前
智启未来:AGI 教育融合 × 跨平台联盟 × 个性化空间,重构教育 AI 新范式开篇:一场 “教育 ×AI” 的范式革命
人工智能·python·重构·推荐算法·agi
黑客思维者1 小时前
ChatGPT软件开发提示词库:开发者常用150个中文提示词分类与应用场景设计
人工智能·chatgpt·提示词·软件开发
IT_陈寒1 小时前
React性能优化:这5个Hooks技巧让我减少了40%的重新渲染
前端·人工智能·后端
七牛云行业应用1 小时前
解决 AI 视频角色闪烁与时长限制:基于即梦/可灵的多模型 Pipeline 实战
人工智能·音视频·ai视频