ORB_SLAM2代码的简介安装运行

本博客结合哔哩大学视频ORBSLAM2原理代码详解-1简介安装运行总结。
代码参照github的ORB_SLAM2_detailed_comments
我对代码要求环境的配置做了一个总结,解决了配置中的一些常见问题,详见slam的环境配置大全–保姆教学
ORBSLAM2代码很经典,而且代码量大,会分成多个博客研究。

在这里插入图片描述

以下正文:

ORBSLAM2简介

ORBSLAM2代码很经典,支持单目、双目相机,在cpu上就可以运行,是特征点slam的巅峰之作,定位精度很高。
在这里插入图片描述
如上图,先是单目或者双目输入进来,做一个预处理即提取特征点,后边的方框都是跟踪过程,包括重定位、跟踪局部地图、关键帧的选择。这些完成以后就是右侧竖着方框里的工作,关键帧一直进行插入并作地图点的筛查工作,去除无效的地图点,增加新的点和局部BA的工作,关键帧也不会一直不变。再左侧的方框就是回环检测,做回环融合、回环校正、整体BA。其中还包括例如重定位的视觉磁带,整个代码很块化,比较好理解。

ORBSLAM2安装

博客开头有github的链接,如图为其要求的配置环境。
在这里插入图片描述
其中c++一般都支持了,Pangolin是用作显示的,Opencv一般安装Opencv3,ROS为可选项。
我对其要求环境的配置做了一个总结,解决了配置中的一些常见问题,详见slam的环境配置大全–保姆教学

ORBSLAM2运行

1、数据集的下载:
安装完成后跑个demo,在如图路径下有三个对应数据集的可执行文件。

在这里插入图片描述先下载数据集,mono_tum对应的tum数据集,github中有下载链接
在这里插入图片描述
随便找一个下载后,除associate外其他和图片一致。包括depth图、rgb图、加速度、depth里包括depth的时间戳和depth名称,rgb类似,groundtruth里有如图的时间戳中和四元数表示的各位姿。在这里插入图片描述

最后associate.py的python文件是从官网下载的,需要在python2下运行。如下为官网截图:
在这里插入图片描述
图中上半段交代了彩色图是640480的8位PNG格式,深度图是640480的16位的png图,注意上半段最后一句说:深度的规模是5000,里面是16位,假设记录的值是5000的话,除以scale,即5000/5000=1,这个点距离相机1米。下面Ground-truth交代了,相机在一个固定的坐标系下的坐标。
而associate.py的作用是在rgbd模式下(单目直接跑就行)因为时间戳不一致,rgbd模式下需要把彩色图和深度图做一个关联,哪一帧的彩色图对应哪一帧的深度图,不是严格关联有时间差。打开associate.py如图,associate.py的内容为此处,可以复制下载自己做一个python
文件放到数据集里。
在这里插入图片描述
运行的指令为:(> 之后的是自己命名的文件),第二句指令和注意我没看懂

python associate.py rgb.txt depth.txt > associate.txt
python associate.py associate.txt groundtruth.txt > associate_with_groundtrurh.txt

注意:
直接associate后出问题,生成的结果
associate.txt 1641行
associate_with_groundtrurh.txt 1637行
也就是说,associate的不一定有groundtruth,所以要以associate_with_groundtrurh.txt的关联结果为准。

2、介绍完数据集就可以跑程序了
指令为

./Examples/Monocular/mono_tum Vocabulary/ORBvoc.txt Examples/Monocular/TUMX.yaml PATH_TO_SEQUENCE_FOLDER

首先是mono_tum文件,ORBvoc.txt是orb的一个训练好的磁带,TUMX.yaml在文件夹中有三个,我们需要把X改成1、2、3,最后一个是指定一个地方放数据集。

我们详细看一下TUM1.yaml里有什么。这是一个配置文件,为什么要有这个配置文件呢,比如我们要跑一个代码,测试一下某个参数对某个性能的影响。若每次都把参数写死在代码里,则每次都要重新编译,所以我们就把经常修改的参数或者路劲放到配置文件里,让他读进去直接改就行了不需要重现编译。内容注释如图:
在这里插入图片描述
有以上这些东西就可以跑了
为什么有以上这些东西就可以跑了呢?
比如单目的tum版本,如图示例划线的地方所对应的文件在这里插入图片描述
参照下面代码中的注释理解

using namespace std;


void LoadImages(const string &strFile, vector<string> &vstrImageFilenames,
                vector<double> &vTimestamps);

int main(int argc, char **argv)#argv是输入的一些参数
{
    if(argc != 4)
    {
        cerr << endl << "Usage: ./mono_tum path_to_vocabulary path_to_settings path_to_sequence" << endl;
        return 1;
    }

    // Retrieve paths to images
    vector<string> vstrImageFilenames;
    vector<double> vTimestamps;
    string strFile = string(argv[3])+"/rgb.txt";#argv[3]就是划线部分第三个path_to_sequence,再加一个+"/rgb.txt"代表读取这个目录下的rgb包。同理argv[1]代表path_to_vocabulary
    LoadImages(strFile, vstrImageFilenames, vTimestamps);

    int nImages = vstrImageFilenames.size();

3、最后跑示例代码
在ORB_SLAM2包下代开终端,输入上边更改后的命令,例如:

./Examples/Monocular/mono_tum Vocabulary/ORBvoc.txt Examples/Monocular/TUM3.yaml /home/cxl/Download/DataSet/TUM/rgbd_dataset_freiburg1_long_office_househlod

跑出来的最后效果和对应怎么操作也很重要,但是不能上传视频,可以参照博客开头的哔哩大学视频24分钟。
运行过程和代码结果如下两图:
在这里插入图片描述
在这里插入图片描述
安装编译若有下图错误,可以按下边第一个评论解决。
在这里插入图片描述

最后把代码大概注释一遍:

/**
* This file is part of ORB-SLAM2.
*
* Copyright (C) 2014-2016 Raúl Mur-Artal <raulmur at unizar dot es> (University of Zaragoza)
* For more information see <https://github.com/raulmur/ORB_SLAM2>
*
* ORB-SLAM2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ORB-SLAM2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ORB-SLAM2. If not, see <http://www.gnu.org/licenses/>.
*/

// 外层结构很简单,就是45行左右的读入图片,68行读图,86行track,110行shutdown,116行打印出运行时间,124行保存轨迹
#include<iostream>
#include<algorithm>
#include<fstream>
#include<chrono>

#include<opencv2/core/core.hpp>

#include<System.h>
#include<unistd.h>
using namespace std;


void LoadImages(const string &strFile, vector<string> &vstrImageFilenames,
                vector<double> &vTimestamps);
// 主函数
int main(int argc, char **argv)
{
    if(argc != 4)
    {
        cerr << endl << "Usage: ./mono_tum path_to_vocabulary path_to_settings path_to_sequence" << endl;
        return 1;
    }

    // Retrieve paths to images
    vector<string> vstrImageFilenames;
    vector<double> vTimestamps;
    string strFile = string(argv[3])+"/rgb.txt"; // 单目只需要rgb
    LoadImages(strFile, vstrImageFilenames, vTimestamps); // 把rgb的strfile给load进来,函数loadimage解释在136行

    int nImages = vstrImageFilenames.size();// 所有帧的总数

    // Create SLAM system. It initializes all system threads and gets ready to process frames.
    ORB_SLAM2::System SLAM(argv[1],argv[2],ORB_SLAM2::System::MONOCULAR,true);// 把orb_slam2的系统初始化

    // Vector for tracking time statistics
    vector<float> vTimesTrack;
    vTimesTrack.resize(nImages);

    cout << endl << "-------" << endl;
    cout << "Start processing sequence ..." << endl;
    cout << "Images in the sequence: " << nImages << endl << endl;

    // Main loop
    cv::Mat im;
    for(int ni=0; ni<nImages; ni++)// 初始化完成后开始每一帧的读
    {
        // Read image from file
        im = cv::imread(string(argv[3])+"/"+vstrImageFilenames[ni],CV_LOAD_IMAGE_UNCHANGED);// read刚才路径下图片的名字
        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);// 输入的图片和时间戳,开始track(轨道)

#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);
    }

    // Stop all threads
    SLAM.Shutdown();// 关闭

    // Tracking time statistics
    sort(vTimesTrack.begin(),vTimesTrack.end());
    float totaltime = 0;
    for(int ni=0; ni<nImages; ni++)
    {
        totaltime+=vTimesTrack[ni];
    }
    cout << "-------" << endl << endl;
    cout << "median tracking time: " << vTimesTrack[nImages/2] << endl;
    cout << "mean tracking time: " << totaltime/nImages << endl;

    // Save camera trajectory
    SLAM.SaveKeyFrameTrajectoryTUM("KeyFrameTrajectory.txt");// 最后保存一下轨迹

    return 0;
}

/**
 * @brief 导入图片
 * 
 * @param[in] strFile                   读入的文件名称
 * @param[in&out] vstrImageFilenames    彩色图片名称
 * @param[in&out] vTimestamps           记录时间戳
 */
void LoadImages(const string &strFile, vector<string> &vstrImageFilenames, vector<double> &vTimestamps)
{
    ifstream f;
    f.open(strFile.c_str());

    // skip first three lines
    // 前三行是注释,跳过
    string s0;
    getline(f,s0);
    getline(f,s0);
    getline(f,s0);

    while(!f.eof())
    {
        string s;
        getline(f,s);
        if(!s.empty())// load进来后判断不为空
        {// 把这个rgb名字给他,记录名字,记录完后开始迭代
            stringstream ss;
            ss << s;
            double t;
            string sRGB;
            ss >> t;
            vTimestamps.push_back(t);
            ss >> sRGB;
            vstrImageFilenames.push_back(sRGB);
        }
    }
}

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值