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匹配: