SLAM14讲 第七章 特征点法

Posted lingting0919

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SLAM14讲 第七章 特征点法相关的知识,希望对你有一定的参考价值。

视觉前端和优化后端

视觉里程计VO-根据相邻图像的信息估计处粗略的相机运动,给后端较好的估计值

【一】特征提取与匹配:特征点法

——运行稳定,对光照、动态物体不敏感

主要问题:根据图像来估计相机运动

特征点-路标-有代表性的点-图像信息的一种表达形式-在相机运动之后保持稳定-角点|边缘|区块

仅灰度值:受光照、形变、物体材质的影响严重【×】

SIFTSURFORB——可重复性、可区别性、高效、局部

特征点=关键点(图像中的位置、朝向、大小)+描述子(向量,周围像素)

依据【外观相似的特征有相似的描述子原则】

SIFT尺度不变特征变换 5228.7ms

FAST关键点——计算速度很快,没有描述子,不具有方向性

ORB(旋转、尺度不变性)——速度极快的二进制描述子BRIEF 1000点/15.3ms

SURF 217.3ms

 

7.1 ORB特征

Oriented FAST关键点(FAST+特征点主方向)+BRIEF特征子

1 FAST关键点

FAST角点:检测局部像素像素灰度变化明显的地方(只比较像素亮度大小)

FAST-9/11/12(半径为3的圆上16个像素点中有N个大于或小于中心点的阈值120%/80%)

FAST-12预测试:第1/5/9/13个点的情况

#非极大值抑制:一定区域内仅保留响应极大值的角点,避免集中

【缺点1】FAST特征点量大且不确定,往往希望对图像提取固定数量的特征

【改进】固定数量N,原始FAST角点计算Harries响应值

【缺点2】FAST不具有方向信息

【改进】由构建图像金字塔并在每一层检测角点实现尺度不变性,灰度质心(以图像块灰度值作为权重的中心)法实现特征旋转

2 BRIEF描述子

关键点附近两个像素p和q的大小关系,1/0,128维,随机选取

旋转后的Steer BRIEF特征

 

7.2 特征匹配(数据关联)

#场景大量重复纹理导致的误匹配问题

计算特征点之间的描述子距离,通常汉明距离,二进制不同位数的个数

特征点多时,用快速近似最近邻FLANN算法

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

int main ( int argc, char** argv )
{
    if ( argc != 3 ) //确认输入为两张图片
    {
        cout<<"usage: feature_extraction img1 img2"<<endl;
        return 1;
    }
    //-- 读取图像
    // imread C++ 模型
    // include <opencv2/imgcodecs.hpp>
    // Mat cv::imread( const String &  filename, int flags = IMREAD_COLOR)
    // 返回MAT类型,读取失败时返回空矩阵 Mat::data = NULL
    // 参数1:filename 读取的图片文件名 绝对/相对路径 要加后缀
    // 参数2:flags 读取标记,读取图片的方式,默认为IMREAD_COLOR(好像没影响)
    Mat img_1 = imread ( argv[1], IMREAD_COLOR );
    Mat img_2 = imread ( argv[2], CV_LOAD_IMAGE_COLOR );

    //-- 初始化
    std::vector<KeyPoint> keypoints_1, keypoints_2;//关键点-放置keypoint对象的一个vector
    Mat descriptors_1, descriptors_2;//描述子,cv::Mat类型
    //OpenCV提供FeatureDetector实现特征检测及匹配;
    //FeatureDetetor是虚类,通过定义FeatureDetector的对象可以使用多种特征检测方法。通过create()函数调用:
    //FASTSTARSIFTSURFORBMSERGFTTHARRISDenseSimpleBlob
    Ptr<FeatureDetector> detector = ORB::create();//ORB特征点检测
    Ptr<DescriptorExtractor> descriptor = ORB::create();//BRIEF描述子提取
    //计算特征点之间的描述子距离,通常汉明距离
    //DescriptorMatcher是匹配特征向量的抽象类,在OpenCV2中的特征匹配方法都继承自该类
    //(例如:BFmatcher,FlannBasedMatcher)。该类主要包含了两组匹配方法:图像对之间的匹配以及图像和一个图像集之间的匹配
    //DescriptorMatcher::create 对于给定参数,创建特征描述子匹配(使用默认的构造函数).
    //BruteForce(L2)、BruteForce-L1BruteForce-HammingBruteForce-HammingLUTFlannBased
    Ptr<DescriptorMatcher> matcher  = DescriptorMatcher::create ( "BruteForce-Hamming" );

    //-- 第一步:检测 Oriented FAST 角点位置
    detector->detect ( img_1,keypoints_1 );
    detector->detect ( img_2,keypoints_2 );

    //-- 第二步:根据角点位置计算 BRIEF 描述子
    descriptor->compute ( img_1, keypoints_1, descriptors_1 );
    descriptor->compute ( img_2, keypoints_2, descriptors_2 );

    Mat outimg1;
    drawKeypoints( img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
    imshow("图1 ORB特征点",outimg1);

    Mat outimg2;
    drawKeypoints( img_2, keypoints_2, outimg2, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
    imshow("图2 ORB特征点",outimg2);

    //-- 第三步:对两幅图像中的BRIEF描述子进行匹配,使用 Hamming 距离
    //DMatch是用于匹配特征关键点的特征描述子的类:查询特征描述子索引, 特征描述子索引, 训练图像索引, 以及不同特征描述子之间的距离.
    vector<DMatch> matches;
    //BFMatcher matcher ( NORM_HAMMING );
    matcher->match ( descriptors_1, descriptors_2, matches );

    //-- 第四步:匹配点对筛选
    double min_dist=10000, max_dist=0;

    //找出所有匹配之间的最小距离和最大距离, 即是最相似的和最不相似的两组点之间的距离
    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;
    }
    
    // 仅供娱乐的写法
    min_dist = min_element( matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance;
    max_dist = max_element( matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance;

    printf ( "-- Max dist : %f 
", max_dist );
    printf ( "-- Min dist : %f 
", min_dist );

    //当描述子之间的距离大于两倍的最小距离时,即认为匹配有误.但有时候最小距离会非常小,设置一个经验值30作为下限.
    std::vector< DMatch > good_matches;
    for ( int i = 0; i < descriptors_1.rows; i++ )
    {
        if ( matches[i].distance <= max ( 2*min_dist, 30.0 ))
        {
            good_matches.push_back ( matches[i] );
        }
    }

    //-- 第五步:绘制匹配结果
    Mat img_match;
    Mat img_goodmatch;
    drawMatches ( img_1, keypoints_1, img_2, keypoints_2, matches, img_match );
    drawMatches ( img_1, keypoints_1, img_2, keypoints_2, good_matches, img_goodmatch );
    imshow ( "图3 所有匹配点对", img_match );
    imshow ( "图4 优化后匹配点对-筛选小于两倍最小汉明距离或工程经验值30的点", img_goodmatch );
    imwrite ( "图3 所有匹配点对.png", img_match );
    imwrite ( "图4 优化后匹配点对筛选小于两倍最小汉明距离或工程经验值30的点.png", img_goodmatch );
    waitKey(0);

max-dist:95

min-dist:4

所有匹配点对:

技术图片

 

优化后匹配点对(小于两倍最小汉明距离的点):

技术图片

优化后匹配点对(小于两倍最小汉明距离或工程经验值30的点):

 技术图片

优化后匹配点对(小于最小和最大汉明距离中间值的点):

 技术图片

 

以上是关于SLAM14讲 第七章 特征点法的主要内容,如果未能解决你的问题,请参考以下文章

视觉SLAM特征点提取与匹配

视觉SLAM研究现状

视觉slam十四讲第七章课后习题6

slam14讲证明构成李代数

SLAM14讲 ch6 g2o曲线拟合程序问题

视觉SLAM14讲ch4心得与课后题答案仅供参考