zoukankan      html  css  js  c++  java
  • OpenCVPython系列之特征匹配

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

    蛮力匹配(ORB匹配)

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

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

    1. 第一个是normType,它指定要使用的距离测量,或在其他情况下,它是cv2.NORM_L2。它适用于SIFT,SURF等(cv2.NORM_L1也在那里)。对于基于二进制串行的替代,如ORB,BRIEF,BRISK等,应使用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属于单应性匹配,单应性指的是图像在投影发生了畸变后仍然能够有较高的检测和匹配准确率,它可以大概率上避免旋转和放缩带来的影响。

    天道酬勤 循序渐进 技压群雄
  • 相关阅读:
    自己觉得好的文章(2)
    为什么要用C运行时库的_beginthreadex代替操作系统的CreateThread来创建线程?
    GraphEdit
    吴裕雄天生自然Spring BootSpring Boot与Thymeleaf实现页面信息国际化
    吴裕雄天生自然Spring BootThymeleaf基础语法
    吴裕雄天生自然Spring BootSpring Boot处理JSON数据
    吴裕雄天生自然Spring Boot基于Thymeleaf与BootStrap的Web开发实例
    吴裕雄天生自然Spring Boot基本配置和注解
    吴裕雄天生自然Spring Boot自定义Starters
    吴裕雄天生自然Spring Boot的基本配置
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/15659989.html
Copyright © 2011-2022 走看看