您当前的位置: 首页 > 
  • 3浏览

    0关注

    417博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

(01)ORB-SLAM2源码无死角解析-(06) 图像金字塔_ORB特征点

江南才尽,年少无知! 发布时间:2022-03-12 11:36:32 ,浏览量:3

讲解关于slam一系列文章汇总链接:史上最全slam从零开始,针对于本栏目讲解的(01)ORB-SLAM2源码无死角解析链接如下(本文内容来自计算机视觉life ORB-SLAM2 课程课件): (01)ORB-SLAM2源码无死角解析-(00)目录_最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/123092196   文末正下方中心提供了本人 联系方式, 点击本人照片即可显示 W X → 官方认证 {\color{blue}{文末正下方中心}提供了本人 \color{red} 联系方式,\color{blue}点击本人照片即可显示WX→官方认证} 文末正下方中心提供了本人联系方式,点击本人照片即可显示WX→官方认证  

一、前言

上一节我们说到了 src/Frame.cc 中的 Frame::Frame() 函数,调用了比较重要的两个函数:

    // ORB extraction
	// Step 3 对这个单目图像进行提取特征点, 第一个参数0-左图, 1-右图
    ExtractORB(0,imGray);
    // Step 4 用OpenCV的矫正函数、内参对提取到的特征点进行矫正 
    UndistortKeyPoints();

我们首先对 ExtractORB() 进行讲解,UndistortKeyPoints() 放到后面的章节。进入 ExtractORB 函数,可以看到其实现如下:

void Frame::ExtractORB(int flag, const cv::Mat &im)
{
    // 判断是左图还是右图
    if(flag==0)
        // 左图的话就套使用左图指定的特征点提取器,并将提取结果保存到对应的变量中 
        // 这里使用了仿函数来完成,重载了括号运算符 ORBextractor::operator() 
        (*mpORBextractorLeft)(im,				//待提取特征点的图像
							  cv::Mat(),		//掩摸图像, 实际没有用到
							  mvKeys,			//输出变量,用于保存提取后的特征点
							  mDescriptors);	//输出变量,用于保存特征点的描述子
    else
        // 右图的话就需要使用右图指定的特征点提取器,并将提取结果保存到对应的变量中 
        (*mpORBextractorRight)(im,cv::Mat(),mvKeysRight,mDescriptorsRight);
}

可以看到,其主要是通过 mpORBextractorLeft,或者 mpORBextractorRight 调用函数,通过前面的章节我们可以知道这两个类对象是在 Tracking::Tracking 构造函数中创建的:

    // tracking过程都会用到mpORBextractorLeft作为特征点提取器
    mpORBextractorLeft = new ORBextractor(
        nFeatures,      //参数的含义还是看上面的注释吧
        fScaleFactor,
        nLevels,
        fIniThFAST,
        fMinThFAST);

    // 如果是双目,tracking过程中还会用用到mpORBextractorRight作为右目特征点提取器
    if(sensor==System::STEREO)
        mpORBextractorRight = new ORBextractor(nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);

    // 在单目初始化的时候,会用mpIniORBextractor来作为特征点提取器
    if(sensor==System::MONOCULAR)
        mpIniORBextractor = new ORBextractor(2*nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);

可以看到,其核心关键在于类 ORBextractor,前面的:

        (*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors);
        # 或者
        (*mpORBextractorRight)(im,cv::Mat(),mvKeysRight,mDescriptorsRight);

其本质上调用的是 src\ORBextractor.cc 文件中的 ORBextractor::operator() 函数。暂且不论,我们想来了解一下 图像金字塔 与 特征点的相关知识

 

二、图像金字塔

在讨论构造函数 ORBextractor::ORBextractor() 之前,我们先了解一下什么是图像金字塔,这个东西呢,我们不用想得太复杂了,简单的说就是:

	对一张图像进行连续的等比缩放(一般是缩小),把多次缩放之后的图像加上原图,我们统称为图像金字塔

如下图所示: 在这里插入图片描述 其上的 Level 0 表示原图, Level 1 则为 按照缩放因子 f 进行第一次缩放的结果,Level 2 则是在 Level 1 的基础上,按照放因子 f 再次进行缩放之后的结果。这样一次循环叠加,形成了上面的图像金字塔。使用图像金字塔,我们可以提取到图像各个尺寸的关键点,这样增加了算法的鲁棒性。了解图像金字塔之后,我们在来看看fast特征是什么。

 

三、ORB特征点

说到 fast特征 之前,我们先来说说ORB特征,特征点一般具备如下性质(SIFT、SURF、ORB等特征点):

	1、可重复性:即相同的“区域“可以在不同的图像中找到(比如将特征点比作一只猫,在图一和图二中都能找到这只猫)。
	2、可区别性:即不同的”区域“有不同的表达。
	3、高效率:在同一副图像中,特征点的数量应该远小于像素的数量。
	4、本地性:特征仅与一小片图像区域相关。

特征点主要由关键点与描述子两个部分组成:         关键点: 通常是指该特征点在图像中的位置,有的特征点还具有朝向、大小等信息。         描述子: 通常是一个向量,按照认为设计的方式,描述了该关键点周围像素的信息。描述子的设计原则是外观相似的特征应该有相似的描述子。

O R B 特征 : \color{red}{ORB特征:} ORB特征:特征也是由关键点和描述子组成。正如其英文全名一样,这种特征使用的特征点是”Oriented FAST“,描述子是”Rotated BRIEF“。其实这两种关键点与描述子都是在ORB特征出现之前就已经存在了,ORB特征的作者将二者进行了一定程度的改进,并将这两者巧妙地结合在一起,得出一种可以快速提取的特征--ORB特征。ORB特征在速度方面相较于SIFT、SURF已经有明显的提升的同时,保持了特征子具有旋转与尺度不变性。

对于 Oriented FAST 关键点与 Rotated BRIEF 描述子,我们在下篇博客进行详细的讲解这篇博客我们先来看看代码。

 

四、代码实现

该篇博客的前言部分我们提到了 Frame::ExtractORB() 函数,本质上调用的是 src\ORBextractor.cc 文件中的 ORBextractor::operator() 函数,在讲解该函数之前,我们先来看看 ORBextractor::ORBextractor() 构造函数,其主要执行了以下流程:

	# ORBextractor.scaleFactor参数默认为1.2  ORBextractor.nLevels默认为8,表示8层金字塔
	1、获取每层金字塔的缩放因子,以及缩放因子的方平(主要用于面积计算),缩放因子来自
	yaml配置文件中的 ORBextractor.scaleFactor 参数。
		(1)mvScaleFactor,mvInvScaleFactor = 每层金字塔缩放因子,缩放因子的倒数
	    (2)mvLevelSigma2,mvInvLevelSigma2 = 每层金字塔缩放因子平方,缩放因子平方的倒数
	
	# ORBextractor.nFeatures: 1000, 表示所有金字塔一共需要提取1000个特征点
	2、mnFeaturesPerLevel:用于存储每层图像金字塔应该提取的特征点数目,其分配方式主要根据	  
	面积进行计算。面积越大,提取的特征数目越多。如果按按面积分配特征点出现多余,未分配的特征
	点,默认分配给最后一层金字塔(最小的那一层)

	
	3、pattern0:其主要和描述子相关,暂时不做详细讲解
	   umax:其主要和描述子相关主要用于记录X的坐标的最大值,暂时不用理会即可

其构造函数的代码注释如下:

//特征点提取器的构造函数

ORBextractor::ORBextractor(int _nfeatures,		//指定要提取的特征点数目
                           float _scaleFactor,	//指定图像金字塔的缩放系数
                           int _nlevels,		//指定图像金字塔的层数
                           int _iniThFAST,		//指定初始的FAST特征点提取参数,可以提取出最明显的角点
                           int _minThFAST):		//如果初始阈值没有检测到角点,降低到这个阈值提取出弱一点的角点
    nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels),
    iniThFAST(_iniThFAST), minThFAST(_minThFAST)//设置这些参数
{
    //存储每层图像缩放系数的vector调整为符合图层数目的大小
    mvScaleFactor.resize(nlevels);  
    //存储这个sigma^2,其实就是每层图像相对初始图像缩放因子的平方
    mvLevelSigma2.resize(nlevels);
    //对于初始图像,这两个参数都是1
    mvScaleFactor[0]=1.0f;
    mvLevelSigma2[0]=1.0f;
    //然后逐层计算图像金字塔中图像相当于初始图像的缩放系数 
    for(int i=1; i            
关注
打赏
1592542134
查看更多评论
0.0392s