目录
前言
我们对于LearnVIORB
的配置,并非从头开始,一个库一个库地配置,如此则区区一篇博文是不够的。因此,我们选择在ORBSLAM2
的基础上,配置LearnVIORB
。
我们在Releasex64/MD
配置下,沿用ORBSLAM2
的Eigen3
、OpenCV3.1
、Pangolin
、boost
四个库,而重新配置DBoW2
、g2o
两个库。这是因为LearnVIORB
的作者似乎对上述两个库做了二次的修改,此可以从其github
获悉。
这里需要注意的是,由于我全程采用/MD
进行配置,而原先的Pangolin
的运行库则默认是/MT
模式的,故而需要另外配置/MD
模式下的Pangolin
,此可以参考我的另一篇博文。
LearnVIORB
的源码则采用LearnViORB_NOROS
,其下载地址如下:地址
相关配置环境再次总结如下:
- Win10
- VS2017
- CMake3.18.4
- Release x64 /MD
- LearnViORB_NOROS
DBoW2 配置
构建生成解决方案
在 Configure 的时候选择x64
模式
接下来提示没有找到OpenCV
,需要在OpenCV_DIR
的属性项目中设置含有OpenCVConfig.cmake
或opencv-config.cmake
文件的目录。由于我的电脑上的OpenCV都是阉割版本,所以就先暂时忽略掉这个错误。
清空build
文件夹,打开库的根目录下的CMakeLists.txt
文件,删除其中的find_package(OpenCV REQUIRED)
,然后保存,重新 Configure 一下。
Configure 没有任何问题,直接 Generate 生成解决方案。
编译基于VS2017
在VS2017中采用Releasex64
模式,同时修改DBoW2
项目的属性如下:
项目属性/配置属性/常规/目标文件扩展名
=.lib
项目属性/配置属性/常规/配置类型
=静态库(.lib)
C/C++/代码生成/运行库
=多线程DLL(/MD)
同时在配置属性/VC++目录
的包含目录和库目录中将之前忽略掉的 OpenCV 的源文件、库文件所在目录写上去。然后直接右键项目生成即可。
编译时发现FORB.cpp
文件中有一行报错,如下修改即可:
// #include <stdint-gcc.h> before
#include <stdint.h> // after
最后编译完成,库文件路径如下:
最后新建文件夹DBoW2
,然后将源文件和生成的库文件分别整理在其下新建的的include
和lib
文件夹即可。
g2o 配置
依赖库 BLAS(LAPACK) 库的配置
Configure 的时候还是x64
的配置,然后就报错找不到BLAS
库。
BLAS
库和LAPACK
库是两个线性代数运算库,后者是基于前者实现的。有赖于此,我们只需要配置好LAPACK
这个库理应也就OKay。LearnVIORB
的作者在github
上给出了上述两个库的官方地址:BLAS、LAPACK
我们打开官方地址按图索骥,发现LAPACK
的官方早已提供 Win10 下的编译好的版本,其相关内容在该网址中如下所示:
Download the Visual Studio Solution LAPACKE examples and unzip.The Solution contains all the includes, libraries and dlls you need.
直接点击引用中的超链接下载即可,其中就有我们需要的库文件和源文件。将上述两个文件所在的include
和lib
文件夹解压备用。
Okay,有基于上,我们依旧清空build
文件夹,将CMakeLists.txt
文件中的如下部分删掉,暂时忽略掉上述报错。
FIND_PACKAGE(BLAS REQUIRED)
FIND_PACKAGE(LAPACK REQUIRED)
构建生成解决方案
再次基于x64
构建,这次是因为缺少Eigen
的路径而报错,直接写上即可,最终Eigen
的路径如下所示:
至此构建完成,直接 Generate 即可。
编译基于VS2017
打开构建的解决方案,各种属性的配置参照上述DBoW2
库的配置,唯一不同的是,在配置前者时,额外添加的是OpenCV
库的包含目录和库目录;这次我们就直接添加之前忽略的LAPACK
库的包含目录和库目录即可。
编译时报错如下:
1>e:\gitrepository\learnviorb_noros\thirdparty\g2o\g2o\core\matrix_operations.h(49): fatal error C1001: 编译器中发生内部错误。
1>(编译器文件“msc1.cpp”,第 1518 行)
1> 要解决此问题,请尝试简化或更改上面所列位置附近的程序。
我们切换到matrix_operations.h
文件发生错误的位置,删除出错部分附近的,第47行以及第65行的template<>
,相关代码如下:
...
template<> // 删除该行
inline void axpy(const Eigen::MatrixXd& A, const Eigen::Map<const Eigen::VectorXd>& x, int xoff, Eigen::Map<Eigen::VectorXd>& y, int yoff)
{
y.segment(yoff, A.rows()) += A * x.segment(xoff, A.cols());
}
...
template<> // 删除该行
inline void atxpy(const Eigen::MatrixXd& A, const Eigen::Map<const Eigen::VectorXd>& x, int xoff, Eigen::Map<Eigen::VectorXd>& y, int yoff)
{
y.segment(yoff, A.cols()) += A.transpose() * x.segment(xoff, A.rows());
}
...
再次编译,报错如下:
max
函数的问题可以通过添加#include <algorithm>
解决,而vasprintf
函数的问题则通过添加WINDOWS
宏即可解决,这一点可以通过查看vasprintf
函数的上下文获悉。
此后则一路绿灯,编译完成,生成的库文件如下所示:
依赖库 cholmod 的配置
在将配置完成的g2o
库整合到LearnVIORB
的过程中,我们发现在linear_solver_cholmod.h
文件中引用了cholmod.h
文件,而后者是无存的,因此报错。相关代码如下:
#ifndef G2O_LINEAR_SOLVER_CHOLMOD
#define G2O_LINEAR_SOLVER_CHOLMOD
#include "../core/linear_solver.h"
#include "../core/marginal_covariance_cholesky.h"
#include "../core/batch_stats.h"
#include "../stuff/timeutil.h"
#include "../stuff/sparse_helper.h"
#include <cholmod.h> // error occur!
纯粹cholmod
库的配置在 Windows 系统下似乎不易,但我获悉suitesparse
库中包含有cholmod
库,正如我们之前配置的PALACK
库中也包含有BLAS
库一样。有基于此,我们就只需要配置出suitesparse
库即可。该库在 Windows 系统下有源码版本可供配置,其github
地址如下:地址
不知为何,github
上的下载总是报错,我们因而去码云
上下载,地址如下:地址。
解压后直接 Configure->Generate 即可,一路绿灯,成功构建生成解决方案。
编译也是一路绿灯,注意采用Releasex64/MD
模式即可。成功编译生成所有的库文件后,我们新建suiteparse
文件夹,其下包含include
与lib
文件夹,前者添加所有的源文件,即库的根目录下的SuiteSparse
目录,后者则添加所有的库文件,命令行切换到相关目录下使用dir /b *.lib >list.txt
可以快速获取,生成的list.txt
文件的内容如下:
libamd.lib
libcamd.lib
libccolamd.lib
libcholmod.lib
libcolamd.lib
metis.lib
suitesparseconfig.lib
然后我在我的LearnVIORB
项目中新建suitesparse
属性表,添加对应的suitesparse
库的包含目录和库目录以及附加依赖项即可。
其他库的配置
其他的库我直接沿用ORBSLAM2
的库,这里就不再赘述。
编译错误Debug
MapPoint.cc
在编译运行项目时,该文件下述代码将会报错,大致是静态声明数组的大小表达式必须是常量云云。
float Distances[N][N]; // error occur!
直接修改为动态的声明即可,记得在该函数的末尾要添加释放指针的代码,如下所示:
// float Distances[N][N];
float ** Distances = new float*[N];
for (int i = 0; i < N; i++)
Distances[i] = new float[N];
...
delete[] Distances;
usleep 函数的修改
该函数是 Linux 下的库函数,Windows 下无法使用。此外,该函数延时的单位是微秒,而 Windows 下对应的Sleep
函数延时单位则是秒,因此需要修改为以下形式:
// usleep(3000)
std::this_thread::sleep_for(std::chrono::microseconds(3000));
注意要加上#include <windows.h>
头文件的引用。
TemplatedVocabulary.h
在该文件的第1484行,报错表达式的计算结果不是常数。我将buf
数组改为动态声明
// char buf[size_node];
char* buf = new char[size_node];
int nid = 1;
while (!f.eof()) {
...
}
delete buf;
sparse_block_matrix.hpp
该文件报错为:sparse_block_matrix.hpp(277): fatal error C1001: 编译器中发生内部错误。
注释第277行代码,替换如下:
// internal::axpy(*a, srcVec, srcOffset, destVec, destOffset);
internal::template axpy<SparseMatrixBlock>(*a, srcVec, srcOffset, destVec, destOffset);
&esmp;之后原先的第279行又报错如此,继续注释替换如下:
if (destOffset < srcOffset)
// internal::atxpy(*a, srcVec, destOffset, destVec, srcOffset);
internal::template atxpy<SparseMatrixBlock>(*a, srcVec, srcOffset, destVec, destOffset);
sparse_block_matrix_ccs.h
其错误和sparse_block_matrix.hpp
文件报错相同,在第125行,注释修改如下:
// internal::atxpy(*a, srcVec, srcOffset, destVec, destOffset);
internal::template atxpy<SparseMatrixBlock>(*a, srcVec, srcOffset, destVec, destOffset);
sparse_block_matrix_diagonal.h
第97行,应对同上,不再赘述。
// internal::axpy(A, srcVec, srcOffset, destVec, destOffset);
internal::template atxpy<SparseMatrixBlock>(A, srcVec, srcOffset, destVec, destOffset);
链接错误Debug
经过上述代码的修改,编译时终于不再报错,接下来是链接时的错误。
/MD 的问题
由于上述DBoW2
库和g2o
库都是在/MD
模式下配置的,因此在LearnVIORB
项目链接时,和我原先的Pangolin.lib
的运行库模式不匹配。这一点可以参考我的另一篇博文,另外配置/MD
模式的Pangolin
库即可。由于我先前配置过,因此我在这里就直接迁移了。
无法解析的外部符号
链接时的报错还有:
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 dtrsm_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 dtrsm_
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 ztrsm_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 ztrsm_
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 dgemm_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 dgemm_
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 zgemm_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 zgemm_
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 dsyrk_
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 zherk_
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 dpotrf_
1>libcholmod.lib(cholmod_super_numeric.o.obj) : error LNK2001: 无法解析的外部符号 zpotrf_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 dgemv_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 zgemv_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 dtrsv_
1>libcholmod.lib(cholmod_super_solve.o.obj) : error LNK2001: 无法解析的外部符号 ztrsv_
该错误和我之前一篇博文中,因为没有添加opengl32.lib
而报的错误在原理上非常相似。这些缺少实现的函数,都是BLAS
和LAPACK
库的函数。
由于LAPACK
是g2o
的依赖库,我们之前已经配置过,按理说可以直接沿用。但是,我如此尝试后,发现上述函数依旧缺失而无法解析。因此,我们转到之前在码云
上下载的suitesparse
库的根目录下,在其下的suitesparse-metis-for-windows-master\lapack_windows\x64
找到其自带的BLAS
和LAPACK
的库文件,然后将其复制到先前创建的suitesparse\lib
目录中,并在LearnVIORB
项目中的suitesparse
属性表添加对应的附加依赖项即可。
注意上述文件夹下的所有.dll
文件都是程序运行所必须的,需要额外复制到LearnVIORB
程序的运行目录下。
缺少各种 dll 文件
直接按照要求添加即可,不说废话。
运行的一些注意事项
首先,我们选择LearnVIORB_NOROS\Examples\ROS\ORB_VIO\src\ros_vio.cc
作为程序的入口。该源文件额外用到了boost
库,我选择沿用ORBSLAM2
之前配的boost
库。
我采用的运行参数如下,仅供参考:
D:/ORB-SLAM2/Run/Vocabulary/ORBvoc.bin D:/ORB-SLAM2/config/euroc.yaml D:/ORB-SLAM2/Run/data/mav0/imu0/data.csv D:/ORB-SLAM2/Run/data/mav0/cam0/data.csv D:/ORB-SLAM2/Run/data/mav0/cam0/data
&esmp;其提供的ros_vio.cc
默认是基于EuRoC
数据集的单目模式,只用到了cam0
的图像数据和imu0
的惯性数据。此外,由于该数据集一共有两万九千多行的 IMU 数据,读取起来特别慢,而且还没有什么回显,不看代码只看命令行界面的话还以为程序陷入什么死循环。因此,如果只是做测试的话,可以修改一下代码,不用把 IMU 数据全部读取完,只读上几千行就够跑很多帧了。
此外,该文件还存在一个 BUG,就是读取iListData
而构成的fullPath
变量的末尾缺少一个g
,这样会导致图像文件无法读取。我这里说起来很抽象,其实代码看过去一望便知。修改的话很简单,如下所示:
// string temp = iListData[j].imgName.substr(0,iListData[j].imgName.size()-1);
string temp = iListData[j].imgName;
噢对了,运行时用的参数文件并非ORBSLAM2
原版自带的参数文件,而是作者修改后添加了相关 IMU 配置的参数文件。其路径可参考如下:LearnVIORB_NOROS\config\euroc.yaml
。其实就在库的根目录下的config
目录里。
运行效果
由于我采用的是EuRoC
的Vicon Room 1 01
数据集,开头的很多帧运动不足,一直没有成功初始化。如此的情况,稍等片刻即可。
至于速度,普通帧倒是挺流畅的,只是每次插入关键帧的时候都会卡一下。
运行效果如下图所示:
后记
这篇指南是我一边配一边写的,草草写就,仅做记录。如今也无心校勘修改,因此仅供参考。如有所助,幸甚至焉。