(接上文)
四、特征匹配
1、BF匹配算法
全称是Brupt Force,是蛮力匹配,算法思想是选取第一幅图像中的一点与另一幅图像中的每个特征点做距离测试,返回距离最近的关键点。
BF算法的用法如下:
①创建一个BFMatcher对象
cv2.BFMatcher(normType,crossCheck)
bf = cv2.BFMatcher(cv2.NORM_L2)
bf = cv.BFMatcher(cv2.NORM_HAMMING,crossCheck=True)
第一个参数是距离测试类型,cv2.NORM_L2适用于SIFT和SURF算法,cv2.NORM_HAMMING适用于ORB算法。默认值为cv2.NORM_L2。
第二个参数是布尔变量 crossCheck,默认值为False。如果设置为True,匹配条件就会更加严格,只有到当A 中的第 i 个特征点与 B 中的第 j 个特征点距离最近,并且 B 中的第 j 个特征点到 A 中的第 i 个特征点也是最近时才会返回最佳匹配。
②BF匹配
BFMatcher对象有两个匹配的方法:
matches = bf.match(des1,des2)
matches = sorted(matches, key = lambda x:x.distance)
该方法会返回最佳匹配,返回结果是一个match对象,这个对象包含了:distance, 描述子之间的距离,值越低越好,越低表示近似度越高,或者说匹配度越高,所以在输出指定数量的最佳匹配对儿时,需要根据距离大小将match对象排序,然后输出前n个距离最小的match对象。
bf = cv2.BFMatcher(cv2.NORM_L2)
matches = bf.knnMatch(des1, des2, k=2) # 最相似的特征点
goodMatch = [] # 最佳匹配点集合
'''基于距离阈值选择优质匹配点对,如果最近邻m的距离小于0.65倍的次近邻n的距离,
则认为这个匹配点对是优质的,将它存储在good列表中。'''
for m, n in matches:
if m.distance < 0.65 * n.distance:
goodMatch.append(m)
goodMatch = np.expand_dims(goodMatch, 1)
该方法为每个关键点返回 k 个最佳匹配(降序排列之后取前 k 个),其中 k 是由用户设定的。这里k=2,说明返回最佳匹配和次最佳匹配。为了确定哪一个才是最合理的匹配,所以对这两个最佳匹配进行了测试,如果最佳匹配的距离小于次最佳分配的部分值,说明这两个点时相似的,可以进行匹配。
③绘制匹配点
res = cv2.drawMatches(img1,kp1,img2,kp2,matches[:100],None)
将匹配点用直线连接起来
也可以用如下方法:
res = cv2.drawMatchesKnn(img1_gray, kp1, img2_gray, kp2, goodMatch[:100], None, flags=2)
该方法是用k条线将匹配点连接起来,flags代表绘制的标志位
0----默认,画出所有关键点
2----只绘制match里面的点
4----会画出所有关键点,但是是关键点周围的圆圈和方向
2、FLANN匹配算法
FLANN,最快邻近区特征匹配方法,是一种快速匹配方法,在进行批量特征匹配时,FLANN速度更快。但是FLANN使用的是邻近近似值,所以精度较差。
①创建FLANN对象
FLANN_INDEX_KDTREE = 0
indexParams = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
searchParams = dict(checks=50)
flann = cv.FlannBasedMatcher(indexParams, searchParams)
flann = cv2.FlannBasedMatcher(index_params[, search_params])
参数index_params是一个字典,我们主要是传入要匹配的算法,有KDTREE和LSH两种算法,通常如果我们使用的是SIFT或者是SURF,就选择KDTREE匹配算法;如果使用的是ORB就选择LSH算法。如果搭配错误会报错。
如果我们使用的匹配算法是KDTREE,就需要传入第二个参数search_params, 这个参数也是一个字典,用来指定KDTREE算法中遍历树的次数,一般情况下经验是:KDTREE的层级设置为5,搜索值设置为50,就是10倍,这样计算量相对比较少,速度比较快,准确率也相对比较高。
②FLANN匹配
同BF,有两个方法:
Dmatch = flann.match(des1, des2)
Dmatch = flann.knnMatch(des1, des2, k)
③绘制匹配点
同BF,有两种方式:
cv2.drawMatches(img1, kp1, img2, kp2, Dmatch, outImg)
cv2.drawMatchesKnn(img1,kp1, img2, kp2, Dmatch)
3、BF和FLANN比较
BF效率低,但是精度高,FLANN速度快,但是精度低。
(这部分内容在前面有,但是没有系统的总结,这里进行了总结)