1.蛮力匹配
首先在第一幅图像中选取一个关键点,然后依次与第二幅图像的每个关键点进行(描述符)距离测试,最后返回距离最近的关键点。
(1)对ORB 描述符进行蛮力匹配
代码速记:
- cv2.ORB_create()
- orb.detectAndCompute()
- cv2.BFMatcher()
- bf.match()
- sorted()
- cv2.drawMatches()
参数解释:
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
- normType:它是用来指定要使用的距离测试类型。默认值为cv2.Norm_L2。这很适合SIFT 和SURF 等(c2.NORM_L1 也可以)。对于使用二进制描述符的ORB,BRIEF,BRISK算法等,要使用cv2.NORM_HAMMING,这样就会返回两个测试对象之间的汉明距离。如果ORB 算法的参数设置为V TA_K==3 或4,normType就应该设置成cv2.NORM_HAMMING2。
- crossCheck:默认值为False。如果设置为True,匹配条件就会更加严格,只有到A 中的第i 个特征点与B 中的第j 个特征点距离最近,并且B 中的第j 个特征点到A 中的第i 个特征点也是最近(A 中没有其他点到j 的距离更近)时才会返回最佳匹配(i,j)。也就是这两个特征点要互相匹配才行。这样就能提供统一的结果,这可以用来替代D.Lowe在SIFT 文章中提出的比值测试方法。
matches = bf.match(des1, des2)#返回最佳匹配
matches = bf.knnMatch(des1, des2, k=2)
#每个关键点返回k 个最佳匹配(降序排列之后取前k 个),其中k 是由用户设定的。
#如果除了匹配之外还要做其他事情的话可能会用上(比如进行比值测试)。
bf:match(des1,des2)返回值是一个DMatch 对象列表。这个DMatch 对象具有下列属性:
- DMatch.distance:描述符之间的距离。越小越好。
- DMatch.trainIdx:目标图像中描述符的索引。
- DMatch.queryIdx:查询图像中描述符的索引。
- DMatch.imgIdx:目标图像的索引。
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2) # 前10个匹配
img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags=2)
用来绘制匹配的点。它会将这两幅图像先水平排列,然后在最佳匹配的点之间绘制直线(从原图像到目标图像)。如果前面使用的是BFMatcher.knnMatch(),现在我们可以使用函数cv2.drawMatchsKnn为每个关键点和它的k 个最佳匹配点绘制匹配线。如果k 等于2,就会为每个关键点绘制两条最佳匹配直线。如果我们要选择性绘制话就要给函数传入一个掩模。
实战:
我们有一个查询图像和一个目标图像。我们要使用特征匹配的方法在目标图像中寻找查询图像的位置。
def bf_orb(self):
img1 = cv2.imread('../images/box.png', 0) # queryImage
img2 = cv2.imread('../images/box_in_scene.png', 0) # trainImage
#【1】初始ORB特征检测器
orb = cv2.ORB_create()
#【2】用ORB找到两幅图像的关键点和描述符
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
#【3】创建BFMatcher对象
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
#【4】匹配两幅图像的描述符
matches = bf.match(des1, des2)
#【5】根据描述符之间的距离来排序
matches = sorted(matches, key=lambda x: x.distance)
#【6】画出前10匹配的特征点
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None,