OpenCV实战:图像查找

目录

简述

1. 什么是单应性矩阵?

1.1 单应性矩阵的定义

1.2 单应性矩阵的作用

2. OpenCV 图像查找流程

2.1 主要步骤

3. 代码实现:从大图中查找目标图像

4. 代码解释

4.1 读取图像

4.2 特征提取

4.3 特征匹配

4.4 提取匹配点的坐标

4.5 计算单应性矩阵

4.6 透视变换

4.7 添加偏移量并绘制轮廓

4.8 显示结果并释放资源

5. 适用场景

6. 选用不同特征检测器

6.1 改用ORB特征检测

7. 总结


相关阅读

OpenCV:FLANN与暴力特征匹配-CSDN博客

OpenCV:SIFT关键点检测与描述子计算-CSDN博客

OpenCV:SURF、OBR特征检测-CSDN博客

OpenCV:特征检测总结-CSDN博客


简述

在计算机视觉中,图像查找是一项常见任务,比如:

  • 在一张大图中查找 特定目标(如商标、书本封面)。
  • 通过图像匹配实现 目标识别。
  • 通过 特征点匹配 + 透视变换 进行目标对齐。

要实现图像查找,我们通常使用 特征匹配 + 单应性矩阵。本文将详细介绍单应性矩阵的概念,并结合 OpenCV 代码示例展示如何在一张大图中找到目标图像。


1. 什么是单应性矩阵?

1.1 单应性矩阵的定义

单应性矩阵(Homography Matrix)是一种 3×3 变换矩阵,用于描述 两个平面之间的透视变换,它可以将一张图像的 任意四边形区域 映射到另一张图像中的对应区域。数学上,单应性矩阵 H 作用于二维坐标 (x, y),变换为 (x1, y1):

\begin{bmatrix} x_{1}\\ y_{1}\\ 1 \end{bmatrix} = H \times \begin{bmatrix} x\\ y\\ 1 \end{bmatrix}

其中,H 是一个 3×3 矩阵:

H = \begin{bmatrix} h_{11} & h_{12} & h_{13}\\ h_{21} & h_{22} & h_{23}\\ h_{31} & h_{32} & h_{33} \end{bmatrix}

1.2 单应性矩阵的作用

  • 图像查找:从大图中找到目标图像。
  • 透视变换:校正倾斜图像(如文档矫正)。
  • 全景拼接:通过特征点匹配找到两张图片的变换关系,进行无缝拼接。

2. OpenCV 图像查找流程

2.1 主要步骤

  • 特征提取:使用 SIFT 提取两张图像的关键点和描述子。
  • 特征匹配:使用 BFMatcher / FLANN 进行特征点匹配。
  • 单应性计算:使用 cv2.findHomography() 计算单应性矩阵 H。
  • 透视变换:使用 H 进行图像映射,标记目标区域。

3. 代码实现:从大图中查找目标图像

以下这段代码的主要目的是在一张较大的场景图像(box_in_sence)中检测并定位特定目标图像(box)的位置。通过特征提取、特征匹配、计算单应性矩阵以及透视变换等步骤,最终在包含目标图像和场景图像的拼接结果图上绘制出目标图像在场景中的实际位置轮廓。

import cv2
import numpy as np

# 读取图像
box = cv2.imread('D:\\resource\\filter\\logo.jpg')
box_in_sence = cv2.imread('D:\\resource\\filter\\web.png')

# 检查图像是否读取成功
if box is None or box_in_sence is None:
    print("图像读取失败,请检查文件路径。")
    exit(1)

cv2.imshow("box", box)
cv2.imshow("box_in_sence", box_in_sence)

# 创建特征检测器
orb = cv2.SIFT_create()
kp1, des1 = orb.detectAndCompute(box, None)
kp2, des2 = orb.detectAndCompute(box_in_sence, None)

# 暴力匹配
bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)
matches = bf.match(des1, des2)
goodMatches = []

# 筛选出好的描述子
matches = sorted(matches, key=lambda x: x.distance)
for i in range(len(matches)):
    if matches[i].distance < 0.7 * matches[-1].distance:
        goodMatches.append(matches[i])

# 检查匹配的特征点数量是否足够
if len(goodMatches) < 4:
    print("匹配的特征点不足,无法计算单应性矩阵。")
    exit(1)

result = cv2.drawMatches(box, kp1, box_in_sence, kp2, goodMatches, None)

obj_pts, scene_pts = [], []

# 单独保存 obj 和 scene 好的点位置
for f in goodMatches:
    obj_pts.append(kp1[f.queryIdx].pt)
    scene_pts.append(kp2[f.trainIdx].pt)

# 计算单应性矩阵
H, _ = cv2.findHomography(np.float32(obj_pts), np.float32(scene_pts), cv2.RANSAC)

h, w = box.shape[0:2]

pts = np.float32([[0, 0], [0, h], [w, h], [w, 0]]).reshape(-1, 1, 2)
dst = cv2.perspectiveTransform(pts, H).reshape(-1, 2)

# 偏移
for i in range(4):
     dst[i][0] += w

cv2.polylines(result, [np.int32(dst)], True, (0, 255, 0), 3, cv2.LINE_AA)

cv2.imshow("Match", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

▶️运行结果:

小图logo:

 

大图box_in_sence:

特征匹配:

 

4. 代码解释

4.1 读取图像

# 读取图像
box = cv2.imread('D:\\resource\\filter\\logo.jpg')
box_in_sence = cv2.imread('D:\\resource\\filter\\web.png')

# 检查图像是否读取成功
if box is None or box_in_sence is None:
    print("图像读取失败,请检查文件路径。")
    exit(1)

cv2.imshow("box", box)
cv2.imshow("box_in_sence", box_in_sence)

使用 cv2.imread 函数读取目标图像和场景图像,并通过 cv2.imshow 显示这两张图像。

4.2 特征提取

# 创建特征检测器
orb = cv2.SIFT_create()
kp1, des1 = orb.detectAndCompute(box,None)
kp2, des2 = orb.detectAndCompute(box_in_sence,None)

使用 cv2.SIFT_create() 创建 SIFT(尺度不变特征变换)特征检测器。detectAndCompute 方法用于在目标图像和场景图像中检测特征点(kp1 和 kp2)并计算对应的描述子(des1 和 des2)。

4.3 特征匹配

# 暴力匹配
bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)
matches = bf.match(des1, des2)
goodMatches = []

# 筛选出好的描述子
matches = sorted(matches, key=lambda x: x.distance)
for i in range(len(matches)):
    if matches[i].distance < 0.7 * matches[-1].distance:
        goodMatches.append(matches[i])

# 检查匹配的特征点数量是否足够
if len(goodMatches) < 4:
    print("匹配的特征点不足,无法计算单应性矩阵。")
    exit(1)

result = cv2.drawMatches(box, kp1, box_in_sence, kp2, goodMatches, None)

使用 cv2.BFMatcher 创建一个暴力匹配器,使用 cv2.NORM_L1 距离度量和 crossCheck=True 确保双向匹配一致。bf.match 方法找到描述子之间的匹配。对匹配结果按距离排序,筛选出距离小于最长距离 70% 的匹配作为好的匹配。最后使用 cv2.drawMatches 绘制好的匹配结果。

4.4 提取匹配点的坐标

obj_pts, scene_pts = [], []

# 单独保存 obj 和 scene 好的点位置
for f in goodMatches:
    obj_pts.append(kp1[f.queryIdx].pt)
    scene_pts.append(kp2[f.trainIdx].pt)

遍历好的匹配结果,提取目标图像和场景图像中匹配点的坐标。

4.5 计算单应性矩阵

H, _= cv2.findHomography(np.float32(obj_pts), np.float32(scene_pts), cv2.RANSAC)

 使用 cv2.findHomography 函数,结合 RANSAC(随机抽样一致性)算法计算单应性矩阵 H,该矩阵用于将目标图像的点映射到场景图像中。

4.6 透视变换

h, w = box.shape[0:2]

pts = np.float32([[0, 0], [0, h], [w, h], [w, 0]]).reshape(-1, 1, 2)
dst = cv2.perspectiveTransform(pts, H).reshape(-1, 2)

 获取目标图像的高度 h 和宽度 w,定义目标图像的四个角点 pts。使用 cv2.perspectiveTransform 函数通过单应性矩阵 H 对四个角点进行透视变换,得到它们在场景图像中的对应位置 dst。

4.7 添加偏移量并绘制轮廓

# 加上偏移量
for i in range(4):
    dst[i][0] += w

cv2.polylines(result, [np.int32(dst)], True, (0, 255, 0), 3, cv2.LINE_AA)

 为 dst 中的 x 坐标添加目标图像的宽度 w 作为偏移量,是为了在拼接图像中正确定位。使用 cv2.polylines 函数在匹配结果图像 result 上绘制变换后四个角点构成的四边形,颜色为绿色,线宽为 3 像素。

4.8 显示结果并释放资源

cv2.imshow("Match", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

显示最终的匹配结果图像,等待用户按下任意键后关闭所有窗口。 


5. 适用场景

应用场景说明
图像查找在大图中找到小目标(如 Logo 识别)
目标识别识别特定物体,如商标、书籍封面
物体跟踪视频中跟踪特定目标
全景拼接通过单应性矩阵拼接多张图像

6. 选用不同特征检测器

特征检测方法适用场景计算速度
SIFT高精度匹配较慢
ORB实时应用

上述代码中的特征提取部分使用了 SIFT(尺度不变特征变换)算法,除此之外,还有很多其他的特征提取方法可供选择,以下为你详细介绍常见的方法及其代码示例: 

6.1 改用ORB特征检测

ORB 是一种快速且高效的特征提取算法,结合了 FAST 特征点检测和 BRIEF 描述子,并且具有旋转不变性。与 SIFT 相比,ORB 的计算速度更快,适合对实时性要求较高的场景。

import cv2
import numpy as np

# 读取图像
box = cv2.imread('D:\\resource\\filter\\logo.jpg')
box_in_sence = cv2.imread('D:\\resource\\filter\\web.png')

# 创建 ORB 特征检测器
orb = cv2.ORB_create()

# 检测特征点并计算描述子
kp1, des1 = orb.detectAndCompute(box, None)
kp2, des2 = orb.detectAndCompute(box_in_sence, None)

# 由于 ORB 使用的是二进制描述子,匹配时使用汉明距离
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)

# 后续的匹配筛选、单应性矩阵计算等步骤与原代码类似
# ...

7. 总结

单应性矩阵可用于透视变换,在大图中找到目标图像。SIFT/ORB + FLANN/BFMatcher 可以进行高效的特征匹配。cv2.findHomography() 计算目标的变换矩阵,找到在大图中的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值