配置 GCNv2_SLAM 所需的环境并实现纯 cpu 运行项目的全过程记录。

前排提醒:本文所述安装方式只在没有显卡的虚拟机上通过了测试,有显卡的主机涉及到 CUDA 等显卡依赖项版本问题,本文可能不适用

1. 环境说明

GCNv2_SLAM 是比较出名的基于 RGB-D 传感器的 SLAM 系统之一,对应的论文和 github 如下:

不过,对新手不友好的一点是,项目 github 的 readme 里面并没有详细的描述如何安装依赖项和运行这个项目(毕竟论文开源代码的目标人群都是会 SLAM 的),在慕雪搜索相关资料的时候还遇到了大量水文,给本来就不太了解 opencv 和 pytorch 的我造成了更大的困扰。

不过,最终我还是搜索到了几篇写的很不错的导引文章,里面详细说明了如何在纯 CPU 环境中运行这个项目,包括安装依赖项的全过程。

本文是对上述博客的汇总和记录,同时我还将 GCNv2_SLAM 的运行环境制作成了 dockerfile,可以在支持 docker 的 linux 桌面环境中运行。该镜像只在 parallels 的 ubuntu-22.04-arm64 虚拟机中测试过,不保证对其他环境也适用。

你可以在我的 github 中找到修改过后的项目和 dockerfile 文件:github.com/musnows/GCNv2_SLAM/tree/cpu;构建 docker 镜像和使用 docker 容器纯 cpu 运行 GCNv2 项目的引导可见:musnows/GCNv2_SLAM/docker/README

前期准备:

  • ubuntu-18.04-desktop 虚拟机或支持 docker 的 ubuntu-desktop 虚拟机;
  • 一个能正常 clone 到 github 项目的网络环境(不然会很烦);

本文示例环境:ubuntu 22.04 arm 虚拟机下启动的 ubuntu18.04 docker 容器(套娃)。

话不多说,开整!

2. 安装依赖项

项目运行主要要手动安装 4 个依赖项,以及数不清的 apt 包。

2.1. 基础 apt 包安装

运行之前先更新一下环境

bash
1
2
sudo apt-get update -y
sudo apt-get upgrade -y

首先是要用的到的工具包(这些都用得上)

bash
1
2
3
4
5
6
7
8
# 工具包
sudo apt-get install -y \
apt-utils \
curl wget unzip zip \
cmake make automake \
openssh-server \
net-tools \
vim git gcc g++

随后是 python 工具组

bash
1
2
3
4
5
6
7
sudo apt-get install -y \
python-dev \
python-pip \
python3-dev \
python3-pip \
python-all-dev \
python3-all-dev

还需要安装 x11 相关的依赖包

bash
1
2
3
4
5
6
7
8
# x11 for gui
sudo apt-get install -y \
libx11-xcb1 \
libfreetype6 \
libdbus-1-3 \
libfontconfig1 \
libxkbcommon0 \
libxkbcommon-x11-0

2.2. Pangolin 6.0

安装 pangolin 之前先安装如下依赖包

bash
1
2
3
4
5
6
7
8
9
# pangolin
sudo apt-get install -y \
libgl1-mesa-dev \
libglew-dev \
libboost-dev \
libboost-thread-dev \
libboost-filesystem-dev \
libpython2.7-dev \
libglu1-mesa-dev freeglut3-dev

随后使用如下命令来编译安装 Pangolin,Github 地址:Pangolin-0.6

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 下载
wget -O Pangolin-0.6.tar.gz https://github.com/stevenlovegrove/Pangolin/archive/refs/tags/v0.6.tar.gz
# 解压
tar -zxvf Pangolin-0.6.tar.gz

pushd Pangolin-0.6
rm -rf build
mkdir build && cd build
# 编译安装
cmake -DCPP11_NO_BOOST=1 ..
make -j$(nproc)
make install
# 刷新动态库
ldconfig
popd

image.png

随后使用如下命令检查是否安装成功

bash
1
2
3
4
5
# 检查安装成功(能不能编译demo)
cd Pangolin-0.6/examples/HelloPangolin
mkdir build && cd build
cmake ..
make

一切正常的话,应该能编译成功。

bash
1
2
3
4
5
root@ubuntu-linux-22-04-02-desktop:/work/docker/Pangolin-0.6/examples/HelloPangolin/build# make
Scanning dependencies of target HelloPangolin
[ 50%] Building CXX object CMakeFiles/HelloPangolin.dir/main.o
[100%] Linking CXX executable HelloPangolin
[100%] Built target HelloPangolin

随后执行./HelloPangolin 运行程序(需要在 GUI 环境中执行),如果出现了一个三色正方体的弹窗就是 ok 了

image.png

2.3. OpenCV 3.4.5

先安装依赖项

bash
1
2
3
4
5
6
7
8
9
10
11
# 解决:Unmet dependencies.Try'apt--fix-broken install'with no packages(or specify a solution)
sudo apt --fix-broken install
sudo apt-get update
sudo apt-get upgrade
# 安装依赖项
sudo apt-get install -y \
build-essential libgtk2.0-dev libgtk-3-dev \
libavcodec-dev libavformat-dev \
libjpeg.dev libtiff5.dev libswscale-dev \
libcanberra-gtk-module \
libavresample-dev libgphoto2-dev

opencv 的依赖项 libjasper 包在 arm64 和 amd64 上有区别,如果是 amd64 环境,使用如下命令安装。命令已在 ubuntu18.04 虚拟机中测试通过,就是 security.ubuntu.com 可能会因为网络问题无法联通,多试几次就 OK 了。

bash
1
2
3
4
5
6
7
# amd64
# 添加新源后继续安装
sudo apt-get install -y software-properties-common
# 下面这条命令实测在arm64上不能用,amd64平台可用
sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"
sudo apt-get -y update
sudo apt-get install -y libjasper1 libjasper-dev

amd64 平台添加新软件源后,update 命令执行结果如下

bash
1
2
3
4
5
6
7
$ sudo apt-get -y update
Hit:1 http://us.archive.ubuntu.com/ubuntu bionic InRelease
Hit:2 http://security.ubuntu.com/ubuntu bionic-security InRelease
Hit:3 http://us.archive.ubuntu.com/ubuntu bionic-updates InRelease
Hit:4 http://security.ubuntu.com/ubuntu xenial-security InRelease
Hit:5 http://us.archive.ubuntu.com/ubuntu bionic-backports InRelease
Reading package lists... Done

如果是 arm64 平台,使用上面的软件源会出现 404 错误,在本站另外一篇博客中有记录。

plaintext
1
2
3
4
5
6
Err:6 http://security.ubuntu.com/ubuntu xenial-security/main arm64 Packages
404 Not Found [IP: 185.125.190.83 80]
Fetched 106 kB in 2s (44.6 kB/s)
Reading package lists... Done
E: Failed to fetch http://security.ubuntu.com/ubuntu/dists/xenial-security/main/binary-arm64/Packages 404 Not Found [IP: 185.125.190.83 80]
E: Some index files failed to download. They have been ignored, or old ones used instead.

在 arm64 上需要借助老版本的清华源来安装,将如下命令写入脚本文件使用 sudo 执行。

bash
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env bash
set -e
# arm64 ubuntu 18.04
echo -e "deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ xenial main multiverse restricted universe\n\
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ xenial-security main multiverse restricted universe\n\
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ xenial-updates main multiverse restricted universe\n\
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ xenial-backports main multiverse restricted universe\n\
deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ xenial main multiverse restricted universe\n\
deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ xenial-security main multiverse restricted universe\n\
deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ xenial-updates main multiverse restricted universe" >> /etc/apt/sources.list && \
apt-get -y update
apt-get install -y libjasper1 libjasper-dev
arm64 成功安装 libjasper 的命令行输出
plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@ubuntu-linux-22-04-02-desktop:/# apt-get install -y libjasper1 libjasper-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
libjasper-runtime
The following NEW packages will be installed:
libjasper-dev libjasper1
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 613 kB of archives.
After this operation, 1327 kB of additional disk space will be used.
Get:1 http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports xenial-security/main arm64 libjasper1 arm64 1.900.1-debian1-2.4ubuntu1.3 [111 kB]
Get:2 http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports xenial-security/main arm64 libjasper-dev arm64 1.900.1-debian1-2.4ubuntu1.3 [502 kB]
Fetched 613 kB in 1s (758 kB/s)
debconf: unable to initialize frontend: Dialog
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76, <> line 2.)
debconf: falling back to frontend: Readline
Selecting previously unselected package libjasper1:arm64.
(Reading database ... 67223 files and directories currently installed.)
Preparing to unpack .../libjasper1_1.900.1-debian1-2.4ubuntu1.3_arm64.deb ...
root@ubuntu-linux-22-04-02-desktop:/#

安装好了依赖项后,使用如下命令编译 OpenCV,Github 地址:opencv 的 3.4.5 版本

PS: 如下命令同样适用于安装 OpenCV 3.2.0 版本,只需要更换链接中的版本号即可。

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 下载和解压
wget -O opencv-3.4.5.tar.gz https://github.com/opencv/opencv/archive/refs/tags/3.4.5.tar.gz
tar -zxvf opencv-3.4.5.tar.gz
# 开始编译和安装
pushd opencv-3.4.5
rm -rf build
mkdir build && cd build
# 构建和编译安装,-j4代表4线程并发
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
make -j$(nproc)
make install
# 刷新动态库
ldconfig
popd

使用如下命令检测 opencv 是否安装成功

bash
1
2
3
4
5
6
# pkg-config --modversion opencv
3.4.5
# pkg-config --cflags opencv
-I/usr/local/include/opencv -I/usr/local/include
# pkg-config --libs opencv
-L/usr/local/lib -lopencv_dnn -lopencv_ml -lopencv_objdetect -lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_video -lopencv_photo -lopencv_imgproc -lopencv_flann -lopencv_core

可以试试编译测试 demo 代码,注意需要在 GUI 环境中执行

bash
1
2
3
4
5
6
# 检测是否安装成功
cd opencv-3.4.5/samples/cpp/example_cmake
mkdir build && cd build
cmake ..
make
./opencv_example

如果成功运行,会弹出一个 hello opencv 的弹窗。如果你的环境有摄像头,则会出现摄像头画面,如果没有摄像头,则为黑屏画面。

image.png

如果运行这个 demo 的时候遇到了 Failed to load module "canberra-gtk-module" 错误,是因为缺少了一个软件包,安装一下就可以了(上文安装包中已经列出)。

bash
1
sudo apt-get install libcanberra-gtk-module

image.png

如果有摄像头的时候运行./opencv_example 的时,遇到了弹窗没有弹出程序就终止,请参考博客里面的说明尝试确认是否为 waitKey() 函数导致。

2.4. Eigen 3.7

Eigen 包在 gitlab 里面下载:gitlab.com/libeigen/eigen/-/releases/3.3.7

bash
1
2
3
4
5
6
7
8
9
# 下载
wget -O eigen-3.3.7.tar.gz https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz
tar -zxvf eigen-3.3.7.tar.gz
# 开始编译和安装
cd eigen-3.3.7
mkdir build && cd build
cmake ..
make
make install

注意需要执行 cp 命令拷贝一下头文件到另外一个目录中

bash
1
2
3
4
# 在很多程序中include时经常使用#include <Eigen/Dense>而不是使用#include <eigen3/Eigen/Dense>
# 因此安装后需要将头文件从 /usr/local/include/eigen3/ 复制到 /usr/local/include
# 后续小节会有C++测试代码说明
sudo cp -r /usr/local/include/eigen3/Eigen /usr/local/include

这里给出一个 cpp 的 demo 代码来测试是否安装成功(直接 g++ 编译就可以了)

cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
//需要将头文件从 /usr/local/include/eigen3/ 复制到 /usr/local/include
#include <Eigen/Dense>
//using Eigen::MatrixXd;
using namespace Eigen;
using namespace Eigen::internal;
using namespace Eigen::Architecture;
using namespace std;
int main()
{
cout<<"*******************1D-object****************"<<endl;
Vector4d v1;
v1<< 1,2,3,4;
cout<<"v1=\n"<<v1<<endl;

VectorXd v2(3);
v2<<1,2,3;
cout<<"v2=\n"<<v2<<endl;

Array4i v3;
v3<<1,2,3,4;
cout<<"v3=\n"<<v3<<endl;

ArrayXf v4(3);
v4<<1,2,3;
cout<<"v4=\n"<<v4<<endl;
}

运行结果如下

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@ubuntu-linux-22-04-02-desktop:/work/docker/pkg/eigen-3.3.7/build# g++ test.cpp -o test_eigen
root@ubuntu-linux-22-04-02-desktop:/work/docker/pkg/eigen-3.3.7/build# ./test_eigen
*******************1D-object****************
v1=
1
2
3
4
v2=
1
2
3
v3=
1
2
3
4
v4=
1
2
3

2.5. Pytorch 1.0.1 (libtorch)

原博客中安装的是 1.4.0,但是在我测试的 arm 环境中 1.4.0 有非常多的错误,这里直接采用 GCNv2 Github 中给出的 1.0.1 版本进行安装。

安装之前需要保证环境中有 python3(测试环境为 3.6.9)并安装 pyyaml 包

bash
1
2
sudo apt-get install python3-dev python3-pip
pip3 install pyyaml

随后克隆 pytorch 并编译 libtorch 动态库

bash
1
2
3
git clone --recursive -b v1.0.1 https://github.com/pytorch/pytorch
cd pytorch && mkdir build && cd build
python3 ../tools/build_libtorch.py

这里就有难题啦!整个 pytorch 的库加上 sub-modules 一共有 3gb 之大,要想从 github 上安稳克隆下来可不简单。这里给大家分享一个百度云盘的链接,是所有子模组都被成功 clone 之后的压缩包。

plaintext
1
2
通过网盘分享的文件:pytorch.full.1.0.1.tar.gz
链接: https://pan.baidu.com/s/1XHeYcHH5CMKmacFodFzqeA 提取码: 4h2g

下载了这个压缩包,使用 tar -zxvf 解压后,使用如下命令检查一下子模组是否完整,如果完整的话这个命令不会有任何输出。不完整它会继续下载子模组

bash
1
git submodule update --init --recursive

在执行 python3 ../tools/build_libtorch.py 之前还需要进行两处代码的修改,这里直接给出 sed 命令,在 pytorch 库的根目录执行。

bash
1
2
sed -i "s/yaml.load(\(.*\))/yaml.load(\1, Loader=yaml.FullLoader)/g" aten/src/ATen/cwrap_parser.py
sed -i "s/yaml.load(\(.*\))/yaml.load(\1, Loader=yaml.FullLoader)/g" tools/cwrap/cwrap.py

两个代码文件中都只有一处要修改的地方,分别是 pytorch/tools/cwrap/cwrap.py 文件里面的 91 行和 pytorch/aten/src/ATen/cwrap_parser.py 的 18 行。

这里的修改是因为 pyyaml 库的变动(环境中安装的 pyyaml 版本为 6.0.1),需要传入第二个参数 Loader。原有的代码是没有传入的,编译的时候会出现如下错误,日志中的重点就是 TypeError: load() missing 1 required positional argument: 'Loader' 缺少参数的报错。

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Traceback (most recent call last):
File "/work/pytorch/cmake/../aten/src/ATen/gen.py", line 465, in <module>
generate_outputs()
File "/work/pytorch/cmake/../aten/src/ATen/gen.py", line 390, in generate_outputs
for file in cwrap_files
File "/work/pytorch/cmake/../aten/src/ATen/gen.py", line 391, in <listcomp>
for d in cwrap_parser.parse(file)]
File "/work/pytorch/aten/src/ATen/cwrap_parser.py", line 18, in parse
declaration = yaml.load('\n'.join(declaration_lines))
TypeError: load() missing 1 required positional argument: 'Loader'
caffe2/CMakeFiles/ATEN_CPU_FILES_GEN_TARGET.dir/build.make:132: recipe for target 'aten/src/ATen/CPUByteType.cpp' failed
make[2]: *** [aten/src/ATen/CPUByteType.cpp] Error 1
CMakeFiles/Makefile2:3522: recipe for target 'caffe2/CMakeFiles/ATEN_CPU_FILES_GEN_TARGET.dir/all' failed
make[1]: *** [caffe2/CMakeFiles/ATEN_CPU_FILES_GEN_TARGET.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
[ 15%] Building CXX object third_party/protobuf/cmake/CMakeFiles/libprotobuf.dir/__/src/google/protobuf/wrappers.pb.cc.o
[ 15%] Linking CXX static library ../../../lib/libprotobuf.a
[ 15%] Built target libprotobuf
Makefile:140: recipe for target 'all' failed
make: *** [all] Error 2
Traceback (most recent call last):
File "../tools/build_libtorch.py", line 30, in <module>
subprocess.check_call(command, universal_newlines=True, env=my_env)
File "/usr/lib/python3.6/subprocess.py", line 311, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/work/pytorch/tools/build_pytorch_libs.sh', '--use-nnpack', '--use-qnnpack', 'caffe2']' returned non-zero exit status 2.

说实话,个人认为 pyyaml 库的这个变动非常不合理,版本更迭后,一个强制需要传入的参数应该给出缺省值才对。如果它给出了缺省值,那么这里的代码即便没有传入也不会报错了。

修改了这两处代码后,执行 python3 ../tools/build_libtorch.py,不出意外的话编译就成功啦。

image.png

原博主使用的 pytorch 1.4.0 需要解决的问题比我这里更多,如果你想通过 pytorch 1.4.0 来编译 libtorch,请参考本文最开头贴出的博客。

3. 编译 GCNv2_SLAM

接下来我们就可以编译正主啦!首先克隆代码

bash
1
git clone https://github.com/jiexiong2016/GCNv2_SLAM.git

3.1. 修改 build.sh 编译项目

修改项目根目录下的 build.sh,将 TORCH_PATH 修改为 pytorch 中的 torch/lib/tmp_install/share/cmake/Torch 目录。

sh
1
cmake .. -DCMAKE_BUILD_TYPE=Release -DTORCH_PATH=/work/gcnv2slam/pytorch/torch/lib/tmp_install/share/cmake/Torch

修改了之后,应该就可以执行./build.sh 来编译项目了。

比较奇怪的是我的环境中并没有 cuda 也依旧能在不修改任何代码的情况下编译成功。

最开始的时候,我遇到了一个难题,参考的博客中大多数都用的 pytorch 1.4.0,里面都提到了修改 TORCH_PATHpytorch/torch/share/cmake/Torch 目录,但是在我的 pytorch 1.0.1 里面压根没有这个目录。

本来都要放弃了,最终在 GCNv2 项目的 github 里面找到了说明,主要的修改点是 jiexiong2016/GCNv2_SLAM/commit/21cc44894 这一笔提交,readme 里面描述如下

The built libtorch library is located at pytorch/torch/lib/tmp_install/ in default.

Update: Have added support for master branch of pytorch or version larger than 1.0.1. For newer version, set TORCH_PATH to pytorch/torch/share/cmake/Torch

说白了就是在 1.0.1 版本中的 TORCH_PATH 是在 pytorch/torch/lib/tmp_install/ 里面的,更新的 pytorch 版本是在 pytorch/torch/share 目录,而 1.0.1 版本中不存在 pytorch/torch/share 目录。

3.2. 修改代码来实现纯 CPU 运行

3.2.1. 修改 GCNextractor.cc

第一处修改点在 GCNv2_SLAM/src/GCNextractor.cc 文件中

cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//第一处原代码216行:
const char *net_fn = getenv("GCN_PATH");
net_fn = (net_fn == nullptr) ? "gcn2.pt" : net_fn;
module = torch::jit::load(net_fn);
//修改为:
torch::DeviceType device_type;
device_type = torch::kCPU;
torch::Device device(device_type);
const char *net_fn = getenv("GCN_PATH");
net_fn = (net_fn == nullptr) ? "gcn2.pt" : net_fn;
module = torch::jit::load(net_fn,device);

//第二处原代码226行:
device_type = torch::kCUDA;
//修改为:
device_type = torch::kCPU;

修改后的截图如下

image.png

3.2.2. 修改 GCN2 下 pt 文件

其实 pt 文件是不影响编译的,可以在编译完成后再修改

修改 GCNv2_SLAM/GCN2 下 gcn2_320x240.pt、gcn2_640x480.pt 和 gcn2_tiny_320x240.pt 中的内容。需要先解压文件

bash
1
unzip gcn2_320x240.pt

解压出来之后会有 GCNv2_SLAM/GCN2/gcn/code/gcn.py 文件,将里面的 cuda:0 修改成 cpu,批量替换就可以了,每个文件里面都是 8 处。

image.png

替换了之后,重新压缩 pt 文件,先删了原本的,重新压缩

bash
1
2
3
rm -rf gcn2_320x240.pt
zip -r gcn2_320x240.pt gcn
rm -rf gcn #删除刚刚的gcn文件夹

这只是一个例子,其他几个 gcn2 压缩包都要用相同的方式修改!

bash
1
2
3
4
5
6
7
unzip gcn2_640x480.pt
rm -rf gcn2_640x480.pt
# 修改下面这个文件
# GCNv2_SLAM/GCN2/gcn2_480x640/code/gcn2_480x640.py
# 重新压缩
zip -r gcn2_640x480.pt gcn2_480x640
rm -rf gcn2_480x640
bash
1
2
3
4
5
6
7
unzip gcn2_tiny_320x240.pt
rm -rf gcn2_tiny_320x240.pt
# 修改文件
# gcnv2slam/GCNv2_SLAM/GCN2/gcn2_tiny/code/gcn2_tiny.py
# 重新压缩
zip -r gcn2_tiny_320x240.pt gcn2_tiny
rm -rf gcn2_tiny

3.2.3. 重新编译

修改之后重新编译项目,先删除原有的编译缓存

bash
1
2
3
4
rm -rf Thirdparty/g2o/build/
rm -rf Thirdparty/DBoW2/build/
rm -rf Vocabulary/*.bin
rm -rf ./build

没有问题,编译成功了。

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
Configuring and building ORB_SLAM2 ...
mkdir: cannot create directory 'build': File exists
Build type: Release
-- Using flag -std=c++11.
TORCH_PATH set to: /work/gcnv2slam/pytorch/torch/lib/tmp_install/share/cmake/Torch
-- Torch version is: 1.0.0
-- Configuring done
-- Generating done
-- Build files have been written to: /work/gcnv2slam/GCNv2_SLAM/build
[ 91%] Built target ORB_SLAM2
[100%] Built target rgbd_gcn
root@ubuntu-linux-22-04-02-desktop:/work/gcnv2slam/GCNv2_SLAM#

image.png

4. 使用 TUM 训练集运行项目

4.1. 下载数据集

下载地址:cvg.cit.tum.de/data/datasets/rgbd-dataset/download

下载 fr1/desk 数据集,这是一个桌子的 RGBD 数据

image.png

在 GCNv2_SLAM 工程下新建 datasets/TUM, 将数据集下载到其中

bash
1
2
3
4
5
6
7
# 新建datasets/TUM数据集文件夹
mkdir -p datasets/TUM
cd datasets/TUM
# 下载数据集到datasets/TUM文件夹内
wget -O rgbd_dataset_freiburg1_desk.tgz https://cvg.cit.tum.de/rgbd/dataset/freiburg1/rgbd_dataset_freiburg1_desk.tgz
# 解压数据集
tar -xvf rgbd_dataset_freiburg1_desk.tgz

然后还需要下载一个 associate.py 脚本来处理一下数据集才能正常运行

下载地址:svncvpr.in.tum.de,同时在我的 Github 仓库也做了留档。

plaintext
1
wget -O associate.py https://svncvpr.in.tum.de/cvpr-ros-pkg/trunk/rgbd_benchmark/rgbd_benchmark_tools/src/rgbd_benchmark_tools/associate.py

这个脚本只能用 python2 运行,需要下载 numpy 库(环境中 python2 是 2.7.17)

bash
1
2
3
4
5
# 容器内库安装
apt-get install -y python-pip
pip install numpy
# 在数据文件夹里执行命令
python associate.py rgbd_dataset_freiburg1_desk/rgb.txt rgbd_dataset_freiburg1_desk/depth.txt > rgbd_dataset_freiburg1_desk/associate.txt

注意下载 numpy 库的时候不要用镜像源,否则无法安装。直接下就行了。

plaintext
1
2
3
4
5
6
7
8
9
10
root@ubuntu-linux-22-04-02-desktop:/work/gcnv2slam/GCNv2_SLAM/datasets/TUM# pip install numpy                            
Collecting numpy
Downloading https://files.pythonhosted.org/packages/b7/6f/24647f014eef9b67a24adfcbcd4f4928349b4a0f8393b3d7fe648d4d2de3/numpy-1.16.6.zip (5.1MB)
100% |################################| 5.2MB 470kB/s
Building wheels for collected packages: numpy
Running setup.py bdist_wheel for numpy ... done
Stored in directory: /root/.cache/pip/wheels/cb/c2/c1/d99e8bf789c8dd07623af6be95e6a89984c85a05e31b8513c3
Successfully built numpy
Installing collected packages: numpy
Successfully installed numpy-1.16.6

执行 python 命令后可以看看合并成功了没有,如下应该就是没问题了。

plaintext
1
2
3
4
5
root@ubuntu-linux-22-04-02-desktop:/work/gcnv2slam/GCNv2_SLAM/datasets/TUM# python associate.py rgbd_dataset_freiburg1_desk/rgb.txt rgbd_dataset_freiburg1_desk/depth.txt > rgbd_dataset_freiburg1_desk/associate.txt
root@ubuntu-linux-22-04-02-desktop:/work/gcnv2slam/GCNv2_SLAM/datasets/TUM# tail rgbd_dataset_freiburg1_desk/associate.txt
1305031472.895713 rgb/1305031472.895713.png 1305031472.892944 depth/1305031472.892944.png
1305031472.927685 rgb/1305031472.927685.png 1305031472.924814 depth/1305031472.924814.png
1305031472.963756 rgb/1305031472.963756.png 1305031472.961213 depth/1305031472.961213.png

在同一个网站下载的其他数据集也需要用相同的方式进行处理

4.2. 运行 GCN2

随后进入项目的 GCN2 目录执行命令,我把命令中的路径都改成了相对路径

bash
1
2
cd GCN2
GCN_PATH=gcn2_320x240.pt ./rgbd_gcn ../Vocabulary/GCNvoc.bin TUM3_small.yaml ../datasets/TUM/rgbd_dataset_freiburg1_desk ../datasets/TUM/rgbd_dataset_freiburg1_desk/associate.txt

如果运行 tiny 数据集,命令如下

bash
1
2
cd GCN2
GCN_PATH=gcn2_tiny_320x240.pt ./rgbd_gcn ../Vocabulary/GCNvoc.bin TUM3_small.yaml ../datasets/TUM/rgbd_dataset_freiburg1_desk ../datasets/TUM/rgbd_dataset_freiburg1_desk/associate.txt

在 mac 上虚拟机安装的 arn 版本 ubuntu22.04 中用 docker 安装的 ubuntu18.04 成功运行本项目,虽然很卡,但是运行起来了!

image.png

image.png

最终结束后的输出如下

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
root@ubuntu-linux-22-04-02-desktop:/work/gcnv2slam/GCNv2_SLAM# cd GCN2/
root@ubuntu-linux-22-04-02-desktop:/work/gcnv2slam/GCNv2_SLAM/GCN2# GCN_PATH=gcn2_320x240.pt ./rgbd_gcn ../Vocabulary/GCNvoc.bin TUM3_small.yaml ../datasets/TUM/rgbd_dataset_freiburg1_desk ../datasets/TUM/rgbd_dataset_freiburg1_desk/associate.txt

ORB-SLAM2 Copyright (C) 2014-2016 Raul Mur-Artal, University of Zaragoza.
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under certain conditions. See LICENSE.txt.

Input sensor was set to: RGB-D

Loading ORB Vocabulary. This could take a while...
Vocabulary loaded!


Camera Parameters:
- fx: 267.7
- fy: 269.6
- cx: 160.05
- cy: 123.8
- k1: 0
- k2: 0
- p1: 0
- p2: 0
- fps: 30
- color order: RGB (ignored if grayscale)

ORB Extractor Parameters:
- Number of Features: 1000
- Scale Levels: 8
- Scale Factor: 1.2
- Initial Fast Threshold: 20
- Minimum Fast Threshold: 7

Depth Threshold (Close/Far Points): 5.97684

-------
Start processing sequence ...
Images in the sequence: 573

New map created with 251 points
Finished!
-------

median tracking time: 1.7969
mean tracking time: 1.82306

Saving camera trajectory to CameraTrajectory.txt ...

trajectory saved!

Saving keyframe trajectory to KeyFrameTrajectory.txt ...

trajectory saved!
root@ubuntu-linux-22-04-02-desktop:/work/gcnv2slam/GCNv2_SLAM/GCN2#

同时我在 vmware16 安装的 ubuntu18.04 虚拟机中也运行了本项目,速度更慢。宿主机配置为牙膏厂的 i5-10400+16GB 内存,虚拟机分配了 8 核 8GB。

image.png

image.png

4.3. 简单分析一下结果

在 mac m3 16G 上 parallels 安装的 arm64 版本 ubuntu22.04 虚拟机(4 核 8G)中用 docker 运行的 ubuntu18.04 容器,容器内运行 gcn2_320x240.pt 的速度如下,约合 0.55hz

plaintext
1
2
median tracking time: 1.7969
mean tracking time: 1.82306

在 vmware16 安装的 amd64 版本 ubuntu18.04 的虚拟机(8 核 8G)中,运行 gcn2_320x240.pt 的速度如下,约合 0.21hz。没想到比 arm 的速度还慢!

plaintext
1
2
median tracking time: 4.70296
mean tracking time: 4.62603

作为对比,GCNv2 论文中提到了两个平台的运行结果,翻译如下

“GCNv2 和我们改进了 SLAM 方法的 GCN-SLAM,在配备 Intel i7-7700HQ 和移动版 NVIDIA 1070 的笔记本电脑上运行约 80 Hz。为了实现更高的帧率,以满足 Jetson TX2 上实时推理的需求,我们引入了 GCNv2 的一个较小版本,称为 GCNv2-tiny,在此版本中,我们从 conv2 开始将特征图的数量减少了一半。GCNv2-tiny 运行在 40 Hz,使用 GCNv2-tiny 的 GCN-SLAM 在 TX2 上运行为 20 Hz,非常适合部署在无人机上。”

image.png

只能说纯 CPU 运行的效果也太差了!应该是因为 GCNv2_SLAM 项目有用到神经网络,所以没有显卡的话速度会非常慢。

5. The end

折腾了好几天,才成功把 GCNv2_SLAM 需要的环境给配置好,可惜 GCNv2 用到了深度神经网络,在没有 GPU 的环境下纯 CPU 运行的效果太差了,不知道有没有办法优化一下。

另外,我似乎没搜到 GCNv2_SLAM 在较新一点的带 N 卡的电脑(比如 30 系以后的 N 卡)中运行的教程博客,如果想用 GPU 来运行一下本项目,估计又是一个大麻烦事……

更新:慕雪已在 AutoDL 云平台的 2080ti 显卡容器化环境中成功运行了 GCNv2_SLAM,效果远好于本地 CPU 运行,详见【SLAM】于 AutoDL 云上 GPU 运行 GCNv2_SLAM 的记录