orbslam3源码阅读 2

system.cc 

这个文件是orb系统初始化文件,主要包括了读取预先存储的地图、初始化词袋、关键帧数据库和地图集、初始化可视化窗口、初始化tracking追踪线程和loopclose闭环线程、轨迹保存等工作。下面是具体介绍。

地图集相关工作,包括词袋、关键帧数据库和地图集的初始化工作。

首先读取配置文件,之后从文件加载地图集,判断是否回环检测

如果没有加载成功地图集,就加载词袋,创建关键帧数据集,并创建地图集,mpAtlas = new Atlas(0)。

加载成功地图集,加载词袋,创建关键帧数据集,mpAtlas->CreateNewMap()。

namespace ORB_SLAM3
{
//输出调试信息等级
Verbose::eLevel Verbose::th = Verbose::VERBOSITY_NORMAL;

System::System(const string &strVocFile, //词典文件
               const string &strSettingsFile, //配置文件
               const eSensor sensor,//传感器类型
               const bool bUseViewer, //可视化窗口
               const int initFr, const string &strSequence):
    mSensor(sensor), mpViewer(static_cast<Viewer*>(NULL)), mbReset(false), mbResetActiveMap(false),
    mbActivateLocalizationMode(false), mbDeactivateLocalizationMode(false), mbShutDown(false)
{
    // Output welcome message
    cout << endl <<
    "ORB-SLAM3 Copyright (C) 2017-2020 Carlos Campos, Richard Elvira, Juan J. Gómez, José M.M. Montiel and Juan D. Tardós, University of Zaragoza." << endl <<
    "ORB-SLAM2 Copyright (C) 2014-2016 Raúl Mur-Artal, José M.M. Montiel and Juan D. Tardós, University of Zaragoza." << endl <<
    "This program comes with ABSOLUTELY NO WARRANTY;" << endl  <<
    "This is free software, and you are welcome to redistribute it" << endl <<
    "under certain conditions. See LICENSE.txt." << endl << endl;

    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;

    //读取配置文件
    cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);//配置文件名转为字符串
    if(!fsSettings.isOpened())
    {
       cerr << "Failed to open settings file at: " << strSettingsFile << endl;
       exit(-1);
    }

    cv::FileNode node = fsSettings["File.version"];
    if(!node.empty() && node.isString() && node.string() == "1.0"){//加载地图集,相应的函数在atlas里面
        settings_ = new Settings(strSettingsFile,mSensor);

        mStrLoadAtlasFromFile = settings_->atlasLoadFile();
        mStrSaveAtlasToFile = settings_->atlasSaveFile();

        cout << (*settings_) << endl;
    }
    else{
        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;
        }
    }

    node = fsSettings["loopClosing"];
    bool activeLC = true;
    if(!node.empty())
    {
        activeLC = static_cast<int>(fsSettings["loopClosing"]) != 0;//强制类型转换判断是否有回环检测
    }

    mStrVocabularyFilePath = strVocFile;//词袋文件路径

    bool loadedAtlas = false;

    if(mStrLoadAtlasFromFile.empty())
    {
        //Load ORB Vocabulary加载词袋
        cout << endl << "Loading ORB Vocabulary. This could take a while..." << endl;

        mpVocabulary = new ORBVocabulary();//词袋创建函数ORBVocabulary()
        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;

        //Create KeyFrame Database//使用词袋创建关键帧数据库KeyFrameDatabase(*mpVocabulary)
        mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);

        //Create the Atlas//创建地图集
        cout << "Initialization of Atlas from scratch " << endl;
        mpAtlas = new Atlas(0);
    }
    else
    {
        //Load ORB Vocabulary
        cout << endl << "Loading ORB Vocabulary. This could take a while..." << endl;

        mpVocabulary = new ORBVocabulary();
        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;

        //Create KeyFrame Database
        mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);

        cout << "Load File" << endl;

        // Load the file with an earlier session
        //clock_t start = clock();
        cout << "Initialization of Atlas from file: " << mStrLoadAtlasFromFile << endl;
        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);
        }
        //mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);


        //cout << "KF in DB: " << mpKeyFrameDatabase->mnNumKFs << "; words: " << mpKeyFrameDatabase->mnNumWords << endl;

        loadedAtlas = true;

        mpAtlas->CreateNewMap();

        //clock_t timeElapsed = clock() - start;
        //unsigned msElapsed = timeElapsed / (CLOCKS_PER_SEC / 1000);
        //cout << "Binary file read in " << msElapsed << " ms" << endl;

        //usleep(10*1000*1000);
    }

IMU标志位、跟踪和闭环线程

    if (mSensor==IMU_STEREO || mSensor==IMU_MONOCULAR || mSensor==IMU_RGBD)
        mpAtlas->SetInertialSensor();//IMU标志位

    //Create Drawers. These are used by the Viewer
    mpFrameDrawer = new FrameDrawer(mpAtlas);
    mpMapDrawer = new MapDrawer(mpAtlas, strSettingsFile, settings_);

    //Initialize the Tracking thread//初始化tracking线程
    //(it will live in the main thread of execution, the one that called this constructor)
    cout << "Seq. Name: " << strSequence << endl;
    mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer,
                             mpAtlas, mpKeyFrameDatabase, strSettingsFile, mSensor, settings_, strSequence);

    //Initialize the Local Mapping thread and launch、、初始化本地建图线程,线程函数为LocalMapping::Run()
    mpLocalMapper = new LocalMapping(this, mpAtlas, mSensor==MONOCULAR || mSensor==IMU_MONOCULAR,
                                     mSensor==IMU_MONOCULAR || mSensor==IMU_STEREO || mSensor==IMU_RGBD, strSequence);
    mptLocalMapping = new thread(&ORB_SLAM3::LocalMapping::Run,mpLocalMapper);
    mpLocalMapper->mInitFr = initFr;    //initFr表示初始化帧的id,代码里设置为0

    if(settings_)    //设置区分远点和近点的阈值,不过配置文件中并没有这个参数,而是有ThDepth,在tracking线程构造函数中读取

        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;

    //Initialize the Loop Closing thread and launch
    // mSensor!=MONOCULAR && mSensor!=IMU_MONOCULAR//初始化闭环线程,线程主函数为LoopClosing::Run()

    mpLoopCloser = new LoopClosing(mpAtlas, mpKeyFrameDatabase, mpVocabulary, mSensor!=MONOCULAR, activeLC); // mSensor!=MONOCULAR);
    mptLoopClosing = new thread(&ORB_SLAM3::LoopClosing::Run, mpLoopCloser);

    //Set pointers between threads
    // 设置线程句柄
    mpTracker->SetLocalMapper(mpLocalMapper);
    mpTracker->SetLoopClosing(mpLoopCloser);

    mpLocalMapper->SetTracker(mpTracker);
    mpLocalMapper->SetLoopCloser(mpLoopCloser);

    mpLoopCloser->SetTracker(mpTracker);
    mpLoopCloser->SetLocalMapper(mpLocalMapper);

    //usleep(10*1000*1000);

可视化初始化工作


    //Initialize the Viewer thread and launch
    if(bUseViewer)//可视化
    //if(false) // TODO
    {
        mpViewer = new Viewer(this, mpFrameDrawer,mpMapDrawer,mpTracker,strSettingsFile,settings_);
        mptViewer = new thread(&Viewer::Run, mpViewer);
        mpTracker->SetViewer(mpViewer);
        mpLoopCloser->mpViewer = mpViewer;
        mpViewer->both = mpFrameDrawer->both;
    }

    // Fix verbosity    //设置打印信息的等级,只有小于这个等级的信息才会被打印

    Verbose::SetTh(Verbose::VERBOSITY_QUIET);

之后是跟踪线程的具体初始化过程,以双目为例,包括了图像校正、裁剪、纯定位模式选择、是否重置地图以及一些数据(如当前地图关键点)的保存。最终会返回一个位姿矩阵tcw。主要计算函数为mpTracker->GrabImageStereo(imLeftToFeed,imRightToFeed,timestamp,filename);

类似的还有用于处理RGBD的和单目monocular

//双目track
Sophus::SE3f System::TrackStereo(const cv::Mat &imLeft, const cv::Mat &imRight, const double &timestamp, const vector<IMU::Point>& vImuMeas, string filename)
{
    if(mSensor!=STEREO && mSensor!=IMU_STEREO)
    {
        cerr << "ERROR: you called TrackStereo but input sensor was not set to Stereo nor Stereo-Inertial." << endl;
        exit(-1);
    }

    cv::Mat imLeftToFeed, imRightToFeed;
    //如果需要图像校正
    if(settings_ && settings_->needToRectify()){
        cv::Mat M1l = settings_->M1l();
        cv::Mat M2l = settings_->M2l();
        cv::Mat M1r = settings_->M1r();
        cv::Mat M2r = settings_->M2r();

        cv::remap(imLeft, imLeftToFeed, M1l, M2l, cv::INTER_LINEAR);
        cv::remap(imRight, imRightToFeed, M1r, M2r, cv::INTER_LINEAR);
    }
    //如果需要更改尺寸
    else if(settings_ && settings_->needToResize()){
        cv::resize(imLeft,imLeftToFeed,settings_->newImSize());
        cv::resize(imRight,imRightToFeed,settings_->newImSize());
    }
    else{
        imLeftToFeed = imLeft.clone();
        imRightToFeed = imRight.clone();
    }

    // Check mode change
    {
        unique_lock<mutex> lock(mMutexMode);
        if(mbActivateLocalizationMode)//如果为纯定位模式
        {
            mpLocalMapper->RequestStop();//请求关闭建图

            // Wait until Local Mapping has effectively stopped
            while(!mpLocalMapper->isStopped())
            {
                usleep(1000);
            }

            mpTracker->InformOnlyTracking(true);//开启纯定位模式
            mbActivateLocalizationMode = false; // 设置为false,避免重复进行以上操作
        }
        
        //关闭纯定位模式,重新打开局部建图线程
        if(mbDeactivateLocalizationMode)
        {
            mpTracker->InformOnlyTracking(false);
            mpLocalMapper->Release();
            mbDeactivateLocalizationMode = false;
        }
    }

    // Check reset是否重置跟踪/地图
    {
        unique_lock<mutex> lock(mMutexReset);
        if(mbReset)
        {
            mpTracker->Reset();
            mbReset = false;
            mbResetActiveMap = false;
        }
        else if(mbResetActiveMap)
        {
            mpTracker->ResetActiveMap();
            mbResetActiveMap = false;
        }
    }

    //保存IMU数据
    if (mSensor == System::IMU_STEREO)
        for(size_t i_imu = 0; i_imu < vImuMeas.size(); i_imu++)
            mpTracker->GrabImuData(vImuMeas[i_imu]);

    // std::cout << "start GrabImageStereo" << std::endl;处理双目和IMU数据
    Sophus::SE3f Tcw = mpTracker->GrabImageStereo(imLeftToFeed,imRightToFeed,timestamp,filename);

    // std::cout << "out grabber" << std::endl;

    unique_lock<mutex> lock2(mMutexState);
    mTrackingState = mpTracker->mState;//状态标志
    mTrackedMapPoints = mpTracker->mCurrentFrame.mvpMapPoints;//当前帧的地图点
    mTrackedKeyPointsUn = mpTracker->mCurrentFrame.mvKeysUn;//当前帧的去畸变后关键点

    return Tcw;
}

此外有一些标志位函数以及轨迹保存函数

标志位:

void System::ActivateLocalizationMode()//mbActivateLocalizationMode=true,进入纯定位模式
void System::DeactivateLocalizationMode()//mbDeactivateLocalizationMode=true,关闭纯定位模式
bool System::MapChanged()//查询从上次查询后地图是否有大变动(回环,全局BA)
void System::Reset()//重置跟踪和地图
void System::ResetActiveMap()//仅重置地图
void System::Shutdown()//请求结束,请求局部建图和回环结束,保存Atlas
bool System::isShutDown() //查询系统是否已经请求结束
int System::GetTrackingState()//查询跟踪状态
vector<MapPoint*> System::GetTrackedMapPoints()//查询跟踪的地图点
vector<cv::KeyPoint> System::GetTrackedKeyPointsUn()//查询跟踪的关键点

轨迹和地图保存,主要有tum,euroc,kitti三种格式。以tum为例

void System::SaveTrajectoryTUM(const string &filename)//保存TUM格式的轨迹,Monocular不可用

{
    cout << endl << "Saving camera trajectory to " << filename << " ..." << endl;
    if(mSensor==MONOCULAR)
    {
        cerr << "ERROR: SaveTrajectoryTUM cannot be used for monocular." << endl;
        return;
    }

    vector<KeyFrame*> vpKFs = mpAtlas->GetAllKeyFrames();//获取地图集中所有关键帧
    sort(vpKFs.begin(),vpKFs.end(),KeyFrame::lId);//使用ID排序

    // Transform all keyframes so that the first keyframe is at the origin.
    // After a loop closure the first keyframe might not be at the origin.
    Sophus::SE3f Two = vpKFs[0]->GetPoseInverse();//第一针关键帧作为世界坐标系

    ofstream f;//打开存储位姿的文件
    f.open(filename.c_str());
    f << fixed;

    // Frame pose is stored relative to its reference keyframe (which is optimized by BA and pose graph).
    // We need to get first the keyframe pose and then concatenate the relative transformation.
    // Frames not localized (tracking failure) are not saved.

    // For each frame we have a reference keyframe (lRit), the timestamp (lT) and a flag
    // which is true when tracking failed (lbL).
    //每一帧都有个参考关键帧,在闭环中不断变化,位姿等于该帧相对于参考关键帧的位姿乘以参考关键帧的世界位姿。
    list<ORB_SLAM3::KeyFrame*>::iterator lRit = mpTracker->mlpReferences.begin();//参考关键帧
    list<double>::iterator lT = mpTracker->mlFrameTimes.begin();//时间戳
    list<bool>::iterator lbL = mpTracker->mlbLost.begin();//是否跟踪失败
    for(list<Sophus::SE3f>::iterator lit=mpTracker->mlRelativeFramePoses.begin(),//相对参考关键帧的位姿
        lend=mpTracker->mlRelativeFramePoses.end();lit!=lend;lit++, lRit++, lT++, lbL++)
    {
        if(*lbL)//跟踪失败
            continue;

        KeyFrame* pKF = *lRit;//成功,取出参考关键帧

        Sophus::SE3f Trw;

        // If the reference keyframe was culled, traverse the spanning tree to get a suitable keyframe.
        while(pKF->isBad())//如果参考关键帧坏了,位姿选取其父位姿
        {
            Trw = Trw * pKF->mTcp;//父帧到原参考关键帧的位姿变换
            pKF = pKF->GetParent();//父帧
        }

        Trw = Trw * pKF->GetPose() * Two;//参考关键帧的位姿

        Sophus::SE3f Tcw = (*lit) * Trw;//参考关键帧到当前帧的相对位姿*参考关键帧位姿=当前帧位姿
        Sophus::SE3f Twc = Tcw.inverse();

        Eigen::Vector3f twc = Twc.translation();//平移
        Eigen::Quaternionf q = Twc.unit_quaternion();//四元数输出旋转

        f << setprecision(6) << *lT << " " <<  setprecision(9) << twc(0) << " " << twc(1) << " " << twc(2) << " " << q.x() << " " << q.y() << " " << q.z() << " " << q.w() << endl;
    }
    f.close();
    // cout << endl << "trajectory saved!" << endl;
}

保存初始化信息的函数void System::SaveDebugData(const int &initIdx),主要将一些调试信息保存到txt文件里。

atlas地图集的保存和加载判断函数void System::SaveAtlas(int type)、bool System::LoadAtlas(int type)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ORBSLAM3是一个开的视觉SLAM系统,可以用于在无GPS信息的情况下实现室内导航和定位。以下是关于ORBSLAM3码下载的相关信息: 要下载ORBSLAM3码,你可以访问ORBSLAM3项目的GitHub页面。在GitHub上,你可以浏览到ORBSLAM3的最新代码,并且可以选择将其克隆到你的本地计算机。 要从GitHub上下载ORBSLAM3码,你可以按照以下步骤进行: 1. 打开你的web浏览器,访问GitHub的主页。 2. 在GitHub的搜索栏中输入“ORBSLAM3”。 3. 在搜索结果中找到ORBSLAM3项目的主页,点击进入。 4. 进入ORBSLAM3项目主页后,你会看到项目的描述、文档和码。 5. 在主页的右上方,有个绿色的按钮,上面写着“Code”,点击它。 6. 在弹出的下拉菜单中,你可以选择不同的下载方式。如果你熟悉git,你可以选择使用git命令将码克隆到你的本地计算机。如果不熟悉git,你可以选择直接下载码的zip压缩包。 7. 选择适合你的方式进行下载,并将码保存到你的本地计算机。 一旦你完成了下载,你就可以开始使用ORBSLAM3的码了。你可以解压zip压缩包(如果你选择了zip方式下载)并浏览码的内容。在码的根目录中,你可以找到主要的代码文件和其他相关文件。 请注意,码的下载可能需要一些时间,具体取决于你的网络连接速度。此外,使用ORBSLAM3前,建议你详细阅读相关的文档和使用说明,以了解如何正确配置、编译和运行该系统。 ### 回答2: ORB-SLAM3是一种开的用于实时单目视觉SLAM的算法框架。为了获取ORB-SLAM3的代码,你可以按照以下步骤进行下载。 1. 首先,打开ORB-SLAM3的官方GitHub页面(https://github.com/UZ-SLAMLab/ORB_SLAM3)。 2. 在该页面上,你可以看到绿色的按钮“Code”,点击它会弹出下拉菜单。 3. 在下拉菜单中,你可以选择“Download ZIP”选项。点击此选项后,代码将以ZIP文件的形式下载到你的计算机中。 4. 下载完成后,你可以将ZIP文件解压缩到你选择的目录中。解压后你会看到代码的文件夹。 现在你已经成功地下载了ORB-SLAM3的代码。你可以通过查看代码、阅读文档、学习示例等方式来了解和使用ORB-SLAM3算法框架。在研究SLAM算法或者开发相关应用时,这个码将为你提供很好的参考和基础。 记得遵守代码的许可证,并尊重作者的工作。你可以在码中查找相关许可证和使用条款,以确保你遵循了正确的使用规定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值