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

讲解关于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→官方认证}文末正下方中心提供了本人联系方式,点击本人照片即可显示W X →官方认证

一、前言

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


    ExtractORB(0,imGray);

    UndistortKeyPoints();

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

void Frame::ExtractORB(int flag, const cv::Mat &im)
{

    if(flag==0)

        (*mpORBextractorLeft)(im,
                              cv::Mat(),
                              mvKeys,
                              mDescriptors);
    else

        (*mpORBextractorRight)(im,cv::Mat(),mvKeysRight,mDescriptorsRight);
}

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


    mpORBextractorLeft = new ORBextractor(
        nFeatures,
        fScaleFactor,
        nLevels,
        fIniThFAST,
        fMinThFAST);

    if(sensor==System::STEREO)
        mpORBextractorRight = new ORBextractor(nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);

    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() 之前,我们先了解一下什么是图像金字塔,这个东西呢,我们不用想得太复杂了,简单的说就是:

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

如下图所示:

(01)ORB-SLAM2源码无死角解析-(06) 图像金字塔_ORB特征点
其上的 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() 构造函数,其主要执行了以下流程:


    1、获取每层金字塔的缩放因子,以及缩放因子的方平(主要用于面积计算),缩放因子来自
    yaml配置文件中的 ORBextractor.scaleFactor 参数。
        (1)mvScaleFactor,mvInvScaleFactor = 每层金字塔缩放因子,缩放因子的倒数
        (2)mvLevelSigma2,mvInvLevelSigma2 = 每层金字塔缩放因子平方,缩放因子平方的倒数

    2、mnFeaturesPerLevel:用于存储每层图像金字塔应该提取的特征点数目,其分配方式主要根据
    面积进行计算。面积越大,提取的特征数目越多。如果按按面积分配特征点出现多余,未分配的特征
    点,默认分配给最后一层金字塔(最小的那一层)

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

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


ORBextractor::ORBextractor(int _nfeatures,
                           float _scaleFactor,
                           int _nlevels,
                           int _iniThFAST,
                           int _minThFAST):
    nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels),
    iniThFAST(_iniThFAST), minThFAST(_minThFAST)
{

    mvScaleFactor.resize(nlevels);

    mvLevelSigma2.resize(nlevels);

    mvScaleFactor[0]=1.0f;
    mvLevelSigma2[0]=1.0f;

    for(int i=1; i<nlevels; i++)
    {

        mvScaleFactor[i]=mvScaleFactor[i-1]*scaleFactor;

        mvLevelSigma2[i]=mvScaleFactor[i]*mvScaleFactor[i];
    }

    mvInvScaleFactor.resize(nlevels);
    mvInvLevelSigma2.resize(nlevels);
    for(int i=0; i<nlevels; i++)
    {
        mvInvScaleFactor[i]=1.0f/mvScaleFactor[i];
        mvInvLevelSigma2[i]=1.0f/mvLevelSigma2[i];
    }

    mvImagePyramid.resize(nlevels);

    mnFeaturesPerLevel.resize(nlevels);

    float factor = 1.0f / scaleFactor;

    float nDesiredFeaturesPerScale = nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels));

    int sumFeatures = 0;

    for( int level = 0; level < nlevels-1; level++ )
    {

        mnFeaturesPerLevel[level] = cvRound(nDesiredFeaturesPerScale);

        sumFeatures += mnFeaturesPerLevel[level];

        nDesiredFeaturesPerScale *= factor;
    }

    mnFeaturesPerLevel[nlevels-1] = std::max(nfeatures - sumFeatures, 0);

    const int npoints = 512;

    const Point* pattern0 = (const Point*)bit_pattern_31_;

    std::copy(pattern0, pattern0 + npoints, std::back_inserter(pattern));

    umax.resize(HALF_PATCH_SIZE + 1);

    int v,
        v0,
        vmax = cvFloor(HALF_PATCH_SIZE * sqrt(2.f) / 2 + 1);

    int vmin = cvCeil(HALF_PATCH_SIZE * sqrt(2.f) / 2);

    const double hp2 = HALF_PATCH_SIZE*HALF_PATCH_SIZE;

    for (v = 0; v  vmax; ++v)
        umax[v] = cvRound(sqrt(hp2 - v * v));

    for (v = HALF_PATCH_SIZE, v0 = 0; v >= vmin; --v)
    {
        while (umax[v0] == umax[v0 + 1])
            ++v0;
        umax[v] = v0;
        DEBUG("%d=%d", v, v0);
        ++v0;
    }
}

四、结语

该章节主要讲解什么金字塔,以及特征点。并且提及到特征点包含了关键点以及描述子两个部分,但是没有做详细的介绍,再下一篇博客中会进行具体的讲解。最后我们还了解了ORBextractor 的构造函数,主要为接下来的内容做铺垫。

本文内容来自计算机视觉life ORB-SLAM2 课程课件

Original: https://blog.csdn.net/weixin_43013761/article/details/123440647
Author: 江南才尽,年少无知!
Title: (01)ORB-SLAM2源码无死角解析-(06) 图像金字塔_ORB特征点

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/559681/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球