Advertisement

【OpenCV】第二十四章: 图像特征匹配:暴力特征匹配算法、FLANN特征匹配算法

阅读量:

第二十四章: 图像特征匹配:暴力特征匹配算法、FLANN特征匹配算法

一、特征匹配

提取特征点及其对应的描述子之后, 就可以进行特征匹配的过程了. opencv所支持的特征匹配算法共有2种:

1、BF暴力特征匹配算法
该算法采用穷举法实现特征匹配过程,在特定场景下表现优异。

匹配原理
为了实现有效的图像配准过程,必须基于至少两张图像来进行操作;接着需要分别从每张图中提取其对应的特征点及其描述子;之后,将第一组的所有描述子依次与第二组的所有描述子对比配对;配准时通常会通过计算两个对应区域之间的相似度或距离来评估配准效果;最终系统能够识别出在所有对比中相似度最高的配对关系作为最终的结果。

opencv提供了多种计算相似度的方法如NORM_L1 NORM_L2 HAMMING1以及HAMMING2等其中NORM_L1与NORM_L2主要应用于SIFT SURF等算法中的特征向量计算而HAMMING1与HAMMING2则专门用于计算ORB BRIEF等算法生成的特征向量这一系列方法均旨在通过不同的数学模型来衡量图像之间的相似程度

BF的具体匹配流程如下:
(1)创建BF匹配器:
bf = cv2.BFMatcher(normType[, crossCheck])
其中:
参数normType指定相似度计算的方法,默认情况下采用NORM_L2方法。
参数crossCheck控制交叉验证功能的启用与否。

(2)执行特征匹配:
第一种方法:通过匹配器的match函数来实现特征匹配,在代码中表示为:
match = bf.match(des1, des2)
该操作旨在比较两幅图像的描述子,并返回匹配结果。
第二种方法:采用knnMatch函数来进行特征比对:
match = bf.knnMatch(des1, des2, k)
其中des1和des2分别代表两幅图像中的描述子;k表示取欧氏距离最小的前k个关键点。
当k=1时,该过程与第一种方法的结果一致。
返回的对象包括distance值(表示描述子间的相似程度)、query索引(第一个图像中的描述子索引)以及train索引(第二个图像中的描述子索引)三个属性。

(3)绘制匹配点:
方法一对应的绘制方法:img_match = cv2.drawMatches(img1, kp1, img2, kp2, match, outImg),就是将匹配的点用线连接到一起,这样通过人眼就能观察到哪些点进行匹配了。
参数img1,kp1是指第一组搜索的图和其特征点,就是我们提供的、要搜索的图;参数img2,kp2是指匹配的图及其特征点,就是比如搜索引擎从图片库中拿出来的图;参数match就是匹配器的匹配结果;outImg是图像的输出,这里不用输出,设置位None,我们用img_match这个对象来接受返回值。
方法二对应的绘制方法:img_match = cv2.drawMatchesKnn(img1,kp1, img2, kp2, match)

复制代码
        1. #例24.1 调用BF算法匹配图像  
    
        2. import cv2
    
        3. import numpy as np
    
        4. import matplotlib.pyplot as plt
    
        5.  
    
        6. img_template = cv2.imread(r'C:\Users\25584\Desktop\builing-0.png')   #模板  (120, 70, 3)
    
        7. img_template_gray = cv2.cvtColor(img_template, cv2.COLOR_BGR2GRAY)  
    
        8. img_orig = cv2.imread(r'C:\Users\25584\Desktop\building.jpg')  #原图  (600, 868, 3)
    
        9. img_orig_gray = cv2.cvtColor(img_orig, cv2.COLOR_BGR2GRAY)  
    
        10.  
    
        11. sift = cv2.xfeatures2d.SIFT_create()    #创建SIFT对象
    
        12. kp_template, des_template = sift.detectAndCompute(img_template_gray, None)        #进行检测
    
        13. kp_orig, des_orig = sift.detectAndCompute(img_orig_gray, None)    
    
        14.  
    
        15. bf = cv2.BFMatcher(cv2.NORM_L1)            #创建匹配器
    
        16. match1 = bf.match(des_template, des_orig)   #调用match方法进行匹配
    
        17. img_match1 = cv2.drawMatches(img_template, kp_template, img_orig, kp_orig, match1, None)      #绘制匹配结果    (600, 938, 3)
    
        18.  
    
        19. match2 = bf.knnMatch(des_template, des_orig, 1)  #调用knnMatch方法进行匹配
    
        20. img_match2 = cv2.drawMatchesKnn(img_template, kp_template, img_orig, kp_orig, match2, None)
    
        21.  
    
        22. #---------------可视化----------------------------------
    
        23. Fig=plt.figure(figsize=(16,14))
    
        24. Grid=plt.GridSpec(3,7)
    
        25. axes1=Fig.add_subplot(Grid[1,0]), plt.imshow(img_template[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('template')
    
        26. axes2=Fig.add_subplot(Grid[0:4,1:3]), plt.imshow(img_orig[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('orig img')
    
        27. axes3=Fig.add_subplot(Grid[0:4,3:5]), plt.imshow(img_match1[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('match img1')
    
        28. axes4=Fig.add_subplot(Grid[0:4,5:7]), plt.imshow(img_match2[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('match img2')
    
    代码解释

模板是从原图截取的一块(注释:具体来说是第三层楼的第2个窗户(从右往左数))。因此匹配效果非常理想。(注释:不过也存在一些误匹配的情况)这就是特征匹配法。(注释:这即是特征匹配法的一种应用)。例如,在直播间的实时视频中(注释:通过视频可以识别主播的手势动作),如'OK'手势被识别后即可判断主播发出相关指令(注释:如'OK'手势被识别到则表示主播发送了OK指令)。

二、FLANN特征匹配

Among feature matching algorithms, FLANN stands out as the most efficient method for batch operations, offering superior speed in such scenarios. However, its reliance on approximate nearest neighbors results in lower precision. Depending on the requirement, BF matching is preferred for precise image matching, while FLANN is more suitable when speed is a priority.

  • FLANN匹配步骤:
    (1)创建FLANN匹配器:flann = cv2.FlannBasedMatcher(index_params[, search_params])
    参数index_params是一个字典,我们主要是传入要匹配的算法,有KDTREE和LSH两种算法,通常如果我们使用的是SIFT或者是SURF,就选择KDTREE匹配算法;如果使用的是ORB就选择LSH算法。如果搭配错误会报错。
    如果我们使用的匹配算法是KDTREE,就需要传入第二个参数search_params, 这个参数也是一个字典,用来指定KDTREE算法中遍历树的次数,一般情况下经验是:KDTREE的层级设置为5,搜索值设置为50,就是10倍,这样计算量相对比较少,速度比较快,准确率也相对比较高。比如:index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5), search_params = dict(checks=50),其中FLANN_INDEX_KDTREE的默认值是1,即参数填:dict(algorithm=1, trees=5), dict(checks=50)即可。
    (2)进行特征匹配:
    方法一:调用match方法进行匹配:Dmatch = flann.match(des1, des2)
    方法二:调用knnMatch方法进行匹配:Dmatch = flann.knnMatch(des1, des2, k)
    (3)绘制匹配点:
    方法一对应的绘制方法:cv2.drawMatches(img1, kp1, img2, kp2, Dmatch, outImg)
    方法二对应的绘制方法:cv2.drawMatchesKnn(img1,kp1, img2, kp2, Dmatch)
复制代码
 #例24.2 调用FLANN算法匹配图像  
    
 import cv2
    
 import numpy as np
    
 import matplotlib.pyplot as plt
    
  
    
 img_template = cv2.imread(r'C:\Users\25584\Desktop\builing-0.png')   #模板  (120, 70, 3)
    
 img_template_gray = cv2.cvtColor(img_template, cv2.COLOR_BGR2GRAY)  
    
 img_orig = cv2.imread(r'C:\Users\25584\Desktop\building.jpg')  #原图  (600, 868, 3)
    
 img_orig_gray = cv2.cvtColor(img_orig, cv2.COLOR_BGR2GRAY)  
    
  
    
 sift = cv2.xfeatures2d.SIFT_create()    #创建特征检测器SIFT
    
 kp_template, des_template = sift.detectAndCompute(img_template_gray, None)        #进行检测
    
 kp_orig, des_orig = sift.detectAndCompute(img_orig_gray, None)    
    
  
    
 flann = cv2.FlannBasedMatcher(dict(algorithm=1, trees=5), dict(checks=50))       #创建匹配器flann
    
 match1 = flann.match(des_template, des_orig)   #调用match方法进行匹配
    
 img_match1 = cv2.drawMatches(img_template, kp_template, img_orig, kp_orig, match1, None)      #绘制匹配结果    
    
  
    
 match2 = flann.knnMatch(des_template, des_orig, 2)  #调用knnMatch方法进行匹配,这里参数k设为2,
    
 good = []   #对匹配的点进行一个过滤
    
 for i, (m,n) in enumerate(match2):   
    
     if m.distance < 0.7 * n.distance:
    
     good.append(m)
    
 img_match2 = cv2.drawMatchesKnn(img_template, kp_template, img_orig, kp_orig, [good], None)   #[good]变成43个点了
    
  
    
 #---------------可视化----------------------------------
    
 Fig=plt.figure(figsize=(16,14))
    
 Grid=plt.GridSpec(3,7)
    
 axes1=Fig.add_subplot(Grid[1,0]), plt.imshow(img_template[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('template')
    
 axes2=Fig.add_subplot(Grid[0:4,1:3]), plt.imshow(img_orig[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('orig img')
    
 axes3=Fig.add_subplot(Grid[0:4,3:5]), plt.imshow(img_match1[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('match img1')
    
 axes4=Fig.add_subplot(Grid[0:4,5:7]), plt.imshow(img_match2[:,:,::-1]), plt.box(), plt.xticks([]), plt.yticks([]), plt.title('match img2')
    
    
    
    
    代码解释

全部评论 (0)

还没有任何评论哟~