ORB-SLAM2系列第一章——简介

欢迎浏览我的SLAM专栏,一起加油淦穿SLAM!

文章目录

  • 前言
  • 一、ORB-SLAM2特点
  • 二、 算法流程框架
    • 1.主体框架
    • 2.数据输入的预处理
  • 三、安装教程
  • 四、TUM 数据集介绍及使用
    • 1.RGBD模式下在TUM数据集上的表现
    • 2.TUM RGB-D 数据集 简介
    • 3.RGBD模式下运行时数据预处理
  • 五、可视化运行效果解析
  • 六、 变量命名规范


前言

2015年,西班牙萨拉戈萨大学机器人感知与实时研究组开源了ORB-SLAM第一个版本,由于其出色的效果受到广泛关注。该团队分别在
2016年和2020年开源了第二个版本ORB-SLAM2和第三个版本ORB-SLAM3。


一、ORB-SLAM2特点

ORB-SLAM2有如下优点:

  • 支持单目,双目和RGB-D相机的完整开源SLAM方案,能够实现地图重用、回环检测和重新定位的功能。
  • 能够实时计算出相机的位姿,并生成场景的稀疏三维重建地图。
  • 支持轻量级定位模式,可以达到零漂移,此时不使用局部建图和回环检测的线程,可以用视觉里程计来跟踪未建图区域。
  • 采用ORB特征,具有旋转不变性、光照不变性、尺度不变性,匹配速度快,适合实时应用。
  • 能够在CPU上进行实时工作,可以用于移动终端如 移动机器人、手机、无人机、汽车。
  • 跟踪、局部地图、闭环、重定位等所有的任务都采用相同的ORB特征,使得系统内数据交互更高效、稳定可靠。
  • 单目初始化和应用场景解耦,不管是平面还是非平面场景,都可以自动初始化,无需人工干预。
  • 双目和RGB-D相对单目相机的主要优势在于,可以直接获得深度信息,不需要像单目情况中那样做一个特定的SFM初始化。
  • 地图点和关键帧创建比较宽松,但后续会进行严格筛选,剔除冗余关键帧和误差大的地图点,增加建图过程的弹性,在大旋转、快速运动、纹理不足等恶劣情况下可以提高跟踪的鲁棒性。
  • 采用共视图,使得跟踪和建图控制在局部共视区域,与全局地图大小无关,可以在大场景下运行。
  • 使用本质图(Essential Graph)来优化位姿实现回环检测,耗时少精度高 。相比于直接法,可以用于宽基线特征匹配,更适合于对深度精度要求较高的场景,比如三维重建。
  • 定位精度高,可达厘米级,是特征点法SLAM的经典代表作品。
  • 代码可读性强,包含很多工程化技巧,非常实用。

ORB-SLAM2作者也指出了该框架的不足之处:

  • 相比于直接法SLAM框架,特征提取部分比较耗时,运行速度没有直接法快。
  • 相比于直接法SLAM框架,在弱纹理、重复纹理、图像模糊的场景下容易跟踪丢失。
  • 产生的定位地图比较稀疏,应用有限。

二、 算法流程框架

1.主体框架

这是ORB-SLAM2文章中的系统线程和模块框架:
ORB-SLAM2系列第一章——简介_第1张图片
汉化一下如图:
ORB-SLAM2系列第一章——简介_第2张图片
上图中,单目的初始化比较复杂,双目比较容易,后几章会讲。地图初始化后就相当于以及生成了一些地图点了,就可以用这些地图点开始跟踪。跟踪(初步的粗糙跟踪)分为三种:恒速模型跟踪、参考关键帧跟踪、重定位跟踪。地图初始化后首先会根据参考关键帧来跟踪,初始化成功的那一帧就是参考关键帧。参考关键帧跟踪成功后,后续就是恒速模型跟踪,恒速意思是帧与帧之间在极短的时间内的速度是恒定的,可以做粗糙的预测,根据前边的速度预测后边帧的位置,大部分时间都是恒速模型跟踪。若跟丢了就启用重定位跟踪,比较复杂。第二阶段是局部地图跟踪,能保证跟踪更加精细。跟踪过程中有很多冗余的地图点需要踢掉,再关键帧之间做一些匹配生成新的地图点。经过优化后的关键帧进入闭环线程,首先通过词袋来查询,词袋就是图中的视觉字典,查询是否数据集是否闭环。视觉字典是作者做的,自己也能做,但不一定有他的全。当前关键帧和闭环后关键帧的SIM3计算(similar相似,3是三维空间)。单目下优化考虑尺度,双目有绝对尺度。闭环识别就是检测是否已经闭环,确定闭环后进行矫正。本质图优化是对当前地图的所有关键帧做一个位姿优化,比较快。后面在做一个全局的BA是整个地图的位姿和地图点都会优化,比较慢。

通过框架图可以总结如下:

  • 输入:有三种模式可以选择:单目模式、双目模式和RGB-D模式。
  • 跟踪:初始化成功后首先会选择参考关键帧跟踪,然后大部分时间都是恒速模型跟踪,当跟踪丢失的时候启动重定位跟踪,在经过以上
    跟踪后可以估计初步的位姿,然后经过局部地图跟踪对位姿进行进一步优化。同时会根据条件判断是否需要将当前帧新建为关键帧。
  • 局部建图:输入的关键帧来自跟踪里新建的关键帧。为了增加局部地图点数目,局部地图里关键帧之间会重新进行特征匹配,生成新的
    地图点,局部BA会同时优化共视图里的关键帧位姿和地图点,优化后也会删除不准确的地图点和冗余的关键帧。
  • 闭环:通过词袋来查询数据集检测是否闭环,计算当前关键帧和闭环候选关键帧之间的Sim3位姿,仅在单目时考虑尺度,双目或RGBD模式下尺度固定为1。然后执行闭环融合和本质图优化,使得所有关键帧位姿更准确。
  • 全局BA:优化所有的关键帧及其地图点。
  • 位置识别:需要导入离线训练好的字典,这个字典是由视觉词袋模型构建的。新输入的图像帧需要先在线转化为词袋向量,主要应用于
    特征匹配、重定位、闭环。
  • 地图:地图主要由地图点和关键帧组成。关键帧之间根据共视地图点数目组成了共视图,根据父子关系组成了生成树。

2.数据输入的预处理

为了兼容不同相机(双目相机与RGBD相机),需要对输入数据进行预处理,使得交给后期处理的数据格式一致,具体流程如下:
ORB-SLAM2系列第一章——简介_第3张图片
如上图,单目不用管,双目的话要做rectified stereo即矫正,然后左右点提取ORB特征点,做立体匹配,然后去矫正。RGB-D需要做对齐,把rgb的depth和rgb做一个对齐的操作,这个需要我们提前标定好内参。开源的数据集都是已经处理好的。


三、安装教程

详见:
slam的环境配置大全–保姆教学
ORB_SLAM2代码的简介安装运行


四、TUM 数据集介绍及使用

1.RGBD模式下在TUM数据集上的表现

ORB-SLAM2系列第一章——简介_第4张图片

2.TUM RGB-D 数据集 简介

注意两点:深度的表达方式 以及 数据的存储格式:
ORB-SLAM2系列第一章——简介_第5张图片

3.RGBD模式下运行时数据预处理

关于associate.py
注意:只能在Python2 环境下运行
Python下运行
python associate.py rgb.txt depth.txt > associate.txt
python associate.py associate.txt groundtruth.txt > associate_with_groundtruth.txt
注意:
直接association后出问题,生成的结果
./Examples/Monocular/mono_tum Vocabulary/ORBvoc.txt Examples/Monocular/TUM1.yaml
Data/rgbd_dataset_freburg1_desk
associate.txt 1641行
associate_with_groundtruth.txt 1637行
也就是说,associate的不一定有groundtruth,所以要以associate_with_groundtruth.txt的关联结果为准


五、可视化运行效果解析

运行的中间结果截图如下所示,对重点信息进行了标注
ORB-SLAM2系列第一章——简介_第6张图片
不同颜色地图点的含义解析
红色点表示参考地图点,其实就是tracking里的local mappoints

void Tracking::UpdateLocalMap()
{
// This is for visualization
mpMap->SetReferenceMapPoints(mvpLocalMapPoints);
// Update
UpdateLocalKeyFrames();
UpdateLocalPoints();
}

黑色点表示所有地图点,红色点属于黑色点的一部分

void MapDrawer::DrawMapPoints()
{
const vector<MapPoint*> &vpMPs = mpMap->GetAllMapPoints();
const vector<MapPoint*> &vpRefMPs = mpMap->GetReferenceMapPoints();
set<MapPoint*> spRefMPs(vpRefMPs.begin(), vpRefMPs.end());
if(vpMPs.empty())
return;
glPointSize(mPointSize);
glBegin(GL_POINTS);
glColor3f(0.0,0.0,0.0);
for(size_t i=0, iend=vpMPs.size(); i<iend;i++)
{
if(vpMPs[i]->isBad() || spRefMPs.count(vpMPs[i]))
continue;
cv::Mat pos = vpMPs[i]->GetWorldPos();
glVertex3f(pos.at<float>(0),pos.at<float>(1),pos.at<float>(2));
}
glEnd();
glPointSize(mPointSize);
glBegin(GL_POINTS);
glColor3f(1.0,0.0,0.0);
for(set<MapPoint*>::iterator sit=spRefMPs.begin(), send=spRefMPs.end(); sit!=send; sit++)
{
if((*sit)->isBad())
continue;
cv::Mat pos = (*sit)->GetWorldPos();
glVertex3f(pos.at<float>(0),pos.at<float>(1),pos.at<float>(2));
}
glEnd();
}

ORB-SLAM2系列第一章——简介_第7张图片


六、 变量命名规范

后面几章会有大量的源码详解,在介绍之前,我们有必要先了解一下在ORB-SLAM2中变量的命名规则,这对我们学习代码非常有用。
以小写字母m(member的首字母)开头的变量表示类的成员变量。比如:

int mSensor;
int mTrackingState;
std::mutex mMutexMode;

对于某些复杂的数据类型,第2个甚至第3个字母也有一定的意义,比如:
mp开头的变量表示指针(pointer)型类成员变量:

Tracking* mpTracker;
LocalMapping* mpLocalMapper;
LoopClosing* mpLoopCloser;
Viewer* mpViewer;

mb开头的变量表示布尔(bool)型类成员变量:

bool mbOnlyTracking;

mv开头的变量表示向量(vector)型类成员变量:

std::vector<int> mvIniLastMatches;
std::vector<cv::Point3f> mvIniP3D;

mpt开头的变量表示指针(pointer)型类成员变量,并且它是一个线程(thread):

std::thread* mptLocalMapping;
std::thread* mptLoopClosing;
std::thread* mptViewer;

ml开头的变量表示列表(list)型类成员变量;
mlp开头的变量表示列表(list)型类成员变量,并且它的元素类型是指针(pointer);
mlb开头的变量表示列表(list)型类成员变量,并且它的元素类型是布尔型(bool):

list<double> mlFrameTimes;
list<bool> mlbLost;
list<cv::Mat> mlRelativeFramePoses;
list<KeyFrame*> mlpReferences;

总结一下:
以小写字母m(member的首字母)开头的变量表示类的成员变量;
对于某些复杂的数据类型,第2个甚至第3个字母也有一定的意义;
mp开头的变量表示指针(pointer)型类成员变量;
mb开头的变量表示布尔(bool)型类成员变量;
mv开头的变量表示向量(vector)型类成员变量;
mpt开头的变量表示指针(pointer)型类成员变量,并且它是一个线程(thread)。

你可能感兴趣的:(slam,SLAM,ORB-SLAM2)