8.6. 特征匹配

8.6.1. 目标

在本章中
-我们将了解如何将一个图像中的特征与其他图像中的特征相匹配。-我们将在OpenCV中使用暴力匹配器和法兰匹配器

8.6.2. 蛮力匹配器基础

蛮力匹配器很简单。它获取第一组中一个特征的描述符,并通过一些距离计算与第二组中的所有其他特征匹配。最接近的一个被退回。

对于BF matcher,首先我们必须使用 cv2.BFMatcher() . 它需要两个可选参数。第一个是 normType . 它指定要使用的距离测量。默认情况下,它是 cv2.NORM_L2 . 它有助于筛分、冲浪等 (cv2.NORM_L1 也在那里)。对于基于二进制字符串的描述符,如ORB、BRIEF、BRISK等, cv2.NORM_HAMMING 应该使用,它使用汉明距离作为测量。如果ORB正在使用 VTA_K == 3 or 4cv2.NORM_HAMMING2 应该使用。

第二个参数是布尔变量, crossCheck 这在默认情况下是错误的。如果是真的,Matcher只返回那些值为(i,j)的匹配,使得集合A中的i-th描述符具有集合B中的j-th描述符作为最佳匹配,反之亦然。也就是说,两个集合中的两个特性应该相互匹配。它提供了一致的结果,是D.Lowe在SIFT论文中提出的比率测试的一个很好的替代品。

一旦创建,两个重要的方法是 BFMatcher.match()BFMatcher.knnMatch() . 第一个返回最佳匹配。第二个方法返回 \(k\) 用户指定k的最佳匹配。当我们需要在这方面做更多的工作时,它可能是有用的。

就像我们使用cv2.draw keypoints()来绘制关键点一样, 图匹配() 帮助我们画火柴。它水平堆叠两个图像,并从第一个图像到第二个图像绘制线,显示最佳匹配。还有 cv2.drawMatchesKnn 它吸引了所有的k个最佳匹配。如果k=2,它将为每个关键点绘制两条匹配线。所以如果我们想有选择地画出一个面具,我们必须通过它。

让我们看一个SURF和ORB的例子(它们都使用不同的距离测量)。

8.6.3. 暴力匹配球描述符

在这里,我们将看到一个关于如何匹配两个图像之间的特征的简单示例。在这种情况下,我有一个queryImage和一个trainImage。我们将尝试使用特征匹配来查找trainImage中的queryImage。(图片是 /samples/c/box.png/samples/c/box_in_scene.png

我们使用SIFT描述符来匹配特性。所以让我们从加载图像、查找描述符等开始。

>>> import numpy as np
>>> import cv2 as cv
>>> import matplotlib.pyplot as plt
>>> img1 = cv.imread('/cvdata/box.png',cv.IMREAD_GRAYSCALE)          # queryImage
>>> img2 = cv.imread('/cvdata/box_in_scene.png',cv.IMREAD_GRAYSCALE) # trainImage
>>> # Initiate ORB detector
>>> orb = cv.ORB_create()
>>> # find the keypoints and descriptors with ORB
>>> kp1, des1 = orb.detectAndCompute(img1,None)
>>> kp2, des2 = orb.detectAndCompute(img2,None)

接下来我们创建一个带有距离测量的BFMatcher对象 cv2.NORM_HAMMING (因为我们正在使用ORB)和 crossCheck 打开以获得更好的结果。然后我们使用Matcher.match()方法在两个图像中获得最佳匹配。我们按照距离的升序对它们进行排序,以便最佳匹配(低距离)出现在前面。然后我们只画了前10场比赛(只是为了可见性)。你可以随意增加)

>>> # create BFMatcher object
>>> bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
>>> # Match descriptors.
>>> matches = bf.match(des1,des2)
>>> # Sort them in the order of their distance.
>>> matches = sorted(matches, key = lambda x:x.distance)
>>> # Draw first 10 matches.
>>> img3 = cv.drawMatches(img1,kp1,img2,kp2,matches[:10],None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
>>> plt.imshow(img3),plt.show()
../_images/sec09-matcher_3_0.png
(<matplotlib.image.AxesImage at 0x7f21935be780>, None)

下面是我得到的结果:

这个匹配对象是什么?

结果 matches = bf.match(des1,des2) 行是DMatch对象的列表。此DMatch对象具有以下属性:

  • DMatch.distance -描述符之间的距离。越低越好。

  • DMatch.trainIdx -列车描述符中描述符的索引

  • DMatch.queryIdx -查询描述符中描述符的索引

  • DMatch.imgIdx -列车图像索引。