每次吃一点ORB_Slam3代码 — 1. System类的初始化

news2024/11/27 16:53:07

文章目录

  • 前言
    • 1. 代码调用位置
    • 2. 前置知识
      • 2.1 Sophus::SE3f
    • 3. 代码细节
      • 3.1 System.h:
      • 3.2 System初始化函数:
    • 小结

前言

ORB_SLAM3代码对于个人而言,感觉十分复杂。因为没有一些几何视图基础加上C++薄弱,所以一直没法入门。基于这种状况,我打算一点一点的学习该代码。每次学一个函数,一个类或者一个几何知识,这样积少成多总归能学会。同时,防止我学完就忘,因此我每次都总结成一篇文章督促自己尽快学完,随时复习。

本次代码的运行以单目相机为例,因此代码中有关双目、RGBD的部分我可能都会直接跳过。不过一个通了,另外两个应该也差别不大。

另外,由于是初次学,所以里面会有很多不太清楚的变量,我都会用TODO标注,后续补充。


本次System类的初始化主要介绍两个部分:

  1. system.h 库文件。
  2. 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]R4x4RSO(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 &timestamp,  //当前双目帧的时间戳 
        	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 &timestamp,   //当前帧的时间戳 
        	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 &timestamp, 	 //当前帧的时间戳
        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分成以下几个部分:

  1. 枚举变量
  2. system初始化函数
  3. 追踪方法(单目,双目,RGBD)
  4. 对slam的控制操作
  5. 对slam的保存操作
  6. 对当前帧的相关操作
  7. debugging相关(TODO:不太懂,后续补充)
  8. REGISTER_TIMES相关(TODO:不太懂,后续补充)
  9. Atlas地图集操作
  10. 创建一些指向class的类指针
  11. 线程管理
  12. flag管理
  13. 文件名字管理

System初始化函数划分为5个部分。分别如下:

  1. 确定相机类型
  2. 读取参数文件内容
  3. 初始化system类中的成员变量(类指针初始化)
  4. 创建三大线程
  5. 创建可视化窗口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1266992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

防雷器的原理、用途、参数和应用领域

防雷器是一种用于保护电子设备和电气系统免受雷电过电压和感应雷电的装置&#xff0c;主要分为外部防雷器和内部防雷器两大类。外部防雷器主要包括接闪器、引下线和接地装置&#xff0c;用于防止直击雷对建筑物和设备的损害&#xff1b;内部防雷器主要包括浪涌保护器、等电位连…

利用人工优化的数据,改善搜索相关性算法

在着手改善搜索算法时&#xff0c;有哪些可用的工具&#xff1f;我们将和来自于 Adobe 和 Etsy 的客户一起就他们每天使用的一些工具和策略&#xff0c;是如何改进他们的搜索算法展开讨论。 为什么需要人工优化的数据&#xff1f; 通过挖掘个人对搜索结果的评估&#xff0c;您…

卡码网语言基础课 | 16. 出现频率最高的字母

目录 一、 哈希表 二、 编写解题 2.1 统计出现次数 2.2 解答 通过本次练习&#xff0c;将学习到C中哈希表的基础知识 题目&#xff1a; 给定一个只包含小写字母的字符串&#xff0c;统计字符串中每个字母出现的频率&#xff0c;并找出出现频率最高的字母&#xff0c;如果…

[数据结构]-map和set

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、键值对…

上市公司-绿色专利申请、授权(2000-2022年)

一、数据介绍 数据名称&#xff1a;上市公司-绿色专利申请、授权 数据范围&#xff1a;A股上市公司 数据年份&#xff1a;2000-2022年 数据样本&#xff1a;56167条 数据来源&#xff1a;国家知识产权局、WIPO绿色专利清单 数据整理&#xff1a;自主整理 二、数据用途 数…

Tomcat 修改版本号

lib 目录下增加文件 /lib/org/apache/catalina/util/ServerInfo.properties ServerInfo.properties文件里面只需要输入server.info显示的版本号 其他可配置信息 server.infonginx server.number22.0 server.builtMay 11 2023 08:22:10 UTC 显示效果

解决掘金量化平台,赋权原因导致委托异常(委托价格低于标的[xxxx]当日的跌停价格)

文章目录 解决方法问题解析 解决方法 修改为全部使用不复权数据ADJUST_NONE进行回测&#xff0c;最新的版本支持分红配股了&#xff0c; 在交易的时候控制市值即可 问题解析 首先&#xff0c;已经设置数据参考前复权数据&#xff1a;run(backtest_adjustADJUST_PREV) 以长生…

图片去水印怎么弄?手把手教你几个去水印方法

在生活中&#xff0c;我们常常会遇到一些心仪的图片&#xff0c;然而这些图片往往带有水印或是不必要的杂物&#xff0c;如路过的行人、标志、商标等元素。这些元素通常位于图片的边角或中心&#xff0c;严重破坏了图片的整体美感&#xff0c;影响了我们的视觉体验。为了解决这…

怎样去除视频上的水印?这几个视频去水印方法简单无痕

作为全民自媒体时代&#xff0c;越来越多的人投身于自媒体行业&#xff0c;对于初学者&#xff0c;往往会遇到网上下载的视频素材会嗲有水印&#xff0c;影响二次创作以及视频观看度&#xff0c;那么怎样去除视频上的水印呢&#xff1f;别着急&#xff0c;今天分享三种视频去水…

2020年8月11日 Go生态洞察:Go 1.15版本发布深度解析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Active Directory 帐户锁定问题

Active Directory&#xff08;AD&#xff09;帐户可能由于多种原因而被锁定&#xff0c;IT 管理员需要发现帐户被锁定的原因并解锁它们&#xff0c;但是手动执行此操作是一项耗时且复杂的活动。 最重要的是&#xff0c;帐户锁定如此普遍的事实只会使解锁这些帐户更具挑战性&am…

新手必备!这款在线制作电子书神器,收藏起来慢慢学!

​随着互联网的普及&#xff0c;越来越多的人开始关注电子书市场。如果你是一名新手&#xff0c;想要尝试制作自己的电子书&#xff0c;那么可以跟着小编一起学习一下如何制作电子书&#xff01; 首先找到一款合适自己的电子书制作神器&#xff0c;小编一直用的都是FLBOOK在线制…

【飞桨星河社区五周年线下工坊-杭州站】

? 欢迎大家参加杭州极客工坊&#xff0c;深入了解大模型前沿技术和创新应用&#xff0c;一站式体验AI原生应用开发? 精彩议程敬请期待&#xff5e; ? 时间&#xff1a;2023年12月3日 14:00-17:30 ? 地点&#xff1a;杭州西湖区花蒋路3号西溪润泽园度假酒店 ? 主题&#xf…

TikTok革新挑战者:全球小众创作者的崛起

随着数字娱乐的快速发展&#xff0c;TikTok以其独特的短视频形式和开放的创作平台&#xff0c;成为全球范围内小众创作者崛起的推动者。本文将深入剖析TikTok在这一领域的革新&#xff0c;以及全球范围内小众创作者如何通过这一平台崭露头角。 TikTok&#xff1a;小众创作者的乐…

MES管理系统在智能工厂建设中的五个核心作用

随着制造业的数字化转型&#xff0c;智能工厂已经成为了现代工业生产的标志。而在智能工厂中&#xff0c;MES生产管理系统扮演着至关重要的角色。MES管理系统是一种用于管理和监控生产过程的软件系统&#xff0c;通过集成生产计划、资源调度、设备控制、质量管理等功能&#xf…

vue3-在自定义hooks使用useRouter 报错问题

文章目录 前言一、报错分析报错的Vue warn截图&#xff1a;查看文档 二、那么在hook要怎么引入路由呢&#xff1f; 前言 记录在vue3项目中&#xff0c;hook使用useRouter 报错问题 一、报错分析 报错的Vue warn截图&#xff1a; 警告 inject() can only be used inside setup…

zookeeper实操课程Acl 访问权限控制,命令行测试

本系列是zookeeper相关的实操课程&#xff0c;课程测试环环相扣&#xff0c;请按照顺序阅读测试来学习zookeeper。阅读本文之前&#xff0c;请先阅读----​​​​​​zookeeper 单机伪集群搭建简单记录&#xff08;实操课程系列&#xff09;。 阅读本文之前&#xff0c;请先阅读…

手机笔记工具怎么加密?

选择用手机笔记工具记事&#xff0c;大家可以记录很多学习笔记、读书笔记、私密日记等&#xff0c;手机作为随身携带的设备&#xff0c;记录相关的笔记比较快捷且方便&#xff0c;当手机笔记中记录的内容比较私密时&#xff0c;大家担心手机笔记会被别人误看&#xff0c;这时候…

跨境电商火爆出圈,自建商城平台如何评估商城源码的安全性?

近日&#xff0c;知名互联网评论人士阑夕的一则朋友圈刷屏。起因来自他在商家群里看到的一位跨境卖家后台晒单截图&#xff0c;说在速卖通上1天卖了快50万美元&#xff0c;比去年双11全周期还高&#xff0c;感叹“现在的跨境电商发展就如同10年前的天猫淘宝&#xff0c;潜力无限…

500元价位开放式耳机哪款好用、百元价位开放式耳机推荐

经常佩戴入耳式耳机的朋友应该都遇到过耳朵肿胀的感觉&#xff0c;这个时候&#xff0c;就是耳朵在告诉你&#xff0c;该休息一会了。如果耳朵里经常塞着耳机听歌&#xff0c;时间久了很容易引起听力衰退等问题&#xff0c;这是不可逆的伤害。各位朋友如果和我一样每天都戴着耳…