Brute-Force匹配器也就是蛮力匹配器,顾名思义,它的工作原理是:在第一幅图像上选取一个关键点,然后依次与第二幅图像的每个关键点进行(描述符)距离测试,最后返回距离最近的关键点。
对于BF匹配器,我们首先要使用cv.BFMatcher()创建一个BFMatcher对象。它有两个可选参数。
第一个是normType,它用来指定要使用的距离测试类型。
默认值为cv.NORM_L2,这个类型很适合SIFT和SURF等(cv.NORM_L1也可以)。对于使用二进制描述符的ORB,BRIEF,BRISK算法等,要使用cv.NORM_HAMMING,这样就会返回两个测试对象间的汉明距离。如果ORB算法的参数设置为MTA_K==3或4,normType就应该设置为cv.NORM_HAMMING2。
第二个参数是布尔变量corssCheck,默认值为False。如果设置为True,匹配条件就会更加严格,只有到A中的第i个特征点与B中的第j个特征点距离最近,并且B中的第j个特征点到A中的第i个特征点也是最近(A中没有其他的点到j的距离最近)时才会返回最佳匹配(i, j)。也就是这两个特征点要互相匹配才行。这样就能提供统一的结果,这可以用来代替D.Lowe在SIFT文章中提出的比值测试方法。
BFMatcher对象有两个方法,bf.match()和bf.knnMatch()。第一个方法会返回最佳匹配。第二个方法为每个关键点返回k个匹配(降序排列之后取前K个),其中K是由用户设定的。结果出了匹配之外还要做其他事情的话可能会用上(比如进行比值测试)。
返回对象是一个DMatch对象列表。这个DMatch对象具有下列属性:
1、DMatch.distance - 描述符之间的距离。越小越好。
2、
DMatch.trainIdx- 目标图像中描述符的索引。
3、DMatch.queryIdx - 查询图像中描述符的索引。
4、DMatch.imgIdx - 目标图像的索引。
就像使用cv.drawKeyPoints()绘制关键点一样,我们使用cv.drawMatches()来绘制匹配的点。它会将两幅图像水平排列,然后在最近匹配的点之间绘制直线(从原图像到目标图像)。如果前面使用的是bf.knnMatch(),就使用函数cv.drawMatchsKnn()为每个关键点和它的K个最佳匹配点绘制匹配线。如果k等于2,就会为每个关键点绘制2条最佳匹配直线。如果我们要选择性绘制的话就给函数传入一个掩模。
具体代码:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img1 = cv.imread('img/box.png', 0)
img2 = cv.imread('img/box_in_scene.png', 0)
def orb_bf_demo():
#创建ORB对象
orb = cv.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
#创建bf对象,并设定初始值
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
#将匹配结果按特征点之间的距离进行降序排列
matches = sorted(matches, key= lambda x:x.distance)
#前10个匹配
img3 = cv.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)
cv.namedWindow('img',cv.WINDOW_AUTOSIZE)
cv.imshow('orb_img',img3)
def sift_bf_demo():
#创建SIFT对象
sift = cv.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
#使用默认参数 cv.Norm_L2 ,crossCheck=False
bf = cv.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
#比值测试,首先获取与A距离最近的点B(最近)和C(次近),只有当B/C小于阈值时(0.75)才被认为是匹配
#因为假设匹配是一一对应的,真正的匹配的理想距离是0
good = []
for m, n in matches:
if m.distance < 0.75*n.distance:
good.append([m])
img3 = cv.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags=2)
cv.namedWindow('img', cv.WINDOW_AUTOSIZE)
cv.imshow('sift_img', img3)
orb_bf_demo()
sift_bf_demo()
cv.waitKey(0)
cv.destroyAllWindows()
效果:
都选取前十个最佳匹配
使用ORB描述符进行BF匹配:
使用SIFT进行BF匹配: