讲解关于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() 之前,我们先了解一下什么是图像金字塔,这个东西呢,我们不用想得太复杂了,简单的说就是:
对一张图像进行连续的等比缩放(一般是缩小),把多次缩放之后的图像加上原图,我们统称为图像金字塔
如下图所示:
其上的 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/
转载文章受原作者版权保护。转载请注明原作者出处!