zoukankan      html  css  js  c++  java
  • OpenCVPython系列之单应性查找对象实战篇

    之前我们讨论到cv2.findHomography()函数里有四个算法,这次我们来简述最后两个算法。

    LMEDS

    LMEDS又称最小中值平方法,LMedS的经典步骤是:

    1. 随机采样

    2. 计算模型参数

    3. 计算相对模型的点集偏差err,并求出偏差中值Med(err)

    4. 迭代2. 3.步直至获得符合阈值的最优解:Med(err)最小

    5. 精确优化模型参数(LM算法迭代优化)

    LMedS的函数接口 参照OpenCV来说主要需要2-3个参数(第三个不是必须的)

    1. 置信度confidence:设置之后代表RANSAC采样n次过程中会出现(至少一次)采样点数据集中的点都为内点的概率,这个值设置的太大,会增加采样次数。太小,会使结果不太理想。一般取0.95-0.99

    2. 最大采样迭代次数maxIters:为了防止一直在采样计算

    3.最大精细迭代次数refineIters:在采样之后,选取最优解。可以增加精确优化,比如使用LM算法获得更优解。

    RANSAC的阈值在具有物理意义或者几何意义的时候比较容易确定,但是当阈值不具有这些特征的时候,就成了一个不太好调整的参数了。这时LMedS可以自适应迭代获得最优解。

    PROSAC

    渐进一致采样法(PROSAC) 是对经典的 RANSAC中采样的一种优化。相比经典的 RANSAC 方法均匀地从整个集合中采样,PROSAC 方法是从不断增大的最佳对应点集合中进行采样的。所以这种方法可以节省计算量,提高运行速度。由于涉及到机器学习相关的知识,在这里并不过多的详述,我们看一下原论文作者的算法:

    image.png

    OpenCV中的使用

    基本步骤

    1)使用SHIT检测特征点

    2)使用FLANN匹配器进行匹配

    3)选取好的匹配

    4)根据原图像和目标图像中对应的特征点,使用上述其中一种算法求变换矩阵

    5)最后将原图像的边界经变换矩阵变换后画到目标图像上

    获取变换矩阵的函数:

    retval, mask = cv2.findHomography(srcPoints, dstPoints, method, ransacReprojThreshold, maxIters, confidence)

    · retval输出的矩阵

    · srcPoints原图像中对应的特征点坐标

    · dstPoints目标图像中对应的特征点坐标

    · method计算单应矩阵的方法,总共包括:

                           0使用所有点的常规方法,即最小二乘法

                           RANSAC基于RANSAC的方法

                           LMEDS最小中值稳健方法

                           RHO基于PROSAC的方法

    · ransacReprojThreshold将点对视为内点的最大允许重投影错误(仅用于RANSAC和RHO方法)。也就是说,如果

    \left \| dstPoints_{i} - convertPointsHomogeneous (H*srcPoints_{i}) \right \|_{2}> ransacReprojThreshold 那么点被认为是异常。如果以像素为单位测量srcPoints和dstPoints,则将此参数设置在1到10的范围内通常是有意义的。

    · mask可选输出掩码由稳健方法(RANSAC或LMEDS)设置。

    · maxItersRANSAC迭代的最大数量。

    · confidence置信水平,介于0和1之间。

    现在我们使用示例图片,模板图片:

    image.png

    原图:

    image.png

    现在我们来看代码:

    import numpy as np
     import cv2
     from matplotlib import pyplot as plt
     
     MIN_MATCH_COUNT = 10
     img1 = cv2.imread('box.png', 0)  # 
    原图像
     img2 = cv2.imread('box_in_scene.png', 0)  # 
    待搜索图像,下面称目标图像
     # 
    启动
    SIFT
    检测器
     sift = cv2.xfeatures2d.SIFT_create()
     # 
    使用
    SIFT
    查找关键点和描述符
     kp1, des1 = sift.detectAndCompute(img1, None)
     kp2, des2 = sift.detectAndCompute(img2, None)
     
     # 
    使用
    FLANN
    匹配器进行匹配
     FLANN_INDEX_KDTREE = 1
     index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
     search_params = dict(checks=50)
     flann = cv2.FlannBasedMatcher(index_params, search_params)
     matches = flann.knnMatch(des1, des2, k=2)  # 
    获得匹配结果
     
     # 
    按照
    Lowe
    的比率存储所有好的匹配。
     good = []
     for m, n in matches:
         if m.distance < 0.7 * n.distance:
             good.append(m)
     
     # 
    只有好的匹配点多于
    10
    个才查找目标,否则显示匹配不足
     if len(good) > MIN_MATCH_COUNT:
         # 
    获取匹配点在原图像和目标图像中的的位置
         # kp1
    :原图像的特征点
         # m.queryIdx
    :匹配点在原图像特征点中的索引
         # .pt
    :特征点的坐标
         src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
         dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
         # 
    获取变换矩阵,采用
    RANSAC
    算法
         M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
         matchesMask = mask.ravel().tolist()
         # 
    图像变换,将原图像变换为检测图像中匹配到的形状
         # 
    获得原图像尺寸
         h, w = img1.shape
         # 
    使用得到的变换矩阵对原图像的四个角进行变换,获得在目标图像上对应的坐标。
         pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]
                          ).reshape(-1, 1, 2)
         # 
    对角点进行变换
         dst = cv2.perspectiveTransform(pts, M)
         # 
    画出边框
         img2 = cv2.polylines(img2, [np.int32(dst)], True, 255, 5, cv2.LINE_AA)
     else:
         print("Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT))
         matchesMask = None
     
     # 
    画出匹配点
     draw_params = dict(matchColor=(0, 0, 255),  # draw matches in green color
                        singlePointColor=None,
                        matchesMask=matchesMask,  # draw only inliers
                        flags=2)
     img3 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params)
     plt.imshow(img3), plt.title('Result'),
     plt.axis('off')
     plt.show()

    结果:

    image.png

    可以看到,即便是在诸多的干扰性的图像中,特征匹配仍然相当的准确。目前此代码只实验了RANSAC算法,至于我们之前讲到的其他的算法,大家自行实验。

    天道酬勤 循序渐进 技压群雄
  • 相关阅读:
    JavaSE知识-18(Map集合&模拟斗地主洗牌和发牌)
    JavaSE知识-17(Set集合)
    20145231 《信息安全系统设计基础》 课程总结
    20145231 《信息安全系统设计基础》第14周学习总结
    20145231 《信息安全系统设计基础》第13周学习总结
    20145231 《信息安全系统设计基础》第12周学习总结
    20145231 20145205 《信息安全系统设计基础》实验五
    20145231 《信息安全系统设计基础》第11周学习总结
    20145231 20145205 《信息安全系统设计基础》 第三次实验
    20145231 《信息安全系统设计基础》第10周学习总结
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/15660000.html
Copyright © 2011-2022 走看看