Sift特征匹配以及ransac消除误差解析

前言

本文不光展示SIFT算法的匹配效果,更重要的是记录下搜集信息以及处理信息的过程,方便以后按照这个行动思路去解决问题,以及优化行动思路

第一部分:了解到SIFT算法的存在

其实早在学习双目视觉的时候就了解过 特征匹配 算法,其中就使用过SIFT算法,以及众多SIFT算法的变种,这时只是知道名字,最近因为课题需要使用,所以开展从原理到实践的研究,首先了解一个算法,首先要直观的看到他的运行结果,不管是自己跑的还是别人跑的,第一个数据来源是opencv-python的中文文档
单张图片特征查找效果如下:
Sift特征匹配以及ransac消除误差解析_第1张图片
两张图片匹配效果如下:
Sift特征匹配以及ransac消除误差解析_第2张图片

看到这里就激起了我的兴趣,接下来就进行第二步

第二部分 学习算法原理

首先去找的是视频资源,当然是先去B站康康,没想到真的有!
视频详解
看完这些之后大概了解了SIFT的流程以及部分数学知识,但是具体的细节还需要文字资料配合食用:
SIFT的宏观描述(大体流程)
SIFT的微观描述(数学细节)
此时再回去看带你入门的视频,会发现首尾呼应,有些不懂的地方也明白了,但是这是一个不断反复多次理解的过程,没有人能一天把别人长时间的研究成果搞懂,所以不会以及困惑很正常,不要灰心,多找资料,反复看几遍就会懂了。

第三部分 算法实践

到这里相信你已经明白了SIFT是什么原理,匹配出来的效果大概是什么样的,所以你也想做出和示例中一样的效果,甚至做得更好,或者你想用SIFT帮助你的科研项目,这些都没有问题,以下是我的代码学习历程以及成果。

在最初阶段,我只想让代码运行起来,因为SIFT算法是受专利保护的,所以在opencv3.4之后被放到了一个单独的收费库里,只能自己在本地机器编译后才能运行,
windows编译方法1
windows编译方法2
当然这个过程会费时大概一天,只有真正的强者才能完成编译这个过程,你会遇上非常多的莫名其妙的问题,需要你自己一个一个去解决,但是只要肯用功,总会解决的
我在这补充一个编译之后在本地python使用的方法,网上没找到,是自己研究出来的,当你完成编译后会有下图这样的文件夹Sift特征匹配以及ransac消除误差解析_第3张图片

找到其中的python_loader,然后打开anaconda prompt,如果你没有anaconda,那么你就打开cmd,并保证输入python后出现python的交互界面(把python放到环境变量的path里)接下来操作如下Sift特征匹配以及ransac消除误差解析_第4张图片
1.首先卸载你的 opencv-python

pip uninstall opencv-python
pip uninstall opencv-contrib-python

2.定位到你的setu.py的目录

切换目录方法

3.然后分别输入

python setup.py build
python setup.py install

下面就是代码实践,我首先尝试了官网教程给出的算法例子

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)

'''
下面是创建sift,以及使用sift进行计算的方法
'''
sift = cv.xfeatures2d.SIFT_create()
kp = sift.detect(gray,None)

'''
下面是绘图部分
'''
img=cv.drawKeypoints(gray,kp,img)
plt.imshow(img),plt.title('sift-gray-ver1'),plt.show()

Sift特征匹配以及ransac消除误差解析_第5张图片
官网给出的版本特征点画得非常小,没有尺度和方向的描述,并且是个黑白的,影响视觉体验。经过一番资料的查询,找到了如何画彩色和清晰特征点的方法。

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')73
'''
下面是创建sift,以及使用sift进行计算的方法
'''
sift = cv2.xfeatures2d.SIFT_create()
kp,des = sift.detectAndCompute(img1,None)

'''
下面是绘图部分
'''
img = cv.drawKeypoints(img1,kp,None,(100,100,255),4)
plt.imshow(img[:,:,::-1]),plt.title('sift-rgb-ver2'),plt.show()

Sift特征匹配以及ransac消除误差解析_第6张图片
这下就看的很清楚了,那么除了SIFT对单个图像的特征挖掘,还要进行两个图片的特征连接,先上代码

'''
构造函数
'''
def my_match(img1,img2,kp1,kp2,des1,des2,mc_type):
    bf = cv.BFMatcher()
    matches = bf.knnMatch(des1,des2,k=2)
    #此处的2就是每个匹配装两个对应的点位
    good = []
    #不难发现,m,n就是对应刚才的2
    for m,n in matches:
        if m.distance < 0.70*n.distance:
            print(m.distance)
            print('---end---')
            # print(n.imgIdx)
            good.append([m])
    img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=mc_type)
    cv.imshow('match',img3)
    cv.waitKey(10000000)
    cv.destroyAllWindows()
    cv.waitKey(1)
'''
调用函数
'''
my_match(img1,
img2,sift_kp_1,sift_kp_2,sift_des_1,sift_des_2,
cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)


这个学生证是我朋友和我出去玩落在我车上的,正好在手边就拿来拍照了,可以看到匹配的效果不错,大部分博客也是到此为止了,但是我发现有些点依然对应的不是很好,所以下一部分是模型内的参数调优以及算法优化。

第四部分 模型内的参数调优以及Ransac优化匹配

首先是加入Ransac算法部分,Ransac算法接收的是由SIFT特征经过BF匹配后生成的 [左图特征点] 和[右图特征点] , 然后对这些匹配后的特征点进行选择,删掉误匹配点,只取正确匹配点,实际代码如下。

def my_match(img1,img2,kp1,kp2,des1,des2,mc_type):
    FLANN_INDEX_KDTREE = 0
    index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
    search_params = dict(checks = 100)
    flann = cv2.FlannBasedMatcher(index_params,search_params)
    matches = flann.knnMatch(des1, des2, k = 2)
    good = []
    #不难发现,m,n就是对应刚才的2
    for m,n in matches:
        if m.distance < 0.95 *n.distance:
            print(m.distance)
            print(m.queryIdx)
            print('---end---')
            # print(n.imgIdx)
            good.append(m)
    if len(good) > 10:
        src_pts = np.float32([sift_kp_1[i.queryIdx].pt for i in good])#.\reshape(-1, 1, 2)
        dst_pts = np.float32([sift_kp_2[i.trainIdx].pt for i in good])#.reshape(-1, 1, 2)
        # print(src_pts.shape)
        # print(dst_pts.shape)
        ransacReprojThreshold = 10.0
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, ransacReprojThreshold)
        matchesMask = mask.ravel().tolist()
        h, w, mode = img1.shape
        pts = np.float32([[0, 0], [0, h -1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)
    #透视变换函数cv2.perspectiveTransform: 输入的参数是两种数组,并返回dst矩阵——扭转矩阵
        dst = cv2.perspectiveTransform(pts, M)
        
        img2 = cv2.polylines(img2, [np.int32(dst)], True, (127,255,0), 3, cv2.LINE_AA)
    draw_params = dict(singlePointColor = None,
                   matchesMask = mask,
                   flags = 2)
    plt.plot(dst_pts[:,0],dst_pts[:,1],"ro")
    dots=dst_pts[mask[:,0]==1]
    plt.plot(dots[:,0],dots[:,1],"bo")
    plt.show()
    plt.plot(src_pts[:,0],src_pts[:,1],"go")
    dots=src_pts[mask[:,0]==1]
    plt.plot(dots[:,0],dots[:,1],"bo")
    plt.show()
    # print(dst_pts[mask,0])
    
    img3 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params)
    cv.imshow('match',img3)
    cv.waitKey(10000000)
    cv.destroyAllWindows()
    cv.waitKey(1)

Sift特征匹配以及ransac消除误差解析_第7张图片

上图是图一,描述了在左图所有的特征点中,rasac选择的正确匹配特征点
Sift特征匹配以及ransac消除误差解析_第8张图片
上图是图二,描述了在右图所有的特征点中,ransac选择的正确匹配特征点

上图是图三,最终生成的结果

在最后的代码中,知识点主要有以下几个

  1. 这种写法是输出dst_pts中mask中值为一的位置,算是一种一维数据掩膜方法
dots=dst_pts[mask[:,0]==1]
  1. match中有两组对应的匹配点,在下图中分别是m和n,代码的含义是如果m匹配对的误差低于n匹配对的误差,就把m加入优秀匹配对的列表中,也就是good
    for m,n in matches:
        if m.distance < 0.95 *n.distance:
            print(m.distance)
            print(m.queryIdx)
            print('---end---')
            # print(n.imgIdx)
            good.append(m)
  1. ransac实际上接受的是两组二维数据点,然后计算出其中符合要求的数据点,所以这个函数的应用范围其实更广,或者说,有其他的方法可以应用在这里,然后会有更好的效果,或许下一个博客试一试用SVM或者深度学习,最近几天会制作出来的,如果大家有问题欢迎留言。

你可能感兴趣的:(机器视觉,计算机视觉,算法,python,机器学习,计算机视觉,人工智能)