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

相关推荐
金智维科技官方12 分钟前
制造业如何用Ki-AgentS智能体平台实现设备巡检自动化?
大数据·运维·人工智能
stereohomology13 分钟前
大模型看大模型:推理Token的能耗用电量比对
人工智能
Hello world.Joey14 分钟前
Transformer解读
人工智能·深度学习·神经网络·自然语言处理·nlp·aigc·transformer
机器之心19 分钟前
Sand.ai开源发布MagiCompiler:突破局部编译界限,定义训推性能上限
人工智能·openai
KieranYin32 分钟前
AI编程 | 概念
人工智能
飞Link42 分钟前
LangChain Core 架构深度剖析与 LCEL 高阶实战
人工智能·架构·langchain
liangdabiao44 分钟前
Seedance 2.0 Skill 一键写好剧本上线了coze的技能商店了,免费
人工智能
喵飞云智AI研发社1 小时前
本土AI企业发力 喵飞科技AIGC开年分享会助力天津数字化转型
人工智能·科技·aigc
于过1 小时前
AgentMiddleware is All You Need
人工智能·langchain·llm
LLM精进之路1 小时前
频域+特征融合:深度学习的黄金组合,顶会顶刊的快速通道
人工智能·计算机视觉·目标跟踪