视觉SLAM十四讲--第13讲 实践:设计SLAM系统(最详细的代码调试运行步骤)

2025-10-02 06:22:53

文章目录

一、 代码目录介绍及运行步骤代码目录:如何运行

二、 代码调试问题1. 准备工作2. 遇到的问题及解决办法3. 成功运行

三、 代码理解核心算法结构数据结构:算法

代码理解及修改代码理解前端后端

代码修改修改特征提取方法查看整体建图效果

运行效果图

四、总结

选题1:Kitti 的双目视觉里程计 Kitti 的 Odometry 提供了左右双目的视觉图像(以及激光,但本作业不使用激光数据),并提供了标定信息。它一共含有若干个 Sequence,其中一部分 Sequence 的真实轨迹是开放的,另一部分则是隐藏的,作为测试使用。在 Kitti 官网可以上传你对测试部分的轨迹估计,系统会计算与真实轨迹的差异,并给出评分。 现在我们已经介绍了所有关于视觉 SLAM 方面的内容,你可以基于已有算法,实现一个双目的视觉里程计了。Kitti 官网 odometry 分类下提供了双目相机的所有信息。请你根据已学知识,实现双目视觉里程计,然后运行任何一个sequence,并与标准轨迹比较。 说明: 虽然已经学完了视觉SLAM的相关知识点,但是当想要去自己编程实现,用c++来实现一整个SLAM系统的时候,我完全不知道该怎么下手了。因此本次的作业代码是基于高博课本第13讲的代码上进行改动的。虽然高博课本上的SLAM系统,已经很简单很基础的了,但是,我自己在读代码、走流程的时候依然觉得有点难啃。里边的C++模板、头文件的书写、多线程的实现、线程锁的使用以及可视化的实现都很精妙。不过这个SLAM系统没有回环检测,也没有用一些trick,特征提取什么的用的也是OpenCV自带的方法。还有很多可以调整的地方。

一、 代码目录介绍及运行步骤

代码目录:

如何运行

在ch9目录下创建一个build文件夹;编译ch9下的CMakeList.txt文件;目录切回到ch9下,执行如下命令:

./bin/run_kitti_stereo

二、 代码调试问题

1. 准备工作

首先一些包是必须安装的,如gtest、gflags、glog、eigen、g2o、CSparse、Sophus、pangolin、OpenCV等。 gtest、gflags、glog的安装,推荐源码编译安装,这里可以看我另外一篇博客,如下图所示,有介绍安装步骤:

然后是修改数据集的路径:将其改为自己的数据集路径位置。 修改文件config/default.yaml中 dataset_dir: 路径位置

修改C++的版本和OpenCV的版本指定,将opencv调成不指定版本的, 修改ch13/CMakeLists.txt中代码如下所示: 修改OpenCV部分

添加fmt库,修改ch13/CMakeLists.txt中代码如下所示:

2. 遇到的问题及解决办法

如果运行run_kitti_stereo时出现如下错误 或者出现了/usr/bin/ld:找不到-lglut…recipe for target ‘…/lib/libmyslam.so’ failed的错误 或者是编译之后不报错 ,但是lib下没有libmyslam.so文件,这是因为缺少包,执行如下命令,安装freeglut即可

sudo apt-get install freeglut3-dev

如果遇到下边的index_sequence错误,此问题易解决,之前遇到过。 解决办法,将ch13/CMakeLists.txt中的c++11标准改为c++ 14,如下所示: 如果编译是出现…/…/lib/libmyslam.so:对‘std::locale fmt::v8::detail::locale_ref::getstd::locale() const’未定义的引用的错误:这是因为编译文件中没有链入fmt库,添加方法看本文的准备工作部分。 如果遇到 relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5’ can not be used when making a shared object; recompile with -fPIC的错误,这是由于链接库中使用了libfmt.a与libmyslam.so,编译时动态库与静态库不能混用。.a是静态库,.so是动态库,具体问题具体分析,有的是因为gflags安装是安装的静态库,如下图所示,而我的问题是fmt是静态库,需要在编译时(cmake … -DGFLAGS_NAMESPACE=google -DCMAKE_CXX_FLAGS=-fPIC …)稍加注意,改成动态库就行了。 改成动态库的具体操作步骤、解决办法: 重新编译安装fmt包:

git clone https://ghproxy.com/https://github.com/fmtlib/fmt.git

cd fmt/

mkdir build

cd build

cmake .. -DGFLAGS_NAMESPACE=google -DCMAKE_CXX_FLAGS=-fPIC ..

make -j8

sudo make install

然后再重新编译就好了,大功告成。 编译运行成功后,运行时又出现了新错误,WARNING: Logging before InitGoogleLogging() is written to STDERR I20210712 22:42:13.808815 12504 visual_odometry.cpp:44] VO is running Segmentation fault (core dumped): 解决办法: 修改app/run_kitti_stereo.cpp,注释掉assert这句代码,将vo->Init()提取出来,重新编译运行: 另外,值得注意的一点是,如果是命令行运行代码,需要在/ch13目录下执行如下代码:

./bin/run_kitti_stereo

如果运行目录直接切到了bin下边,执行./run_kitti_stereo,会出现WARNING: Logging before InitGoogleLogging() is written to STDERR E20211204 11:31:53.583640 10794 config.cpp:9] parameter file ./config/default.yaml does not exist. I20211204 11:31:53.583715 10794 visual_odometry.cpp:44] VO is running 段错误 (核心已转储)的错误,如下图所示:

如果使用CLion进行编译,出现如下错误“ERROR: unknown command line flag ‘gtest_color’”,这是因为clion中少加了关于测试的参数。 两种解决办法:1. 按照slambook2书中的指示,在命令行中运行 bin/run_kitti_stereo就可以了; 2. 加这个参数不就可以了嘛,怎么加,我还在想办法。

3. 成功运行

我测试过,经过上述步骤,在CLion下,或者自己创建build文件夹,编译运行都可正常运行。

这里,我要感谢一下我参考的一些博客的作者,有时虽不能帮我解决问题,但是在他们的文章下进行评论时,能得到及时的回复,使我备受鼓舞。 参考链接:

第十三讲 实践:设计SLAM系统第13讲实践:设计slam系统遇到问题总结slam14讲第13讲问题解决make报错:relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5

三、 代码理解

核心算法结构

数据结构:

基本数据结构及关系如下图所示: 图像、特征和路标是本系统最基本的数据结构:

处理的基本数据单元就是图像对每一帧图像进行特征点的提取在图像中寻找相同的特征点,然后用三角化计算它的3D位置,及路标。

算法

分析系统有两个重要的模块:

前端:负责提取图像中的特征、光流追踪、三角化。必要时,补充新的特征点做三角化。前端处理结果作为后端的初始值,前端要对每帧进行处理,需要较高的效率。后端:后端优化不需要实时的进行,是一个较慢的过程。对前端之前的发出的数据(关键帧和路标点)进行优化,返回优化结果,最终改善建图的整体效果。后端应该控制优化问题的规模,不要让其对时间无限增长。

为了方便前端与后端之间的数据流动,加入地图类,前端负责在地图中添加路标点,后端负责将地图优化路标点,并将旧的路标点删除掉,保持一定的规模。

除了核心算法,为了后续的编码实现,我们还需要一些小的辅助模块让系统更方便:

相机类:来管理相机的参数和投影函数配置文件类:方便灵活修改配置数据类:读取相应格式的数据可视化模块类:可以观察系统的运行状态

代码理解及修改

代码理解

前端

如何选取关键帧?如果追踪到的点较少,就判定当前帧为关键帧。

前端的处理逻辑:

前端本身有初始化、正常追踪、追踪丢失三种状态在初始化状态中,根据左右目之间的光流匹配,寻找可以三角化的地图点,成功时建立初始地图。追踪阶段中,前端计算上一帧的特征点到当前帧的光流,根据光流结果计算图像位姿。该计算只使用左目图像,不用右目。关键帧的选取如果追踪丢失,重置前端系统,重新初始化。

前端处理流程大致确定了,代码如下:

bool Frontend::AddFrame(myslam::Frame::Ptr frame) {

current_frame_ = frame;

switch (status_) {

case FrontendStatus::INITING:

StereoInit();

break;

case FrontendStatus::TRACKING_GOOD:

case FrontendStatus::TRACKING_BAD:

Track();

break;

case FrontendStatus::LOST:

Reset();

break;

}

last_frame_ = current_frame_;

return true;

}

后端

后端相比前端的代码量较少,但是逻辑却更复杂。

代码修改

修改特征提取方法

原来的代码中使用的是GFTT特征点提取方法,这种方法提取的精度较高,但缺点是速度慢,修改成OpenCV自带的FastFeature提取,运行速度会快很多,但是提取的特征点质量不高。代码修改如下:

修改src/frontend.cpp

Frontend::Frontend() {

// gftt_ =

// cv::GFTTDetector::create(Config::Get("num_features"), 0.01, 20);

gftt_ =

cv::FastFeatureDetector::create(Config::Get("num_features") );

num_features_init_ = Config::Get("num_features_init");

num_features_ = Config::Get("num_features");

}

修改include/myslam/frontend.h

// utilities

// cv::Ptr gftt_; // feature detector in opencv

cv::Ptr gftt_; // feature detector in opencv

查看整体建图效果

按照如下方式修改src/viewer.cpp,可以查看整体的建图效果。

// 注意是viewer.cpp中的函数

void Viewer::UpdateMap() {

std::unique_lock lck(viewer_data_mutex_);

assert(map_ != nullptr);

active_keyframes_ = map_->GetActiveKeyFrames();

// 这样可以显示所有地图点,同时也能够看出没有回环检测,累计误差很大

// active_landmarks_ = map_->GetActiveMapPoints();

active_landmarks_ = map_->GetAllMapPoints(); // 改为all mappoints,显示整体地图

map_updated_ = true;

}

运行效果图

四、总结

在完成上述系统的代码调试之后,我又重新读课本上的代码介绍,再读源代码。现在也算了解了SLAM过程中的每个环节,学到现在才觉得自己开始入门SLAM了。对我自己而言理一理SLAM的整体过程也能收获很多, 接下来将会重点放在后端优化部分的调整,后期会尝试将回环检测模块加入本系统。继续加油~

参考资料链接整理:

重读《视觉SLAM十四讲》ch13实践设计SLAM系统一个基于深度学习回环检测模块的简单双目 SLAM 系统

资源星图