Direct Sparse Mapping DSM (一) 源代码环境配置&编译
愿天下学子都可以找到属于自己学习某项技能的动力;对于我来说,学习SLAM相关算法,最大的动力就是能亲手运行代码,看到“华丽”的效果;让效果告诉我,之后为它熬杀论文,手撕代码的努力都会是值得的(吧)。
下面就开始DSM环境配置和编译的讲解:
1. 源代码获取
论文作者的源代码开源并上传在github中,如下链接
https://github.com/jzubizarreta/dsm
但如果各位仔细查看DSM代码中附带的dsm/CMakeLists,会发现作者用了最省事的方法,直接在系统中查找所需要的Eigen以及ceres库,引入进行编译;
但ceres库对Eigen的版本依赖又非常严苛,这种省事的做法往往会在安装了库版本不匹配的电脑上产生问题;坚持使用就要修改各种链接,以及安装更多新的库,这样操作的结果往往又会让其他项目的依赖爆炸…非常的恼人;
为了让自己远离反复重装的烦恼,我改写了CMakeLists, 并将依赖库源代码直接存在thirdparty文件夹下,保证DSM项目不影响其他项目,又不会被其他项目影响,Elegant,世界和平!
https://github.com/Wen-Binghui/dsm
2 依赖软件的安装
作者依赖配置方法
如果还是选择使用作者的源代码,请按照git中的提示进行以下依赖的安装:
git clone https://github.com/jzubizarreta/dsm.git
sudo apt-get install libeigen3-dev
sudo apt-get install libopencv-dev
# glog & gflags
sudo apt-get install libgoogle-glog-dev
# BLAS & LAPACK
sudo apt-get install libatlas-base-dev
# SuiteSparse
sudo apt-get install libsuitesparse-dev
切换到另一个文件夹,准备安装ceres-solver, 例如在一个名为cpp_lib的文件中:
git clone https://ceres-solver.googlesource.com/ceres-solver
cd ceres-solver
mkdir build
cd build
cmake ..
make -j4
sudo make install
之后如果不出意外就可以编译源代码运行了!
我修改后的代码依赖配置方法
如果不想将库安装到系统中,更Elegant地配置项目,那么就建议使用我的代码~
git clone https://github.com/Wen-Binghui/dsm.git
一些软件还是需要安装;(Opencv以及glog等也完全可以添加到thirdparty之中达到Super Elegant,但考虑到他们都不存在很严重的版本问题以及大小和自己编译所花费的时间,此项目就只针对Eigen和ceres-solver喽)
sudo apt-get install libopencv-dev
# glog & gflags
sudo apt-get install libgoogle-glog-dev
# BLAS & LAPACK
sudo apt-get install libatlas-base-dev
# SuiteSparse
sudo apt-get install libsuitesparse-dev
之后, 进入DSM项目文件夹,运行我提供的build_submodules.sh脚本
cd dsm
chmod +x build_submodule.sh
./build_submodule.sh
ceres就自动地build到了项目文件夹里的thirdparty文件夹中;
根据我在dsm/dsm/CMakeLists修改的内容,此项目的编译就将使用thirdparty文件夹中的eigen以及ceres, 版本冲突问题再见!
3 项目编译
这一步骤比较基础不需要特殊的操作,使用擅长的IDE按按钮就行,或者在终端中:
cd ../dsm # cd 后处于项目根目录!(这个../ 有没有or有多少取决与你现在在哪,关注你cd后的位置就好)
mkdir build
cd build
cmake ..
make -j4
如果过程顺利,成功就在眼前了!
4 数据集准备
4.1 下载 EuRoC Example 数据集
首先打开网站
https://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets
找到下图位置
任选ASL Dataset Format中的任意一个链接(link),你可能会惊讶地发现,你点它并没有什么用,那么我们就需要换一种方法,右键任意一个link, 复制链接地址;
例如
http://robotics.ethz.ch/~asl-datasets/ijrr_euroc_mav_dataset/machine_hall/MH_01_easy/MH_01_easy.zip
在你项目文件夹的目录中创建一个叫data的新文件夹,用wget将文件下载
# @ dsm folder
mkdir data
cd data
wget http://robotics.ethz.ch/~asl-datasets/ijrr_euroc_mav_dataset/machine_hall/MH_01_easy/MH_01_easy.zip MH_01_easy.zip
数据集不小,所以需要等待一段时间将数据下载好;完成后解压数据集;
unzip MH_01_easy.zip
4.2 处理 EuRoC Example 数据集
DSM代码给的EuRoCExample并不完全适配 EuRoC Example 数据集(很气人,不知道的话需要Debug很久才能运行起来…)
4.2.1 创建标定数据
DSM 需要的标定数据必须符合以下形式
fx fy cx cy k1 k2 p1 p2
in_width in_height
out_width out_height
即三行,第一行8个参数,二三行各2个参数;我们可以根据刚下载的数据集sensor.yaml文件获取这几个参数;
例如我们希望DSM运行MH_01_easy数据中mav0中cam0的数据序列,打开文件 :
data/mav0/cam1/sensor.yaml
可以看到例如以下的数据格式
# General sensor definitions.
sensor_type: camera
comment: VI-Sensor cam0 (MT9M034)
# Sensor extrinsics wrt. the body-frame.
T_BS:
cols: 4
rows: 4
data: [0.0148655429818, -0.999880929698, 0.00414029679422, -0.0216401454975,
0.999557249008, 0.0149672133247, 0.025715529948, -0.064676986768,
-0.0257744366974, 0.00375618835797, 0.999660727178, 0.00981073058949,
0.0, 0.0, 0.0, 1.0]
# Camera specific definitions.
rate_hz: 20
resolution: [752, 480]
camera_model: pinhole
intrinsics: [458.654, 457.296, 367.215, 248.375] #fu, fv, cu, cv
distortion_model: radial-tangential
distortion_coefficients: [-0.28340811, 0.07395907, 0.00019359, 1.76187114e-05]
我们需要的只有resolution, intrisics以及distortion_coefficients中的参数!我们按照DSM所要求的格式创建的新文件就如下所示,就取名为 calib.txt 吧,并保存在
/home/wbh/code/cpp_project/dsm/data/mav0/cam0/calib.txt
458.654 457.296 367.215 248.375 -0.28340811 0.07395907 0.00019359 1.76187114e-05
752 480
752 480
4.2.2 对时间戳数据处理
时间戳数据位于(依然是举例)
data/mav0/cam0/data.csv
我们需要将第一行表头删除掉,让第一行便是数据!
完成后效果为(前四行):
1403636579763555584,1403636579763555584.png
1403636579813555456,1403636579813555456.png
1403636579863555584,1403636579863555584.png
1403636579913555456,1403636579913555456.png
4.2.3 对源代码的处理
如果你已经使用了我处理后的代码,你可以直接跳过此步;
如果使用的是作者的源代码,那就请将作者的dsm/src/Utils/EurocReader.cpp文件用我修改后的文件替代(或者只替换下面说到的函数);
因为作者希望的Euroc时间戳文件的格式是这样的:
1403636628963555584
1403636629013555456
1403636629063555584
1403636629113555456
1403636629163555584
但我们从Euroc网站上下载的数据格式其实是这样的:
1403636579763555584,1403636579763555584.png
1403636579813555456,1403636579813555456.png
1403636579863555584,1403636579863555584.png
1403636579913555456,1403636579913555456.png
1403636579963555584,1403636579963555584.png
1403636580013555456,1403636580013555456.png
1403636580063555584,1403636580063555584.png
1403636580113555456,1403636580113555456.png
1403636580163555584,1403636580163555584.png
1403636580213555456,1403636580213555456.png
1403636580263555584,1403636580263555584.png
1403636580313555456,1403636580313555456.png
1403636580363555584,1403636580363555584.png
所以需要修改 bool EurocReader::readImageNames() 函数来存储真实格式的图片文件位置;修改后的代码如下(我已在我的代码库中修改好了!不用自己改):
bool EurocReader::readImageNames()
{
//clear all data
this->timestamps.clear();
this->files.clear();
// read timestamps and images with names equal to timestamps
std::ifstream infile;
infile.open(this->timestampPath);
while (!infile.eof() && infile.good())
{
std::string line;
std::getline(infile, line);
if (!line.empty())
{
std::size_t pos = line.find(",");
line = line.substr(0, pos);
this->files.push_back(imagePath + "/" + line + ".png");
this->timestamps.push_back(std::atof(line.c_str()) / 1e9); // transform to seconds
}
}
if (this->timestamps.size() > 0 && this->timestamps.size() == this->files.size())
{
return true;
}
else
{
this->timestamps.clear();
this->files.clear();
std::cout << "NOOOOOOOT good" << std::endl;
}
return false;
}
5. 运行
至此,所有代码和数据都已经准备完全!
执行命令的参数设置如下,其中SETTINGS_FILE可以不添加
./EurocExample <IMAGE_FOLDER> <TIMESTAMPS_FILE> <CALIB_FILE> <SETTINGS_FILE>
cd到项目根目录,运行以下命令(如果数据集和我举例不一样,请略微修改):
./build/bin/EurocExample data/mav0/cam0/data data/mav0/cam0/data.csv data/mav0/cam0/calib.txt
你就可以看到如下的图床:
点击Play,左侧出现图片帧,图窗中心出现三维点云图(没看到就按住鼠标左右键任一,拖动下)
最终效果如下: