OpenCV开发教程之暴力特征匹配

13人浏览 / 0人评论 / 添加收藏

暴力特征匹配(Brute-Force Feature Matching) 是 OpenCV 中最基本、最直观的特征点匹配方法。它的原理非常简单:对查询图像中的每一个特征描述子,都要与训练图像中的所有描述子计算一次距离,从中选出距离最近的一个(或 k 个)作为匹配点。因为采取了穷举的搜索策略,所以称为“暴力”匹配。

在 OpenCV 中,主要通过 cv::BFMatcher 类来实现,它既支持单次最优匹配,也支持 k 近邻匹配,配合一些筛选策略(如交叉检验、Lowe’s ratio test)可以得到相当干净、准确的匹配结果。

暴力匹配的优缺点

 
 
优点 缺点
实现简单,总能找到全局最近邻 当特征点数量很大时计算量巨大 (O(N²))
匹配结果绝对精确(就所给距离度量而言) 对高维大数据集几乎不可用
配合交叉检验、比率测试后鲁棒性好 不能处理实时、海量特征场景

通常,在特征点数量 < 几千 时,暴力匹配表现良好且简单可靠;当特征点超过数万 时,更适合使用 FLANN(快速近似最近邻)匹配器。
 

我们获取到图像特征点和描述子之后,可以将两幅图像进行特征匹配。
BF(Brute-Force)暴力特征匹配方法,通过枚举的方式进行特征匹配。
暴力匹配器很简单。它使用第一组(即第一幅图像)中一个特征的描述子,并使用一些距离计算将其与第二组中的所有其他特征匹配。并返回最接近的一个。
BFMatcher(normType, crossCheck)o normType计算距离的方式。
-NORM_L1,L1距离,即绝对值,SIFT和SURF使用
.NORML2,L2距离,默认值.即平方.SIFT和SURF使用
·HAMMING汉明距离.ORB使用ocrossCheck:是否进行交叉匹配,默认False.使用match函数进行特征点匹配,返回的对象为DMatch对象.该对象具有以下属性:

o DMatch.distance -描述符之间的距离。越低,它就越好。
o DMatch.trainldx-训练描述符中描述符的索引
o DMatch.queryldx-查询描述符中描述符的索引
o DMatch.imgldx-训练图像的索引

具体演示代码如下:

#暴力特征匹配
import cv2
print(cv2.getVersionString())
import numpy as np
from utils import plt_showimg

img1 = cv2.imread('./images/opencv1.png')
img2 = cv2.imread('./images/opencv2.png')
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 创建特征检测对象
sift = cv2.SIFT_create()

#计算描述子
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

#进行暴力匹配
# 匹配描述子
# bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
bf = cv2.BFMatcher(cv2.NORM_L1)
# bf = cv2.BFMatcher(cv2.NORM_HAMMING)
# matches = bf.match(des1, des2)
# # 除了match可以进行匹配,还可以使用knnMatch
matches = bf.knnMatch(des1, des2, k=2)
print(len(matches))
# 绘制匹配结果
# result = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
# result = cv2.drawMatches(img1, kp1, img2, kp2, matches, None)

good = []
for m, n in matches:
   #设定阈值,距离小于对方距离的0.7倍,我们认为是好的匹配点
   if m.distance < 0.7 * n.distance:
       good.append(m)
print(len(good))
result = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
# 显示结果
plt_showimg(result, 'result')

展示效果图如下:

全部评论