OpenCV中的特征匹配(Feature Matching)

Posted 程序媛一枚~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV中的特征匹配(Feature Matching)相关的知识,希望对你有一定的参考价值。

这篇博客将介绍如何使用OpenCV将一个图像中的特征与其他图像中的特征进行匹配。通过SIFT等关键点检测、蛮力匹配器和 FLANN KNN匹配来实现。

  • Brute-Force matcher 蛮力匹配器
  • FLANN Fast Approximate Nearest Neighbor Search Library 快速最近邻逼近搜索函数库
  • KNN K Nearest Neighbors K近邻

1. 效果图

要进行匹配的俩张原始图如下:
SIFT关键点检测+Knn近邻及蛮力匹配效果图如下:
ORB关键点检测及蛮力匹配效果图如下:
SIFT关键点检测+Knn近邻匹配效果图如下:

2. 原理

蛮力匹配器很简单。它采用第一个集合中一个特征的描述符,并通过一些距离计算与第二个集合中的所有其他特征匹配。返回最近的一个或者k个匹配符。

  • cv2.BFMatcher() 创建BFMatcher对象;

参数一:normType,指定要使用的距离测量,默认cv2.NORM_L2,适用于SURF、SIFT;对于基于二进制字符串的描述符,如ORB、BRIENT、BRISK等,应使用cv2.NORM_HAMMING,它使用HAMMING距离作为度量。如果ORB使用WTA_K==3或4,则应使用cv2.NORM_HAMMING2。


参数二:交叉检查bool变量,默认false。如果为true,Matcher只返回那些具有值(i,j)的匹配,这样集合A中的第i个描述符将集合B中的第j个描述符作为最佳匹配。

  • BFMatcher.match() 返回最佳匹配;
  • BFMatcher.knnMatch() 返回k个最佳匹配,其中k由用户指定。
  • cv2.drawKeypoints() 绘制关键点;
  • cv2.drawMatches() 绘制匹配项。它水平堆叠两个图像,并从第一个图像到第二个图像绘制线条,显示最佳匹配。
  • cv2.drawMatchesKnn() 它绘制所有k个最佳匹配。如果k=2,它将为每个关键点绘制两条匹配线。

3. 源码

3.1 SIFT关键点检测+Knn近邻匹配

# 基于SIFT描述符和比率检验的蛮力匹配
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('images/box.png')  # 查询图像
img2 = cv2.imread('images/box_in_scene.png')  # 训练图像
plt.subplot(121)
plt.imshow(cv2.cvtColor(img1,cv2.COLOR_BGR2RGB))  # 通过for循环逐个显示图像
plt.xticks([])  # 去掉x轴的刻度
plt.yticks([])  # 去掉y轴的刻度
plt.title("origin box")
plt.subplot(122)
plt.imshow(cv2.cvtColor(img2,cv2.COLOR_BGR2RGB))  # 通过for循环逐个显示图像
plt.xticks([])  # 去掉x轴的刻度
plt.yticks([])  # 去掉y轴的刻度
plt.title("origin box_in_scene")
plt.show()

img1 = cv2.imread('images/box.png', 0)  # 查询图像
img2 = cv2.imread('images/box_in_scene.png', 0)  # 训练图像

# 初始化SIFT检测器
sift = cv2.xfeatures2d.SIFT_create()

# 使用SIFT寻找关键点和描述符
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

# 使用默认参数初始化BFMatcher
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)

# 应用比率测试
good = []
for m, n in matches:
    if m.distance < 0.75 * n.distance:
        good.append([m])

# cv2.drawMatchesKnn:绘制Knn匹配结果
img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, img1, flags=2)

plt.imshow(img3)
plt.xticks([])
plt.yticks([])
plt.title("sift res")
plt.show()

3.2 ORB关键点检测+蛮力特征匹配

# ORB关键点检测+蛮力特征匹配
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('images/box.png', 0)  # 查找图像
img2 = cv2.imread('images/box_in_scene.png', 0)  # 训练图像

# 初始化ORB检测器
orb = cv2.ORB_create()

# 寻找关键点和描述符
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

# 使用距离测量cv2.NORM_HAMMING创建一个BFMatcher对象(因为我们使用的是ORB),并打开交叉检查以获得更好的结果。
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# 使用Matcher.match()方法在两幅图像中获得最佳匹配。
# 返回结果matches是一个DMatch对象列表。此DMatch对象具有以下属性:
# DMatch.distance—描述符之间的距离。越低越好。
# DMatch.trainIdx—训练描述符中描述符的索引
# DMatch.queryIdx-查询描述符中描述符的索引
# DMatch.imgIdx—训练图像的索引。
matches = bf.match(des1, des2)

# 按照距离的升序排序,以便最好的匹配项(距离较短的)出现在前面
matches = sorted(matches, key=lambda x: x.distance)

# 只抽取前10场匹配绘制(只是为了更便于可视化)。
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], img1, flags=2)

plt.imshow(img3)
plt.xticks([])
plt.yticks([])
plt.title("orb res")
plt.show()

3.3 SIFT关键点检测+Knn近邻及蛮力特征匹配

# ORB关键点检测+蛮力特征匹配
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('images/box.png', 0)  # 查找图像
img2 = cv2.imread('images/box_in_scene.png', 0)  # 训练图像

# 初始化ORB检测器
orb = cv2.ORB_create()

# 寻找关键点和描述符
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

# 使用距离测量cv2.NORM_HAMMING创建一个BFMatcher对象(因为我们使用的是ORB),并打开交叉检查以获得更好的结果。
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# 使用Matcher.match()方法在两幅图像中获得最佳匹配。
# 返回结果matches是一个DMatch对象列表。此DMatch对象具有以下属性:
# DMatch.distance—描述符之间的距离。越低越好。
# DMatch.trainIdx—训练描述符中描述符的索引
# DMatch.queryIdx-查询描述符中描述符的索引
# DMatch.imgIdx—训练图像的索引。
matches = bf.match(des1, des2)

# 按照距离的升序排序,以便最好的匹配项(距离较短的)出现在前面
matches = sorted(matches, key=lambda x: x.distance)

# 只抽取前10场匹配绘制(只是为了更便于可视化)。
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], img1, flags=2)

plt.imshow(img3)
plt.xticks([])
plt.yticks([])
plt.title("orb res")
plt.show()

参考

以上是关于OpenCV中的特征匹配(Feature Matching)的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV中的特征匹配+单应性以查找对象

[OpenCV] Feature Matching

如何从 OpenCV Python 中的特征匹配中获取像素坐标

openCV实战项目--人脸考勤

使用 OpenCV 改进特征点的匹配

OpenCV探索之路(二十三):特征检测和特征匹配方法汇总