Advertisement

Opencv 各种特征点提取和匹配

阅读量:

opencv 特征点的提取和匹配

1. 当中的数据结构

该平台此数据结构 包含有其相关数据结构

类KeyPoint

定义angle为角度指标,在计算机视觉领域中被广泛采用以表征关键点的方向特性。SIFT算法通过计算关键点周围局部区域的梯度信息来确定其方向特征。具体而言,在这一过程中,SIFT算法会首先对目标图像中的每个候选关键点计算其所在区域的梯度分布情况,然后根据这些梯度信息确定每个关键点对应的角度方向。值得注意的是,该角度值在本系统中被设定为其取值初始化为-1

class_id:在图像分类任务中,默认情况下我们可以通过class_id标记各个特征点以实现分类目的。其默认值设置为-1

octave:代表是从金字塔哪一层提取的得到的数据。

pt:关键点点的坐标(pt.x pt.y)

response:响应程度上表示该关键点的强健度。响应不仅表示该关键点的质量如何(how good),而且具体指其角部特性。瞬间即刻理解了这一概念的本质.

size:该点直径的大小

请注意:keypoint仅包含opencv sift库检测到的特征点的基本信息,即上述提到的内容。然而,sift提取出的特征向量并不在此处存储;相反地,它们被利用SiftDescriptorExtractor提取出来,并以Mat数据结构的形式存储。新版本可以直接利用SIFT进行计算。

DMATCH 数据结构:

struct DMatch {
// 三个成员函数(构造函数)链接
DMatch() {
queryIdx = -1,
trainIdx = -1,
imgIdx = -1,
distance = std::numeric_limits::max()
}
}

DMatch(int q, int t, float d) { queryId(q), trainId(t), imgId(-1), distance(d) }

DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance ) :
queryIdx(_queryIdx), trainIdx( _trainIdx), imgIdx( _imgIdx),distance( _distance) {}
int queryIdx; //此匹配对应的查询图像的特征描述子索引(输入图1)
int trainIdx; //此匹配对应的训练(模板)图像的特征描述子索引(输入图2)
int imgIdx; //训练图像的索引(若有多个)
float distance; //两个特征向量之间的欧氏距离,越小表明匹配度越高。
booloperator < (const DMatch &m) const;
};

2. 各种的特征点

SIFT, SURF以及FAST等算法均被广泛应用于图像处理领域中

对float类型的匹配方案可用FlannBasedMatcher以及BruneForce等多种选择。对于uchar类型的匹配方案仅支持BruneForce方法。由于ORB和BRIEF特征描述子不具备自适应能力,在实际应用中仅能配合基础的BruneForce算法进行匹配。在编译链接时建议添加opencv_legacy248d.lib文件(其中release版本则为opencv_legacy248.lib并将其中的数字替换为你所使用的版本号)。推荐在编译链接阶段同时添加上述lib文件(注意针对release版本需将路径中的数字更新为你当前使用的版本号)。

具体的代码如下:

复制代码
    #include <iostream>
    #include "opencv2/opencv.hpp"
    #include "opencv2/core/core.hpp"  
    #include "opencv2/features2d/features2d.hpp"  
    #include "opencv2/highgui/highgui.hpp"  
    #include  "opencv2/legacy/legacy.hpp" // 暴力匹配的头文件
    #include  "opencv2/nonfree/nonfree.hpp"
    #include <iostream>  
    #include <vector> 
    
    #include "cv_import_static_lib.h"
    
    using namespace std;
    using namespace cv;
    
    void main(){
    
    
    Mat img_1 = imread("E:\ 3Dtestdata\ 3.jpg");
    Mat img_2 = imread("E:\ 3Dtestdata\ 4.jpg");
    if (!img_1.data || !img_2.data)
    {
        cout << "error reading images " << endl;
        return ;
    }
    
    vector<KeyPoint> keyPoints_1, keyPoints_2;
    Mat descriptors_1, descriptors_2;
    
    /*-----------------SIFT featrue Point----------------
    SIFT sift;
    sift(img_1, Mat(), keyPoints_1, descriptors_1);
    sift(img_2, Mat(), keyPoints_2, descriptors_2);
    */
    
    /*-----------------SURF featrue Point----------------
    SURF surf;
    surf(img_1, Mat(), keyPoints_1, descriptors_1);
    surf(img_2, Mat(), keyPoints_2, descriptors_2); 
    //SurfDescriptorExtractor extrator;           // another surf sift operation 
    //extrator.compute(img_1, keyPoints_1, descriptors_1);
    //extrator.compute(img_2, keyPoints_2, descriptors_2);
    */
    
    //-----------------ORB featrue Point----------------
    ORB orb;   // float Feature, can not use FlannBase Match.
    orb(img_1, Mat(), keyPoints_1, descriptors_1);
    orb(img_2, Mat(), keyPoints_2, descriptors_2);
    
    
    /*-----------------ORB featrue Point----------------
    MSER mesr;
     */
    
    /*-----------------FAST featrue Point----------------
    FastFeatureDetector fast1(100);   // 检测的阈值为40  
    FastFeatureDetector fast2(100);
    
    fast1.detect(img_1, keyPoints_1);
    fast2.detect(img_2, keyPoints_2);
    //SurfDescriptorExtractor extrator;           // another surf sift operation 
    //extrator.compute(img_1, keyPoints_1, descriptors_1);
    //extrator.compute(img_2, keyPoints_2, descriptors_2);
    
    OrbDescriptorExtractor extrator;
    extrator.compute(img_1, keyPoints_1, descriptors_1);
    extrator.compute(img_2, keyPoints_2, descriptors_2);
    */
    
    
    BruteForceMatcher<HammingLUT> matcher;// orb 等float型的
    
    //FlannBasedMatcher matcher;   // 只能 对uchar的点进行匹配
    
    vector< DMatch > matches;
    
    matcher.match(descriptors_1, descriptors_2, matches);
    
    double max_dist = 0; double min_dist = 100;
    //-- Quick calculation of max and min distances between keypoints  
    for (int i = 0; i < descriptors_1.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist < min_dist) min_dist = dist;
        if (dist > max_dist) max_dist = dist;
    }
    cout<<"-- Max dist :"<< max_dist<<endl;
    cout<<"-- Min dist :"<< min_dist<<endl;
    
    //-- Draw only "good" matches (i.e. whose distance is less than 0.6*max_dist )  
    //-- PS.- radiusMatch can also be used here.  
    vector< DMatch > good_matches;
    for (int i = 0; i < descriptors_1.rows; i++)
    {
        if (matches[i].distance < 0.6*max_dist)
        {
            good_matches.push_back(matches[i]);
        }
    }
    
    
    // vector<KeyPoint> m_LeftKey;
    // vector<KeyPoint> m_RightKey;
    // vector<DMatch> m_Matches;
    // 以上三个变量已经被计算出来,分别是提取的关键点及其匹配,下面直接计算F
    
    // 分配空间
    int ptCount = (int)matches.size();
    Mat p1(ptCount, 2, CV_32F);
    Mat p2(ptCount, 2, CV_32F);
    
    // 把Keypoint转换为Mat
    Point2f pt;
    for (int i = 0; i<ptCount; i++)
    {
        pt = keyPoints_1[matches[i].queryIdx].pt;
        p1.at<float>(i, 0) = pt.x;
        p1.at<float>(i, 1) = pt.y;
    
        pt = keyPoints_2[matches[i].trainIdx].pt;
        p2.at<float>(i, 0) = pt.x;
        p2.at<float>(i, 1) = pt.y;
    }
    
    
    // 用RANSAC方法计算 基本矩阵F
    Mat m_Fundamental;
    vector<uchar> m_RANSACStatus;
    
    m_Fundamental = findFundamentalMat(p1, p2, m_RANSACStatus, FM_RANSAC);//?????????????????
    
    // 计算野点个数
    int OutlinerCount = 0;
    for (int i = 0; i<ptCount; i++)
    {
        if (m_RANSACStatus[i] == 0) // 状态为0表示野点
        {
            OutlinerCount++;
        }
    }
    
    // 计算内点
    vector<Point2f> m_LeftInlier;
    vector<Point2f> m_RightInlier;
    vector<DMatch> m_InlierMatches;
    // 上面三个变量用于保存内点和匹配关系
    int InlinerCount = ptCount - OutlinerCount;
    m_InlierMatches.resize(InlinerCount);
    m_LeftInlier.resize(InlinerCount);
    m_RightInlier.resize(InlinerCount);
    InlinerCount = 0;
    for (int i = 0; i<ptCount; i++)
    {
        if (m_RANSACStatus[i] != 0)
        {
            m_LeftInlier[InlinerCount].x = p1.at<float>(i, 0);
            m_LeftInlier[InlinerCount].y = p1.at<float>(i, 1);
            m_RightInlier[InlinerCount].x = p2.at<float>(i, 0);
            m_RightInlier[InlinerCount].y = p2.at<float>(i, 1);
            m_InlierMatches[InlinerCount].queryIdx = InlinerCount;
            m_InlierMatches[InlinerCount].trainIdx = InlinerCount;
            InlinerCount++;
        }
    }
    
    // 把内点转换为drawMatches可以使用的格式
    vector<KeyPoint> key1(InlinerCount);
    vector<KeyPoint> key2(InlinerCount);
    KeyPoint::convert(m_LeftInlier, key1);
    KeyPoint::convert(m_RightInlier, key2);
    
    // 显示计算F过后的内点匹配
     //Mat m_matLeftImage;
     //Mat m_matRightImage;
    // 以上两个变量保存的是左右两幅图像
    Mat OutImage;
    drawMatches(img_1, key1, img_2, key2, m_InlierMatches, OutImage);
    
    //stereoRectifyUncalibrated();
    
    Mat img_matches;
    drawMatches(img_1, keyPoints_1, img_2, keyPoints_2,
    good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
    vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    
    imwrite("FASTResult.jpg", img_matches);
    imshow("Match", img_matches);
    
    imwrite("FmatrixResult.jpg", OutImage);
    imshow("Match2", OutImage);
    waitKey(0);
    
    return;
    }
这是匹配的效果,用过RANSAC处理以后的效果

做好匹配以后,对于以后的三维重建都很有帮助。

全部评论 (0)

还没有任何评论哟~