这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 企业专区 » OpenVINO生态社区 » 【原创】OpenCV-Python系列之特征匹配(五十三)

共4条 1/1 1 跳转至

【原创】OpenCV-Python系列之特征匹配(五十三)

高工
2020-08-03 16:08:57     打赏

OpenCV-Python系列之特征匹配

之前我们讨论过了诸多的特征检测算法,这次我们来讨论如何运用相关的方法进行特征匹配。本次教程完全为实战教程,没有相关的算法原理介绍,大家可以轻松一下了。

蛮力匹配(ORB匹配)

Brute-Force匹配非常简单,首先在第一幅图像中选择一个关键点然后依次与第二幅图像的每个关键点进行(改变)距离测试,最后返回距离最近的关键点。

对于BF匹配器,首先我们必须使用cv2.BFMatcher()创建BFMatcher对象。它需要两个可选的参数。

1.        第一个是normType,它指定要使用的距离测量,或在其他情况下,它是cv2.NORM_L2。它适用于SIFTSURF等(cv2.NORM_L1也在那里)。对于基于二进制串行的替代,如ORBBRIEFBRISK等,应使用cv2.NORM_HAMMING,使用汉明距离作为度量,如果ORB使用WTA_K == 3or4,则应使用cv2.NORM_HAMMING2

2.        crossCheck:最小数值为假。如果设置为True,匹配条件就会更加严格,只有到A中的第i个特征点与B中的第j个特征点距离最近,并且B中的第j个特征点到A中的第i个特征点也是最近时才会返回最佳匹配,即这两个特征点要互相匹配才行。

两个重要的方法是BFMatcher.match()和BFMatcher.knnMatch(),第一个返回最佳匹配,第二种方法返回k个最佳匹配,其中k由用户指定。

使用cv2.drawMatches()来对齐匹配的点,它可以将两幅图像先行水平划分,然后在最佳匹配的点之间对齐直线。如果前面使用的BFMatcher.knnMatch(),现在可以使用函数cv2.drawMatchsKnn为每个关键点和它的一个最佳匹配如果要选择性替换就要给函数重新定义一个指针。

我们来看代码:

def BruteForce(img1,img2):
     # Initiate ORB detector
     orb = cv2.ORB_create()
 
     # find the keypoints and descriptors with ORB
     kp1, des1 = orb.detectAndCompute(img1, None)
     kp2, des2 = orb.detectAndCompute(img2, None)
 
     # create BFMatcher object
     bf = cv2.BFMatcher(cv2.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 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)
 
     plt.imshow(img3), plt.show()

输出:

image.png

SIFT的特征匹配

关于SIFT的概念我们之前已经讨论过,现在来看相关的实战代码:

def SIFT(img1, img2):
     # Initiate SIFT detector
     sift = cv2.xfeatures2d.SIFT_create()
 
     # find the keypoints and descriptors with SIFT
     kp1, des1 = sift.detectAndCompute(img1, None)
     kp2, des2 = sift.detectAndCompute(img2, None)
 
     # BFMatcher with default params
     bf = cv2.BFMatcher()
     matches = bf.knnMatch(des1, des2, k=2)
 
     # Apply ratio test
     good = []
     for m, n in matches:
         if m.distance < 0.6 * n.distance:
             good.append([m])
 
     # cv.drawMatchesKnn expects list of lists as matches.
     img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags=2)
 
     plt.imshow(img3), plt.show()

结果:

image.png

事实上我们可以看到,与蛮力匹配相比,SIFT算法的特征匹配是十分强大的,效果显而易见。

SURF的特征匹配

def SURF(img1, img2):
     # Initiate SIFT detector
     surf = cv2.xfeatures2d.SURF_create()
 
     # find the keypoints and descriptors with SIFT
     kp1, des1 = surf.detectAndCompute(img1, None)
     kp2, des2 = surf.detectAndCompute(img2, None)
 
     # BFMatcher with default params
     bf = cv2.BFMatcher()
     matches = bf.knnMatch(des1, des2, k=2)
 
     # Apply ratio test
     good = []
     for m, n in matches:
         if m.distance < 0.6 * n.distance:
             good.append([m])
 
     # cv.drawMatchesKnn expects list of lists as matches.
     img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags=2)
 
     plt.imshow(img3), plt.show()

image.png

SIFT算法的特征匹配相比较SURF来说,基本上效果差不多,但是速度不同。

基于FLANN的匹配器

FLANN代表近似最近邻居的快速库。它包含一组算法,这些算法针对大型数据集中的快速最近邻搜索和高维特征进行了优化。对于大型数据集,它比BFMatcher工作得更快。

代码:

def FLANN(img1, img2):
     # Initiate SIFT detector
     sift = cv2.xfeatures2d.SIFT_create()
 
     # find the keypoints and descriptors with SIFT
     kp1, des1 = sift.detectAndCompute(img1, None)
     kp2, des2 = sift.detectAndCompute(img2, None)
 
     # FLANN parameters
     FLANN_INDEX_KDTREE = 1
     index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
     search_params = dict(checks=50)  # or pass empty dictionary
 
     flann = cv2.FlannBasedMatcher(index_params, search_params)
 
     matches = flann.knnMatch(des1, des2, k=2)
 
     # Need to draw only good matches, so create a mask
     matchesMask = [[0, 0] for i in range(len(matches))]
 
     # ratio test as per Lowe's paper
     for i, (m, n) in enumerate(matches):
         if m.distance < 0.6 * n.distance:
             matchesMask[i] = [1, 0]
 
     draw_params = dict(matchColor=(0, 255, 0),
                        singlePointColor=(255, 0, 0),
                        matchesMask=matchesMask,
                        flags=0)
 
     img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, matches, None, **draw_params)
 
     plt.imshow(img3, ), plt.show()

输出结果:

image.png

FLANN属于单应性匹配,单应性指的是图像在投影发生了畸变后仍然能够有较高的检测和匹配准确率,它可以大概率上避免旋转和放缩带来的影响。


对计算机视觉感兴趣?这个社区推荐给你~

>>点击了解OpenVINO生态开发社区



高工
2020-08-03 23:35:55     打赏
2楼

期待继续更新


工程师
2020-08-03 23:39:01     打赏
3楼

讲解的很详细!



工程师
2020-08-07 19:14:55     打赏
4楼

讲的很不错


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]