前言
ORB_SLAM3代码对于个人而言,感觉十分复杂。因为没有一些几何视图基础加上C++薄弱,所以一直没法入门。基于这种状况,我打算一点一点的学习该代码。每次学一个函数,一个类或者一个几何知识,这样积少成多总归能学会。同时,防止我学完就忘,因此我每次都总结成一篇文章督促自己尽快学完,随时复习。
本次代码的运行以单目相机为例,因此代码中有关双目、RGBD的部分我可能都会直接跳过。不过一个通了,另外两个应该也差别不大。
另外,由于是初次学,所以里面会有很多不太清楚的变量,我都会用TODO标注,后续补充。
本次System类的初始化主要介绍两个部分:
- system.h 库文件。
- system类的初始化函数。
涉及文件 | - |
---|---|
库文件 | System.h |
源文件 | System.cc |
参考资料:
1. 5小时让你假装大概看懂ORB-SLAM2源码
2. ORB_SLAM3的源码,作者:UZ-SLAMLab
1. 代码调用位置
// slam.cc中
ORB_SLAM3::System SLAM(argv[1], argv[2], ORB_SLAM3::System::MONOCULAR, argv[argc-1], show);
2. 前置知识
2.1 Sophus::SE3f
通过Sophus库来获取刚体的变化矩阵,矩阵的维数为4x4。其中R为旋转矩阵,表示刚体的旋转变化,维数为3x3。t为位移矩阵,表示刚体的位移变化,维数为3x1。
S E ( 3 ) = { T = [ R t 0 T 1 ] ∈ R 4 x 4 ∣ R ∈ S O ( 3 ) , t = R 3 } SE(3)=\begin{Bmatrix}T=\begin{bmatrix} R & t \\ 0^T & 1 \end{bmatrix}\in{R^{4x4}}|R\in{SO(3),t=R^3} \end{Bmatrix} SE(3)={T=[R0Tt1]∈R4x4∣R∈SO(3),t=R3}
代码表示:
#include <iostream>
#include <cmath>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include "sophus/se3.hpp"
using namespace std;
using namespace Eigen;
int main()
{
// 定义平移矢量(沿X轴平移1)
Vector3f t(1, 0, 0);
cout << "平移矢量 t\n" << t.matrix() << endl;
// -----------------------------------
// 定义旋转矩阵(绕Z轴旋转90°)
// -----------------------------------
Matrix3f R = AngleAxisf(M_PI / 2, Vector3f(0, 0, 1)).toRotationMatrix();
cout << "旋转矩阵 R\n" << R.matrix() << endl;
// 从旋转矩阵进行构建SE(3)
Sophus::SE3f SE3_Rt(R,t);
cout << "变化矩阵 SE(3)\n" << SE3_Rt.matrix() << endl;
// -----------------------------------
// 定义四元数
// -----------------------------------
Quaternionf q(R);
// 从四元数进行构建SE(3)
Sophus::SE3f SE3_qt(q,t);
// 输出李群内容
cout << "四元数 SE(3)\n" << SE3_qt.matrix() << endl;
return 0;
}
输出:
3. 代码细节
3.1 System.h:
System.h分成以下几个部分:
- 枚举变量
- system初始化函数
- 追踪方法(单目,双目,RGBD)
- 对slam的控制操作
- 对slam的保存操作
- 对当前帧的相关操作
- debugging相关(TODO:不太懂,后续补充)
- REGISTER_TIMES相关(TODO:不太懂,后续补充)
- Atlas地图集操作
- 创建一些指向class的类指针
- 线程管理
- flag管理
- 文件名字管理
class System
{
public:
// ============================================================
// 公开的成员变量
// ============================================================
// 1 两个枚举类型,eSensor表示相机类型。
enum eSensor{
MONOCULAR=0, //单目
STEREO=1, //双目
RGBD=2, //RGBD
IMU_MONOCULAR=3, //IMU和单目
IMU_STEREO=4, //IMU和双目
IMU_RGBD=5, //IMU和RGBD
};
// 2. 枚举类型 FileType 文件类型
enum FileType{
TEXT_FILE=0, //文本
BINARY_FILE=1, //二进制
};
// ------------------------------------------------------------
public:
// ============================================================
// 公开的成员函数
// ============================================================
// EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) 是否需要校准
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
// ------------------------------------------------------------
// System初始化
// ------------------------------------------------------------
System(
const string &strVocFile, // ../Vocabulary/ORBvoc.txt文件所在路径。
const string &strSettingsFile, // 相机参数文件路径。(eg:EuRoc.yaml)。
const eSensor sensor, // 枚举变量,表示相机类型(eg: ORB_SLAM3::System::MONOCULAR)。
const string &save_path, // 保存路径(这是我加的,原本保存路径保存在相机参数文件中)。
const bool bUseViewer = true, // 是否进行可视化显示。
const int initFr = 0, // TODO:目前没遇到,后续补充。
const string &strSequence = std::string() // TODO:目前没遇到,后续补充。
);
// ------------------------------------------------------------
// 追踪方法
// ------------------------------------------------------------
// 处理双目帧,双目图像必须是同步和纠正后的。
// 输入图像可以是RGB(CV_8UC3)或者灰度(CV_8U)(其中RGB要转化为灰度)。
// 结果返回当前相机姿态。(追踪失败则返回空)
Sophus::SE3f TrackStereo(
const cv::Mat &imLeft, //当前左目帧
const cv::Mat &imRight, //当前右目帧
const double ×tamp, //当前双目帧的时间戳
const vector<IMU::Point>& vImuMeas = vector<IMU::Point>(), // imu数据(TODO:这个没用过过,等待后续补充)
string filename="" //当前图像名
);
// 处理RGBD帧,深度图像必须是同步和纠正后的。
// 输入图像可以是RGB(CV_8UC3)或者灰度(CV_8U)(其中RGB要转化为灰度)。
// 输入深度图像:Float (CV_32F)。
// 结果返回当前相机姿态。(追踪失败则返回空)
Sophus::SE3f TrackRGBD(
const cv::Mat &im, //当前RGB帧
const cv::Mat &depthmap, //当前深度帧
const double ×tamp, //当前帧的时间戳
const vector<IMU::Point>& vImuMeas = vector<IMU::Point>(), // imu数据(TODO:这个没用过过,等待后续补充)
string filename="" //当前图像名
);
// 处理单目帧(可选imu数据)
// 输入图像可以是RGB(CV_8UC3)或者灰度(CV_8U)(其中RGB要转化为灰度)。
// 结果返回当前相机姿态。(追踪失败则返回空)
Sophus::SE3f TrackMonocular(
const cv::Mat &im, //当前单目帧
const double ×tamp, //当前帧的时间戳
string filename="", //当前图像名
const vector<IMU::Point>& vImuMeas = vector<IMU::Point>() // imu数据(TODO:这个没用过过,等待后续补充)
);
// ------------------------------------------------------------
// 对SLAM的相关操作
// ------------------------------------------------------------
// 1 控制local mapping线程
// 停止后续的local mapping线程,并且仅执行相机追踪。
void ActivateLocalizationMode();
// 恢复local mapping线程,并且重新执行SLAM。
void DeactivateLocalizationMode();
// 2 查看地图变化
// 自上次调用此函数以来,如果发生大地图变化(loop closure, global BA)则返回true
bool MapChanged();
// 3 重置系统
// 重置系统(清除Atlas(地图集))
void Reset();
// 重置系统(active map(激活建图?))
void ResetActiveMap();
// 4 关闭系统
// 所有线程关闭(函数必须在保存轨迹前调用)
void Shutdown();
// 查看线程是否关闭完成。
bool isShutDown();
// ------------------------------------------------------------
// 保存相关操作
// ------------------------------------------------------------
// 以TUM RGB-D数据格式来保存轨迹。
// 输入要求:仅支持双目和RGBD数据。无法工作在单目上。
// 看数据格式细节: http://vision.in.tum.de/data/datasets/rgbd-dataset
// 注意事项:必须之前调用shutdown。
void SaveTrajectoryTUM(const string &filename);
// 以TUM RGB-D数据格式来保存关键帧姿态。
// 输入要求:支持所有的传感器输入。
// 看数据格式细节: http://vision.in.tum.de/data/datasets/rgbd-dataset
// 注意事项:必须之前调用shutdown。
void SaveKeyFrameTrajectoryTUM(const string &filename);
// 以EuRoC数据格式来保存轨迹。
// 注意事项:必须之前调用shutdown。
void SaveTrajectoryEuRoC(const string &filename);
// 以EuRoC数据格式来保存关键帧姿态。
// 注意事项:必须之前调用shutdown。
void SaveKeyFrameTrajectoryEuRoC(const string &filename);
// 以EuRoC数据格式来保存轨迹。上面SaveTrajectoryEuRoC的重载,添加了Map数据。
void SaveTrajectoryEuRoC(const string &filename, Map* pMap);
// 以EuRoC数据格式来保存关键帧姿态。上面SaveKeyFrameTrajectoryEuRoC的重载,添加了Map数据。
void SaveKeyFrameTrajectoryEuRoC(const string &filename, Map* pMap);
// 保存用于初始化调试的数据(TODO:目前没用过,后续添加)
void SaveDebugData(const int &iniIdx);
// 以KITTI数据格式来保存轨迹。
// 输入要求:仅支持双目和RGBD数据。无法工作在单目上。
// 看数据格式细节: http://www.cvlibs.net/datasets/kitti/eval_odometry.php
// 注意事项:必须之前调用shutdown。
void SaveTrajectoryKITTI(const string &filename);
// TODO: Save/Load functions
// SaveMap(const string &filename);
// LoadMap(const string &filename);
// ------------------------------------------------------------
// 对SLAM处理的当前帧的相关操作
// ------------------------------------------------------------
// 最近处理过的帧的信息,可以在追踪函数后调用
int GetTrackingState();
std::vector<MapPoint*> GetTrackedMapPoints();
std::vector<cv::KeyPoint> GetTrackedKeyPointsUn();
// ------------------------------------------------------------
// debugging相关(TODO:不太懂,后续补充)
// ------------------------------------------------------------
double GetTimeFromIMUInit();
bool isLost();
bool isFinished();
void ChangeDataset();
float GetImageScale();
// ------------------------------------------------------------
// REGISTER_TIMES相关(TODO:不太懂,后续补充)
// ------------------------------------------------------------
#ifdef REGISTER_TIMES
void InsertRectTime(double& time);
void InsertResizeTime(double& time);
void InsertTrackTime(double& time);
#endif
private:
// ============================================================
// 私有的成员函数
// ============================================================
// ------------------------------------------------------------
// Atlas地图集操作
// ------------------------------------------------------------
void SaveAtlas(int type);
bool LoadAtlas(int type);
// ------------------------------------------------------------
// TODO:不清楚做啥,后续补充
// ------------------------------------------------------------
string CalculateCheckSum(string filename, int type);
// ============================================================
// 私有的成员变量
// ============================================================
// 从公有成员枚举类型中,创建枚举变量。
eSensor mSensor;
// ------------------------------------------------------------
// 创建一些指向class的类指针
// ------------------------------------------------------------
// 1. 创建ORBVocabulary类的指针mpVocabulary
// 内容:指向TemplatedVocabulary.h中TemplatedVocabulary类指针。
// 功能:该类实现创建用于位置识别和特征匹配。
ORBVocabulary* mpVocabulary;
// 2. 创建KeyFrameDatabase类的指针mpKeyFrameDatabase
// 内容:指向KeyFrameDatabase类的指针,
// 功能:创建关键帧数据库,主要保存orb描述子倒排索引(即根据描述子查找拥有该描述子的关键帧)
KeyFrameDatabase* mpKeyFrameDatabase;
// 3. 创建Atlas类的指针mpAtlas。
// 内容:指向Atlas类的指针
// 功能:该类存储指向所有关键帧和地图点的指针。
//Map* mpMap;
Atlas* mpAtlas;
// 4. 创建Tracking类的指针mpTracker。
// 内容:指向Tracking类的指针
// 功能:该类能接受一个帧,并计算相关相机位姿。
Tracking* mpTracker;
// 5. 创建LocalMapping类的指针mpLocalMapper。
// 内容:指向LocalMapping类的指针
// 功能:该类管理局部地图和执行局部BA
LocalMapping* mpLocalMapper;
// 6. 创建LoopClosing类的指针mpLoopCloser。
// 内容:指向mpLoopCloser类的指针
// 功能:该类是回环检测类。
LoopClosing* mpLoopCloser;
// 7. 创建Viewer类的指针mpViewer。
// 内容:指向Viewer类的指针
// 功能:通过绘制Pangolin地图点和当前相机姿态。
Viewer* mpViewer;
// 8. 创建Saving类的指针mpSaving。(这个是自己写,源代码没有)
// 内容:指向Saving类的指针
// 功能:保存地图点和相机姿态
Saving* mpSaving;
// 9. 创建FrameDrawer类的指针mpFrameDrawer。
// 内容:指向FrameDrawer类的指针
FrameDrawer* mpFrameDrawer;
// 10. 创建MapDrawer类的指针mpMapDrawer。
// 内容:指向MapDrawer类的指针
MapDrawer* mpMapDrawer;
// 11. 创建Settings类的指针settings_。
// 内容:指向Settings类的指针
// 功能:读取相机设置的类
Settings* settings_;
// ------------------------------------------------------------
// 线程管理
// ------------------------------------------------------------
// 创建线程LocalMapping, LoopClosing, Viewer, Saving。
// 注意track是主线程,LocalMapping, LoopClosing, Viewer, Saving是子线程。
std::thread* mptLocalMapping;
std::thread* mptLoopClosing;
std::thread* mptViewer;
std::thread* mptSaving;
// ------------------------------------------------------------
// flag管理
// ------------------------------------------------------------
// Reset flag
std::mutex mMutexReset;
bool mbReset;
bool mbResetActiveMap;
// 改变模式flags,ActivateLocalization或者DeactivateLocalization
std::mutex mMutexMode;
bool mbActivateLocalizationMode;
bool mbDeactivateLocalizationMode;
// ShutDown flag
bool mbShutDown;
// Tracking state
int mTrackingState;
std::vector<MapPoint*> mTrackedMapPoints;
std::vector<cv::KeyPoint> mTrackedKeyPointsUn;
std::mutex mMutexState;
// ------------------------------------------------------------
// 文件名字管理
// ------------------------------------------------------------
// 保存和加载地图集的文件路径
string mStrLoadAtlasFromFile;
string mStrSaveAtlasToFile;
//vocabulary文件路径
string mStrVocabularyFilePath;
};
3.2 System初始化函数:
System类的初始化函数用来初始化SLAM系统。以单目相机为例,代码中的调用方式为:
ORB_SLAM3::System SLAM(argv[1], argv[2], ORB_SLAM3::System::MONOCULAR, argv[argc-1], show);
我将System初始化函数划分为5个部分。
- 确定相机类型
- 读取参数文件内容
- 初始化system类中的成员变量(类指针实例化)
- 创建三大线程
- 创建viewer线程
System初始化函数的具体代码如下:
System::System(
const string &strVocFile, //Vocabulary文件路径
const string &strSettingsFile, //相机参数配置文件路径
const eSensor sensor, //相机类型
const string &save_path, //地图点和相机位姿的保存路径(个人添加,源码没有)
const bool bUseViewer, //是否进行窗口显示地图点和相机轨迹
const int initFr, //TODO: 和debug有关,我调用的时候没填。后续补充。
const string &strSequence //TODO: 图像序列,好像和双目,RGBD有关,单目相机用不上。后续补充吧。
):
// 通过初始化列表的方法,来给System类成员赋值。
mSensor(sensor), mpViewer(static_cast<Viewer*>(NULL)), mbReset(false), mbResetActiveMap(false),
mbActivateLocalizationMode(false), mbDeactivateLocalizationMode(false), mbShutDown(false)
{
// ============================================================
// 1.确定相机类型
// ============================================================
cout << "Input sensor was set to: ";
if(mSensor==MONOCULAR)
cout << "Monocular" << endl;
else if(mSensor==STEREO)
cout << "Stereo" << endl;
else if(mSensor==RGBD)
cout << "RGB-D" << endl;
else if(mSensor==IMU_MONOCULAR)
cout << "Monocular-Inertial" << endl;
else if(mSensor==IMU_STEREO)
cout << "Stereo-Inertial" << endl;
else if(mSensor==IMU_RGBD)
cout << "RGB-D-Inertial" << endl;
相机配置文件示例:
%YAML:1.0
#----------------------------------------------------------------------------------
# System config
#----------------------------------------------------------------------------------
# 加载和保存文件名
# 如果LoadFile不存在,系统给出一条消息并从头创建一个新的Atlas
#System.LoadAtlasFromFile: "Session_MH01_MH02_MH03_Mono"
# 存储文件是从当前会话创建的,如果存在同名的文件,则删除该文件
#System.SaveAtlasToFile: "Session_MH01_MH02_MH03_Mono"
#----------------------------------------------------------------------------------
# Camera Parameters. Adjust them!
#----------------------------------------------------------------------------------
File.version: "1.0"
Camera.type: "PinHole"
# 相机校准后的参数
# 相机x轴焦距
Camera1.fx: 1655.764141
# 相机y轴焦距
Camera1.fy: 1655.764141
# 相机x轴中心坐标
Camera1.cx: 959.5
# 相机y轴中心坐标
Camera1.cy: 543.5
# 相机径向畸变参数
Camera1.k1: -0.065
Camera1.k2: 0.03
# 相机切向畸变参数
Camera1.p1: 0.0
Camera1.p2: 0.0
# 相机拍摄图像的宽高
Camera.width: 1920
Camera.height: 1080
Camera.newWidth: 1920
Camera.newHeight: 1080
# 相机每秒获取多少帧
Camera.fps: 6
# 相机拍摄的图像类型 (0: BGR, 1: RGB. It is ignored if images are grayscale)
Camera.RGB: 1
#----------------------------------------------------------------------------------
# ORB Parameters
#----------------------------------------------------------------------------------
# ORB Extractor: 每个图像上特征点的数量
ORBextractor.nFeatures: 4000
# ORB Extractor: 在图像金字塔中每层之间的分辨率尺度
ORBextractor.scaleFactor: 1.2
# ORB Extractor: 图像金字塔的层数
ORBextractor.nLevels: 8
# ORB Extractor: Fast threshold
# 图像通过网格划分。我们需要在在每个cell提取FAST特征点。
# 首先通过高阈值initfast来进行提取特征点。如果没有检测到角,则再通过施加一个低阈值minThFAST来提取特征点
# 你可以降低这些值,如果你的图像有低对比度(这个我不清楚,这是原文注释内容)
ORBextractor.iniThFAST: 20
ORBextractor.minThFAST: 7
#----------------------------------------------------------------------------------
# Viewer Parameters
#----------------------------------------------------------------------------------
Viewer.KeyFrameSize: 0.05
Viewer.KeyFrameLineWidth: 1.0
Viewer.GraphLineWidth: 0.9
Viewer.PointSize: 2.0
Viewer.CameraSize: 0.08
Viewer.CameraLineWidth: 3.0
Viewer.ViewpointX: 0.0
Viewer.ViewpointY: -0.7
Viewer.ViewpointZ: -1.8
Viewer.ViewpointF: 500.0
Viewer.imageViewScale: 0.5
# Viewer.savePath: "/home/zhaowenjie/DATA/20230926-orb3/gongqinghceng/20230922/images-split/1/images-1s1-result"
通过上述相机配置文件参数内容,可以对照着看下面读取参数的代码。代码如下:
// ============================================================
// 2.读取参数文件内容
// ============================================================
// ------------------------------------------------------------
// 本模块内容:
// 1.根据文件中version来读取参数文件。结果保存在system类的成员变量settings_中
// 2.获取mStrLoadAtlasFromFile和mStrSaveAtlasToFile的值
// ------------------------------------------------------------
// 通过cv的方法打开文件。
cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);
// 文件没有打开的话,则报错。
if(!fsSettings.isOpened())
{
cerr << "Failed to open settings file at: " << strSettingsFile << endl;
exit(-1);
}
// 获取文件中setting相关的内容。
cv::FileNode node = fsSettings["File.version"];
if(!node.empty() && node.isString() && node.string() == "1.0"){
//如果version是1.0,则通过system类中settings_来进行读取。
settings_ = new Settings(strSettingsFile,mSensor);
// TODO:我调试的时候这俩变量显示是字符串空,具体方法,后续学到settings类再补充。
mStrLoadAtlasFromFile = settings_->atlasLoadFile();
mStrSaveAtlasToFile = settings_->atlasSaveFile();
// 将参数打印出来
cout << (*settings_) << endl;
}
else{
//如果version不是1.0或者不存在,则进行初始化。
settings_ = nullptr;
cv::FileNode node = fsSettings["System.LoadAtlasFromFile"];
if(!node.empty() && node.isString())
{
mStrLoadAtlasFromFile = (string)node;
}
node = fsSettings["System.SaveAtlasToFile"];
if(!node.empty() && node.isString())
{
mStrSaveAtlasToFile = (string)node;
}
}
// ------------------------------------------------------------
// 本模块内容:
// 1.根据文件中loopClosing的参数存在与否,确定变量activeLC的值。
// TODO:目前不知道activeLC啥作用,后续补充。
// ------------------------------------------------------------
// 读取配置文件中的loopClosing参数,我的配置文件中,这个是空的
node = fsSettings["loopClosing"];
bool activeLC = true; // TODO:这个目前还不知道是干嘛的,后续补充
if(!node.empty())
{
activeLC = static_cast<int>(fsSettings["loopClosing"]) != 0;
}
// Vocabulary文件路径传给system中的成员变量mStrVocabularyFilePath
mStrVocabularyFilePath = strVocFile;
bool loadedAtlas = false;
mStrLoadAtlasFromFile的读取结果,这个需要后续学习到settings类再分析。
此时,cout << (*settings_) << endl;的打印结果:
// ============================================================
// 3.初始化system类中的成员变量(类指针初始化):
// (包括mpVocabulary,mpKeyFrameDatabase,mAtlas,mpFrameDrawer,mpMapDrawer)
// ============================================================
// ------------------------------------------------------------
// 本模块内容:1.创建mpVocabulary
// 2.创建mpKeyFrameDatabase
// 3.初始化Atlas
// 参数解释:
// mpVocabulary: orb提取和匹配
// mpKeyFrameDatabase:创建关键帧数据库,主要保存orb描述子倒排索引(即根据描述子查找拥有该描述子的关键帧)
// ------------------------------------------------------------
// 从上述图片中看到,mStrLoadAtlasFromFile我们能没有设置,因此为空
if(mStrLoadAtlasFromFile.empty())
{
//加载 ORB Vocabulary
cout << endl << "Loading ORB Vocabulary. This could take a while..." << endl;
// 将system类中的类指针mpVocabulary实例化,创建词袋
mpVocabulary = new ORBVocabulary();
// 通过ORBVocabulary类加载本地的Vocabulary文件,最后返回bool类型的读取结果。
bool bVocLoad = mpVocabulary->loadFromTextFile(strVocFile);
if(!bVocLoad)
{
cerr << "Wrong path to vocabulary. " << endl;
cerr << "Falied to open at: " << strVocFile << endl;
exit(-1);
}
cout << "Vocabulary loaded!" << endl << endl;
// 将system类中的类指针mpKeyFrameDatabase实例化。
mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
// 创建Atlas地图集
cout << "Initialization of Atlas from scratch " << endl;
mpAtlas = new Atlas(0);
}
else
{
cout << endl << "Loading ORB Vocabulary. This could take a while..." << endl;
// 将system类中的类指针mpVocabulary实例化,创建词袋
mpVocabulary = new ORBVocabulary();
// 通过ORBVocabulary类加载本地的Vocabulary文件,最后返回bool类型的读取结果。
bool bVocLoad = mpVocabulary->loadFromTextFile(strVocFile);
if(!bVocLoad)
{
cerr << "Wrong path to vocabulary. " << endl;
cerr << "Falied to open at: " << strVocFile << endl;
exit(-1);
}
cout << "Vocabulary loaded!" << endl << endl;
// 将system类中的类指针mpKeyFrameDatabase实例化。
mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
cout << "Load File" << endl;
cout << "Initialization of Atlas from file: " << mStrLoadAtlasFromFile << endl;
// 加载地图集,并返回bool类型的读取结果
bool isRead = LoadAtlas(FileType::BINARY_FILE);
if(!isRead)
{
cout << "Error to load the file, please try with other session file or vocabulary file" << endl;
exit(-1);
}
loadedAtlas = true;
// 创建地图
mpAtlas->CreateNewMap();
}
// ------------------------------------------------------------
// 本模块内容:1.在地图集中获取相机类型
// 2.创建mpFrameDrawer
// 3.创建mpMapDrawer
// 参数解释:
// mpFrameDrawer和mpMapDrawer应该是绘制相机位姿和地图点的。
// ------------------------------------------------------------
if (mSensor==IMU_STEREO || mSensor==IMU_MONOCULAR || mSensor==IMU_RGBD)
mpAtlas->SetInertialSensor();
//Create Drawers. These are used by the Viewer
mpFrameDrawer = new FrameDrawer(mpAtlas);
mpMapDrawer = new MapDrawer(mpAtlas, strSettingsFile, settings_);
mpKeyFrameDatabase 的初始化展示。TODO:目前暂时还没学到具体函数和变量的含义,后续补充
mpAtlas的初始化展示。TODO:目前暂时还没学到具体函数和变量的含义,后续补充
// ============================================================
// 4.创建三大线程
// ============================================================
// ------------------------------------------------------------
// 本模块内容:1.创建Track线程(主线程)
// 2.创建LocalMappinig线程
// 3.创建LocalClosing线程
// 参数解释:
// mpVocabulary: orb提取和匹配
// mpKeyFrameDatabase:创建关键帧数据库,主要保存orb描述子倒排索引(即根据描述子查找拥有该描述子的关键帧)
// ------------------------------------------------------------
// step 1创建主线程mpTracker,因为Track是主线程,因此不需要创建thread
cout << "Seq. Name: " << strSequence << endl;
mpTracker = new Tracking(
this, //system类的实例结果
mpVocabulary, //ORB类的对象
mpFrameDrawer, //FrameDrawer类的对象
mpMapDrawer, //MapDrawer类的对象
mpAtlas, //Atlas类的对象
mpKeyFrameDatabase, //KeyFrameDatabase类的对象
strSettingsFile, //相机参数配置文件路径
mSensor, //传感器类型
settings_, //已经读取好的settings_
strSequence //数据序列
);
// step 2 创建子线程mpLocalMapper
// step 2.1 实例化LocalMapping类的对象mpLocalMapper。
mpLocalMapper = new LocalMapping(
this, //system类的实例结果
mpAtlas, //Atlas类的对象
mSensor==MONOCULAR || mSensor==IMU_MONOCULAR,
mSensor==IMU_MONOCULAR || mSensor==IMU_STEREO || mSensor==IMU_RGBD, //mSensor 传感器类型
strSequence //数据序列
);
// step 2.2 创建mptLocalMapping子线程。
mptLocalMapping = new thread(&ORB_SLAM3::LocalMapping::Run,mpLocalMapper);
// step 2.3 给mpLocalMapper对象赋值部分参数文件。
// TODO:initFr这个目前不知道啥作用。
mpLocalMapper->mInitFr = initFr;
if(settings_)
mpLocalMapper->mThFarPoints = settings_->thFarPoints();
else
mpLocalMapper->mThFarPoints = fsSettings["thFarPoints"];
if(mpLocalMapper->mThFarPoints!=0)
{
cout << "Discard points further than " << mpLocalMapper->mThFarPoints << " m from current camera" << endl;
mpLocalMapper->mbFarPoints = true;
}
else
mpLocalMapper->mbFarPoints = false;
// step 3 创建子线程mpLoopCloser和mptLoopClosing
// step 3.1 实例化LoopClosing类的对象mpLoopCloser。
mpLoopCloser = new LoopClosing(
mpAtlas, //Atlas类的对象
mpKeyFrameDatabase, //KeyFrameDatabase类的对象
mpVocabulary, //ORB类的对象
mSensor!=MONOCULAR, //mSensor传感器类型
activeLC //activeLC
);
// step 3.2 创建mpLoopCloser子线程。
mptLoopClosing = new thread(&ORB_SLAM3::LoopClosing::Run, mpLoopCloser);
// step 4 设置线程间的通讯
mpTracker->SetLocalMapper(mpLocalMapper);
mpTracker->SetLoopClosing(mpLoopCloser);
mpLocalMapper->SetTracker(mpTracker);
mpLocalMapper->SetLoopCloser(mpLoopCloser);
mpLoopCloser->SetTracker(mpTracker);
mpLoopCloser->SetLocalMapper(mpLocalMapper);
三大线程的部分结果。
// ============================================================
// 5.创建可视化窗口,并启动Viewer线程
// ============================================================
cout<< "bUseViewer:" << bUseViewer <<endl;
if(bUseViewer)
{
mpViewer = new Viewer(this,
mpFrameDrawer, //FrameDrawer类的对象
mpMapDrawer, //MapDrawer类的对象
mpTracker, //Tracker线程
strSettingsFile,//相机参数配置文件路径
settings_ // 读取好的settings_的结果
);
// 创建Viewer子线程。
mptViewer = new thread(&Viewer::Run, mpViewer);
mpTracker->SetViewer(mpViewer);
// 设置mpLoopCloser中的mpViewer
mpLoopCloser->mpViewer = mpViewer;
mpViewer->both = mpFrameDrawer->both;
}
// 自己写的,用来保存结果
mpSaving = new Saving(this, mpAtlas, save_path);
mptSaving = new thread(&Saving::Run, mpSaving);
// Fix verbosity(TODO: 不太清楚)
Verbose::SetTh(Verbose::VERBOSITY_QUIET);
}
小结
System.h分成以下几个部分:
- 枚举变量
- system初始化函数
- 追踪方法(单目,双目,RGBD)
- 对slam的控制操作
- 对slam的保存操作
- 对当前帧的相关操作
- debugging相关(TODO:不太懂,后续补充)
- REGISTER_TIMES相关(TODO:不太懂,后续补充)
- Atlas地图集操作
- 创建一些指向class的类指针
- 线程管理
- flag管理
- 文件名字管理
System初始化函数划分为5个部分。分别如下:
- 确定相机类型
- 读取参数文件内容
- 初始化system类中的成员变量(类指针初始化)
- 创建三大线程
- 创建可视化窗口