orb_slam2源码解析(1)

主体框架

输入:有三种模式选择,单目模式,双目模式和RGB-D模式。

跟踪:初始化成功后首先会选择参考关键帧跟踪,然后大部分时间是恒速模型跟踪,当跟踪丢失的时候启动重定位跟踪,,在经过以上跟踪后可以估计初步的位姿,然后经过局部地图对位姿进行进一步优化,同时会根据条件判断是否要将当前关键帧新建为关键帧。

局部建图:输入的关键帧来自跟踪重新建的关键帧,为了增加局部地图点数目,局部地图里关键帧之间会重新进行特征匹配,生成新的地图点,局部BA会同时优化共视图里关键帧位姿和地图点,优化后也不会删除不准确的地图点和冗余的关键帧。

闭环:通过词袋来查询数据集检测是否闭环,计算当前关键帧和闭环候选关键帧之间的Sim3位姿,仅在单目时考虑尺度,双目或RGB-D模式下尺度固定为1,然后执行闭环融合和本质图优化,使得所有关键帧位姿更加准确。

全局BA:优化所有的关键帧及其地图点。

位置识别:需要导入离线训练好的字典,这个字典是由视觉词袋模型构建的,新输入的图像帧需要先在线转化成词袋向量,主要应用于特征匹配,重定位,闭环。

地图:地图主要由地图点和关键帧组成,关键帧之间根据共视地图点数目组成了共视图,根据父子关系组成了生成树。

orb_slam2总共由三个线程:Tracking,Local Mapping,Loop Closing 线程,Tracking主要负责定位相机以及相机是否插入一个新的关键帧,将输入的每一个帧进行orb fearures,并且以此估计相机位姿。local mapping 线程主要负责处理新的关键帧以及执行局部BA以此来优化相机位姿,此外,负责新的map point的创建和剔除掉冗余的keyframes。loop closing线程主要负责回环检测和全局地图优化,减少位姿累计误差漂移,将误差均匀化,使得总体误差减小。

其中Tracking线程位于主线程之中,Local Mapping 线程和Loop Closing线程位于主线程中的系统初始化中。

命名规则:

了解一个工程项目的命名规则有助于学习源码。

以小写字母m(member)开头的变量表示类的成员变量,如:

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

mp(member point)开头的变量表示指针型类成员变量,如:

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

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

bool mbOnlyTracking;

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

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

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

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

ml(member list)开头的变量表示列表型成员变量,

mlp(menber list pointer)开头的变量表示列表型类成员变量,并且元素类型是指针

mlb(member list bool)开头的变量表示列表型类成员变量,并且他的元素类型是布尔型

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

接下来介绍main()函数入口

首先加载图片,将rgb.txt文档中的timestamp-filename序列存到vstrImageFilenames和vTimestamps中。

LoadImages(strFile, vstrImageFilenames, vTimestamps);

初始化,创建一个slam系统

 ORB_SLAM2::System SLAM(argv[1],argv[2],ORB_SLAM2::System::MONOCULAR,true);

调用TrackMonocular函数,进行跟踪图片,并记录每张图片的开销时间

    for(int ni=0; ni<nImages; ni++)
    {
        // Read image from file
        im = cv::imread(string(argv[3])+"/"+vstrImageFilenames[ni],CV_LOAD_IMAGE_UNCHANGED);
        double tframe = vTimestamps[ni];

        if(im.empty())
        {
            cerr << endl << "Failed to load image at: "
                 << string(argv[3]) << "/" << vstrImageFilenames[ni] << endl;
            return 1;
        }

#ifdef COMPILEDWITHC11
        std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
#else
        std::chrono::monotonic_clock::time_point t1 = std::chrono::monotonic_clock::now();
#endif

        // Pass the image to the SLAM system
        SLAM.TrackMonocular(im,tframe);

#ifdef COMPILEDWITHC11
        std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
#else
        std::chrono::monotonic_clock::time_point t2 = std::chrono::monotonic_clock::now();
#endif

        double ttrack= std::chrono::duration_cast<std::chrono::duration<double> >(t2 - t1).count();

        vTimesTrack[ni]=ttrack;

        // Wait to load the next frame
        double T=0;
        if(ni<nImages-1)
            T = vTimestamps[ni+1]-tframe;
        else if(ni>0)
            T = tframe-vTimestamps[ni-1];

        if(ttrack<T)
            usleep((T-ttrack)*1e6);
    }

关闭slam系统

SLAM.Shutdown();

计算Track图片时间的平均值和中间值

    sort(vTimesTrack.begin(),vTimesTrack.end());
    float totaltime = 0;
    for(int ni=0; ni<nImages; ni++)
    {
        totaltime+=vTimesTrack[ni];
    }

保存相机轨迹为KeyFrameTrajectory.txt

这里只保存了关键帧位姿,不包含全部帧的轨迹

SLAM.SaveKeyFrameTrajectoryTUM("KeyFrameTrajectory.txt");

ps:笔者水平有限,如有错误,联系邮箱2806762759@qq.com,欢迎批评指正

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_johan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值