news 2026/9/8 14:12:58

视觉SLAM入门路线:从《十四讲》到ORB-SLAM3实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
视觉SLAM入门路线:从《十四讲》到ORB-SLAM3实战

最近几年,具身智能、人形机器人、无人驾驶成了 AI 领域最热的方向。不管是让机器人自己走路避障,还是让汽车在复杂道路上感知环境,背后都有一个交叉学科的影子:SLAM,尤其是视觉 SLAM(Visual SLAM,简称 VSLAM)。很多读者后台问我,想系统入门视觉 SLAM,第一步应该看什么?我通常会回答:把《视觉SLAM十四讲》这本书吃透,配套把 ORB-SLAM3 跑起来,基本就摸到门道了。

不过,《视觉SLAM十四讲》这本书内容非常密集,涉及李群李代数、非线性优化、特征点法、直接法、回环检测、地图构建等多个模块。很多初学者在看书过程中会遇到“公式看得懂、代码跑不起来”的困境。本文结合我自己的学习经历和工程实践,把从零入门视觉 SLAM 的关键概念、学习主线、环境搭建、运行 Demo 的完整路径整理出来,希望能帮你把这条学习曲线走平一些。

无论你将来是做机器人导航、无人驾驶、AR/VR,还是具身智能算法,视觉 SLAM 都是一门绕不开的基础课。读完本文,你会明白视觉 SLAM 的整体框架是什么,四个核心模块分别解决什么问题,以及在一台 Ubuntu 机器上如何把 ORB-SLAM3 完整跑起来。我会尽量把原理和实操结合起来,代码、命令、配置都给全,方便你照着做。

1. 背景与核心概念:为什么视觉SLAM如此重要

1.1 SLAM是什么

SLAM 的全称是 Simultaneous Localization and Mapping,中文叫“同时定位与建图”。简单说,就是让一个移动的载体(机器人、无人机、汽车、手机)在没有事先知道环境地图的情况下,一边确定自己在哪里,一边构建周围环境的地图。它的英文名称包含了两个任务:

  • Localization:定位,解决“我在哪”的问题。
  • Mapping:建图,解决“周围长什么样”的问题。

这两个问题互相耦合:定位需要地图,建图需要知道当前位姿。所以 SLAM 本质上是一个“鸡生蛋、蛋生鸡”的问题,需要通过传感器数据和状态估计算法一起求解。

根据传感器类型,SLAM 可以分成激光 SLAM 和视觉 SLAM。激光 SLAM 直接测距,精度高、受光照影响小,但激光雷达贵,而且只能获取几何信息,无法感知纹理和颜色。视觉 SLAM 则使用相机作为传感器,成本低、信息丰富,既能做定位,也能识别语义信息,因此在无人驾驶、服务机器人、AR/MR 领域不可替代,唯一的难点是视觉信息计算量大,对算法和算力要求更高。

1.2 视觉SLAM与具身智能、无人驾驶的关系

这里先梳理一个概念链条:

  • 具身智能(Embodied AI)指的是让 AI 拥有“身体”,能感知环境、做出决策并行动,比如人形机器人、机械臂抓取。
  • 机器人要在真实世界中导航、避障、抓取,首先就需要知道“我在哪”“物体在哪”“障碍物在哪”。这三个问题分别对应 SLAM 的定位、语义感知和建图能力。
  • 无人驾驶感知系统中,一个关键环节是在线实时定位。视觉 SLAM 可以结合 IMU、轮速计、RTK 等传感器,在 GPS 失效场景(地下车库、隧道)中提供连续、精确的位姿估计。

所以,视觉 SLAM 是机器人和无人驾驶“感知-决策-执行”链路中最底层的一环,也是具身智能学习路线的第一站。

1.3 为什么从《视觉SLAM十四讲》开始

《视觉SLAM十四讲》(以下简称《十四讲》)是国内最受欢迎的一本视觉 SLAM 入门书,配套有开源代码,内容覆盖了视觉 SLAM 的完整数学基础和工程实现。很多人说这本书“劝退”,原因在于:

  • 数学要求高:旋转矩阵、变换矩阵、四元数、李群李代数、非线性优化。
  • 依赖环境复杂:OpenCV、Eigen、Sophus、Ceres、G2O、PCL、DBoW3 等库版本众多,配置很容易踩坑。
  • 跨学科:涉及图像处理、概率论、多视图几何、图优化等多个方向。

但这恰恰说明一个问题:只有把这些基础啃下来,后面的高层应用才能真正理解。如果你能跑通书中的代码,再把 ORB-SLAM3 运行起来,你对 SLAM 的认知会有一个质的飞跃。

1.4 经典视觉SLAM系统运行框架

为了便于记忆,可以把视觉 SLAM 分成四个核心模块:

模块英文名称核心任务常用方法
前端视觉里程计Front-end Visual Odometry (VO)根据相邻帧估算相机相对运动,构建局部轨迹特征点法(ORB)、直接法(LSD-SLAM)、半直接法(SVO)
后端优化Back-end Optimization对相机位姿和地图点进行全局优化,消除累积漂移扩展卡尔曼滤波(EKF)、BA(Bundle Adjustment)、位姿图优化
回环检测Loop Closure Detection识别相机是否回到之前访问过的位置词袋模型(BoW)、DBoW2/DBoW3、深度学习全局描述子
建图Mapping根据位姿和观测构建地图表达稀疏点云、稠密点云、八叉树地图(OctoMap)、栅格地图

下图是经典的视觉 SLAM 流程图(用文字描述):

传感器数据(图像/IMU) ↓ 前端视觉里程计(帧间位姿估计) ↓ 后端优化(全局位姿、地图点、滑动窗口) ↓ 回环检测(当前位置是否访问过) —→ 触发回环修正 ↓ 地图构建(稀疏/稠密/语义地图)

初学者最容易踩的一个误区是:只盯着“帧间匹配”,以为 SLAM 就是算一个变换矩阵。实际上,没有回环检测的 SLAM 只能叫视觉里程计,因为误差会不断累积;没有后端优化的 SLAM 轨迹会越飘越远。只有把四个模块串联起来,才是一个完整的 SLAM 系统。

2. 环境准备与版本说明

2.1 操作系统与编译工具

如果你的目标是学习算法而非生产部署,推荐使用 Ubuntu 20.04 或 Ubuntu 22.04。本文示例针对 Ubuntu 20.04 + ROS Noetic 组合,这也是目前《十四讲》和 ORB-SLAM3 社区最常见的搭配。

版本需要根据你的项目实际情况调整,本文示例以常见环境为例,重点演示配置思路。如果你的系统是 Ubuntu 22.04,有些库(比如 OpenCV 4.5.x、PCL 1.12)版本更高,编译 ORB-SLAM3 时通常也没有问题,但需要注意 Ceres 和 Pangolin 的版本匹配。

2.2 依赖清单

视觉 SLAM 是一个重度依赖第三方库的方向,下面列出最关键的几项:

库名称作用示例版本
Eigen线性代数库,矩阵运算基础3.3.7
Sophus李群李代数库,支持 SO(3) / SE(3)书中修改版
OpenCV图像读取、特征提取、相机标定4.2.0 / 4.5.5
Ceres非线性最小二乘优化库1.14.0 / 2.1.0
G2O图优化库,基于顶点和边书中修改版
PangolinOpenGL 可视化库,画轨迹和相机位姿0.6
PCL点云处理库,用于建图1.10
ROS机器人操作系统Noetic / Foxy

2.3 安装基础工具

在开始之前,先把系统的编译工具链装好:

sudo apt update sudo apt install -y build-essential cmake git pkg-config sudo apt install -y libeigen3-dev libglew-dev libglfw3-dev sudo apt install -y libgoogle-glog-dev libgflags-dev sudo apt install -y libatlas-base-dev libsuitesparse-dev

上面这些库中,libeigen3-dev是矩阵运算基础,libsuitesparse-dev是稀疏线性求解依赖,Ceres 和 G2O 都会用到。libgoogle-glog-devlibgflags-dev是日志和命令行解析库。

2.4 安装OpenCV

OpenCV 的选择要谨慎。Ubuntu 自带源里的 OpenCV 通常是 4.2 或 4.5,对大多数例子来说足够。可以这样安装:

sudo apt install -y libopencv-dev

安装完成后验证版本:

pkg-config --modversion opencv4

如果需要编译 Pangolin 或者 ORB-SLAM3,建议同时安装 OpenCV contrib 模块吗?这里要提醒:ORB-SLAM3 只需要基础模块,不需要 contrib。编译时如果 OpenCV 版本太高(比如 4.8+),某些旧代码可能因为CV_LOAD_IMAGE_GRAYSCALE等 API 变更而报错,遇到时改为cv::IMREAD_GRAYSCALE即可。

2.5 编译Pangolin

Pangolin 是可视化库,《十四讲》第三版使用 Pangolin 0.6。编译步骤:

git clone https://github.com/stevenlovegrove/Pangolin.git cd Pangolin git checkout v0.6 mkdir build && cd build cmake .. make -j$(nproc) sudo make install

注意:如果 clone 的默认分支是 0.9/0.8 版本,接口会发生一些变化(比如gl::GlTexture之类的命名空间调整),所以一定要按 v0.6 这个 tag 编译,除非你想用新版适配代码。

2.6 安装Ceres和G2O

《十四讲》的许多示例依赖 Ceres 和 G2O。如果你只想先跑通演示,可以只装 Ceres:

git clone https://github.com/ceres-solver/ceres-solver.git cd ceres-solver mkdir build && cd build cmake .. make -j$(nproc) sudo make install

G2O 因为作者维护了一个修改过的分支,建议直接从《十四讲》源码的3rdparty里编译。也可以使用官方原版,但部分示例会依赖g2o::VertexSE3Expmap之类的类,官方库接口略有差异,编译时如果报错,先检查接口变化。

2.7 拉取《十四讲》源码

高翔老师维护的《十四讲》配套代码是:https://github.com/gaoxiang12/slambook2

这是第二版,也是目前使用最广泛的版本。第三方库放在了slambook2/3rdparty目录下,你可以把整个仓库克隆到本地:

git clone https://github.com/gaoxiang12/slambook2.git cd slambook2

书的配套代码并不是一个大工程,而是按章节拆成了多个独立的文件夹,例如:

  • ch3/:三维空间刚体运动
  • ch4/:李群李代数
  • ch5/:相机模型与图像
  • ch6/:非线性优化
  • ch7/:特征点法视觉里程计
  • ch9/:设计前端
  • ch10/:后端优化
  • ch11/:位姿图优化
  • ch12/:回环检测
  • ch13/:建图

强烈建议按章节顺序编译运行。不要一开始就跳到 ORB-SLAM3,否则会缺少中间很多数学和工程铺垫。

3. 核心原理拆解:从数学到系统

3.1 三维空间刚体运动:旋转矩阵、变换矩阵、四元数

SLAM 中最重要的一个基础问题,是如何描述相机在空间中的位置和朝向。

相机位姿由旋转矩阵 $R$ 和平移向量 $t$ 组成,通常用变换矩阵 $T$ 表示:

$$T = \begin{bmatrix} R & t \ 0^T & 1 \end{bmatrix}$$

一个三维点在世界坐标系下的坐标 $p_w$,经过变换矩阵 $T$ 转换到相机坐标系:

$$p_c = T \cdot p_w$$

在代码里,Eigen 提供了矩阵运算模块:

#include <Eigen/Core> #include <Eigen/Geometry> int main() { // 定义旋转角:绕 Z 轴旋转 45 度 double angle = M_PI / 4; Eigen::Matrix3d R = Eigen::AngleAxisd(angle, Eigen::Vector3d::UnitZ()).toRotationMatrix(); // 定义平移向量 Eigen::Vector3d t(1.0, 2.0, 3.0); // 构造变换矩阵 T Eigen::Isometry3d T = Eigen::Isometry3d::Identity(); T.rotate(R); T.pretranslate(t); // 世界坐标系下的点 Eigen::Vector3d p_w(0.0, 1.0, 0.0); // 转换到相机坐标系 Eigen::Vector3d p_c = T * p_w; std::cout << "p_c = " << p_c.transpose() << std::endl; return 0; }

这里有一个新手容易混淆的概念:Isometry3d本质上是一个四维的齐次变换矩阵,但在 Eigen 中可以直接乘以三维点,Eigen 内部自动完成齐次坐标变换。实际工程中,一定要明确点是“在世界系”还是“在相机系”,这是很多 bug 的根源。

四元数也是描述旋转的一种方式,优点是简洁、无奇异性、插值方便。但四元数不好直观理解,一般建议先把旋转矩阵和变换矩阵搞清楚,四元数只需知道和矩阵之间的转换关系即可。

3.2 相机模型与内参

相机把三维世界投影到二维图像,这个过程可以用针孔相机模型描述:

  • 相机坐标系下的点 $(X, Y, Z)$
  • 投影到归一化平面坐标 $(x, y) = (X/Z, Y/Z)$
  • 再经过内参矩阵 $K$ 得到像素坐标:

$$u = f_x \cdot x + c_x$$ $$v = f_y \cdot y + c_y$$

内参矩阵 $K$ 可以写成:

$$K = \begin{bmatrix} f_x & 0 & c_x \ 0 & f_y & c_y \ 0 & 0 & 1 \end{bmatrix}$$

其中,$f_x, f_y$ 是焦距(单位像素),$c_x, c_y$ 是主点坐标。

在代码中,用 OpenCV 读取图像并查看内参的例子:

#include <opencv2/opencv.hpp> #include <iostream> int main() { // 读取图像 cv::Mat image = cv::imread("/home/your_name/slambook2/ch5/undistort/1.png", cv::IMREAD_COLOR); if (image.empty()) { std::cerr << "Failed to load image" << std::endl; return -1; } // 内参矩阵,实际值需要根据相机标定得到 cv::Mat K = (cv::Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1); // 畸变系数 cv::Mat distCoeffs = (cv::Mat_<double>(1, 5) << -0.2541, 0.1159, 0, 0, 0); // 去除畸变 cv::Mat undistorted; cv::undistort(image, undistorted, K, distCoeffs); cv::imwrite("undistorted.png", undistorted); std::cout << "Undistortion done." << std::endl; return 0; }

相机标定是视觉 SLAM 工程落地中绕不开的流程。常见的标定工具包括:

  • OpenCV 提供的calibrateCamera()接口。
  • ROS 中的camera_calibration功能包。
  • 张正友棋盘格标定法。

在生产环境中,相机的内参和畸变系数必须精确标定,否则前端的特征匹配和三角化都会产生明显误差。

3.3 非线性优化与图优化

视觉 SLAM 的位姿估计本质上是一个状态估计问题。我们要找一组相机位姿和三维空间点,使得所有观测误差最小。这个问题的数学形式是最小二乘问题:

$$\min \sum_{i,j} | z_{ij} - h(T_i, P_j) |^2$$

其中 $z_{ij}$ 是实际观测到的像素坐标,$h$ 是重投影函数,$T_i$ 是第 i 帧相机位姿,$P_j$ 是第 j 个地图点坐标。

高斯牛顿法和列文伯格-马夸尔特法(LM)是解决这个问题的常用方法。Eigen 本身不做非线性优化,我们通常借助 Ceres 或 G2O 完成。

下面用 Ceres 演示一个非常简单的曲线拟合问题,理解 Ceres 的基本用法:

#include "ceres/ceres.h" #include "glog/logging.h" #include <iostream> #include <cmath> // 残差块:拟合 y = exp(a * x + b) + w struct ExponentialResidual { ExponentialResidual(double x, double y) : x_(x), y_(y) {} template <typename T> bool operator()(const T* const a, const T* const b, T* residual) const { residual[0] = y_ - exp(a[0] * x_ + b[0]); return true; } private: const double x_; const double y_; }; int main(int argc, char** argv) { google::InitGoogleLogging(argv[0]); // 生成带噪声的数据 const double a_true = 0.3, b_true = 0.1; std::vector<double> x_data, y_data; for (int i = 0; i < 100; ++i) { double x = i * 0.1; double y = exp(a_true * x + b_true) + (rand() % 1000) / 1000.0 * 0.2 - 0.1; x_data.push_back(x); y_data.push_back(y); } // 初始估计 double a = 0.0, b = 0.0; ceres::Problem problem; for (int i = 0; i < x_data.size(); ++i) { problem.AddResidualBlock( new ceres::AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>( new ExponentialResidual(x_data[i], y_data[i])), nullptr, &a, &b); } ceres::Solver::Options options; options.max_num_iterations = 100; options.linear_solver_type = ceres::DENSE_QR; options.minimizer_progress_to_stdout = true; ceres::Solver::Summary summary; ceres::Solve(options, &problem, &summary); std::cout << summary.BriefReport() << std::endl; std::cout << "Estimated a: " << a << ", b: " << b << std::endl; return 0; }

这段代码的核心思想是:定义残差、添加残差块、求解。在视觉 SLAM 中,残差就是“重投影误差”,而待优化的变量就是相机位姿和地图点坐标。理解 Ceres 的使用方法后,再去看 ORB-SLAM3 中的优化代码就不会太吃力。

3.4 前端视觉里程计:特征点法

特征点法是目前最成熟、最常用的视觉里程计方法。它主要由以下步骤组成:

  1. 提取特征点:FAST、ORB 等。
  2. 计算描述子:ORB 描述子。
  3. 匹配特征点:暴力匹配或快速近似最近邻(FLANN)。
  4. 求解相对运动:对极几何(2D-2D),PnP(3D-2D),ICP(3D-3D)。
  5. 剔除误匹配:随机采样一致性(RANSAC)。

ORB 特征在旋转和光照上都有一定的鲁棒性,提取速度也快,适合实时 SLAM。OpenCV 中提取 ORB 特征的代码:

#include <opencv2/opencv.hpp> #include <opencv2/features2d.hpp> #include <iostream> int main() { cv::Mat img1 = cv::imread("1.png", cv::IMREAD_GRAYSCALE); cv::Mat img2 = cv::imread("2.png", cv::IMREAD_GRAYSCALE); if (img1.empty() || img2.empty()) { std::cerr << "Failed to load images" << std::endl; return -1; } // 提取 ORB 特征 std::vector<cv::KeyPoint> kp1, kp2; cv::Mat desc1, desc2; cv::Ptr<cv::ORB> orb = cv::ORB::create(500, 1.2f, 8, 31, 0, 2, cv::ORB::HARRIS_SCORE, 31, 20); orb->detectAndCompute(img1, cv::noArray(), kp1, desc1); orb->detectAndCompute(img2, cv::noArray(), kp2, desc2); // 暴力匹配 std::vector<cv::DMatch> matches; cv::BFMatcher matcher(cv::NORM_HAMMING); matcher.match(desc1, desc2, matches); // 筛选最优匹配 double min_dist = 10000; for (const auto& m : matches) { if (m.distance < min_dist) min_dist = m.distance; } std::vector<cv::DMatch> good_matches; for (const auto& m : matches) { if (m.distance <= std::max(2 * min_dist, 30.0)) { good_matches.push_back(m); } } cv::Mat img_match; cv::drawMatches(img1, kp1, img2, kp2, good_matches, img_match); cv::imshow("good matches", img_match); cv::waitKey(0); std::cout << "Total good matches: " << good_matches.size() << std::endl; return 0; }

为什么匹配之后还要做 RANSAC?因为图像中的错误匹配是不可避免的,哪怕描述子距离很小,也可能匹配到错误位置。RANSAC 可以从包含误匹配的对应点集合中估计出正确的变换模型,同时把外点剔掉。在《十四讲》第7章中,你还会看到用对极约束求解本质矩阵 E,再分解得到 R 和 t 的完整流程。

4. 完整实战案例:编译运行ORB-SLAM3

当你学完《十四讲》的大部分章节后,下一步就是跑一个完整、现代的 SLAM 系统。ORB-SLAM3 是目前最经典、影响力最大的特征点法 SLAM 之一,支持单目、双目、RGB-D 和 IMU 融合。本小节以 RGB-D 模式为例,带你在 Ubuntu 上跑通一个 TUM 数据集序列。

4.1 下载ORB-SLAM3源码

ORB-SLAM3 官方仓库是:https://github.com/UZ-SLAMLab/ORB_SLAM3(注意大小写)。

git clone https://github.com/UZ-SLAMLab/ORB_SLAM3.git cd ORB_SLAM3

4.2 ORB-SLAM3依赖说明

ORB-SLAM3 依赖以下库:

  • OpenCV
  • Eigen3
  • Pangolin(可视化界面)
  • DBoW2(回环检测词袋,SLAM 源码自带第三方库)
  • g2o(图优化,源码自带第三方库)
  • Sophus(源码自带第三方库)

如果你按照第 2 节装好了 Pangolin 和 OpenCV,就可以直接编译 ORB-SLAM3。在执行编译前,还需要安装:

sudo apt install -y libssl-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev

然后执行编译:

cd ORB_SLAM3 chmod +x build.sh ./build.sh

编译时间取决于机器性能,通常需要几分钟到十几分钟。如果网络不稳定导致 DBoW2 或 g2o 子模块下载失败,可以在ORB_SLAM3/Thirdparty目录下单独编译各个子模块。

4.3 下载TUM数据集

TUM RGB-D 数据集是慕尼黑工业大学公开的视觉 SLAM 评估数据集,包含彩色图、深度图和真实轨迹。常用的是rgbd_dataset_freiburg1_desk

wget https://cvg.cit.tum.de/rgbd/dataset/freiburg1/rgbd_dataset_freiburg1_desk.tgz tar -xzvf rgbd_dataset_freiburg1_desk.tgz

如果下载地址失效,也可以去 TUM 官网手动下载。数据集解压后需要确认目录下有rgb.txtdepth.txtgroundtruth.txtrgb/depth/文件夹。

4.4 运行RGB-D示例

ORB-SLAM3 自带 TUM RGB-D 示例,运行前需要准备Examples/RGB-D/TUM1.yaml配置文件。通常这个文件已经在仓库里了,我们只需要执行:

./Examples/RGB-D/rgbd_tum \ Vocabulary/ORBvoc.txt \ Examples/RGB-D/TUM1.yaml \ /path/to/rgbd_dataset_freiburg1_desk \ /path/to/rgbd_dataset_freiburg1_desk/associations.txt

其中associations.txt是彩色图和深度图的配对文件。如果数据集目录没有这个文件,可以用仓库自带的 Python 脚本生成:

import os rgb_dir = "rgb" depth_dir = "depth" def load_timestamps(filepath): timestamps = [] with open(filepath, "r") as f: for line in f: line = line.strip() if line.startswith("#") or not line: continue parts = line.split() timestamps.append((parts[0], parts[1])) return timestamps rgb_items = load_timestamps("rgb.txt") depth_items = load_timestamps("depth.txt") with open("associations.txt", "w") as f: for rgb_ts, rgb_file in rgb_items: # 找时间戳最近的深度图 best_depth = None best_diff = float("inf") for depth_ts, depth_file in depth_items: diff = abs(float(rgb_ts) - float(depth_ts)) if diff < best_diff: best_diff = diff best_depth = depth_file if best_depth: f.write(f"{rgb_ts} {rgb_file} {float(rgb_ts) + 0.0:.6f} {best_depth}\n")

注意,这个脚本简化了深度图时间戳的配对逻辑,实际 TUM 数据集的 association 脚本要更严谨一些。官方提供的associate.py可以在这里获取:

wget https://raw.githubusercontent.com/raulmur/ORB_SLAM2/master/Examples/RGB-D/associate.py python associate.py rgb.txt depth.txt > associations.txt

之所以要配准时间戳,是因为深度图和彩色图是不同相机异步采集的,直接按文件顺序简单拼接会导致像素对不齐,最终轨迹精度变差。

4.5 预期运行结果

程序启动后会出现 Pangolin 可视化窗口,显示相机轨迹和稀疏地图点。终端会打印每帧处理的耗时、当前关键帧数量、地图点数量等。数据集运行结束后,程序会输出轨迹文件KeyFrameTrajectory.txt,你可以用 Python 和 matplotlib 画出来。

import numpy as np import matplotlib.pyplot as plt data = [] with open("KeyFrameTrajectory.txt", "r") as f: for line in f: line = line.strip() if line.startswith("#") or not line: continue parts = line.split() data.append([float(parts[0]), float(parts[1]), float(parts[2]), float(parts[3])]) data = np.array(data) plt.figure(figsize=(8, 6)) plt.plot(data[:, 1], data[:, 2], linewidth=1.0) plt.xlabel("x (m)") plt.ylabel("z (m)") plt.title("ORB-SLAM3 Trajectory") plt.grid(True) plt.savefig("trajectory.png", dpi=200)

运行成功后,你实际上已经完成了一个“从传感器数据到轨迹输出”的完整链路。接下来再去分析它的源码,比如跟踪线程、局部建图线程、回环检测线程,就有了很好的工程基础。

5. 常见问题与排查思路

视觉 SLAM 环境配置是出了名的麻烦。这里整理几个我经常遇到的报错和排查方法。

问题现象常见原因解决思路
编译 C++ 代码报错找不到 Eigen3没有安装 Eigen 或 CMake 找不到 Eigen3_DIRsudo apt install libeigen3-dev;CMake 里添加find_package(Eigen3 REQUIRED)
OpenCV 版本不匹配,报cuda_gl_interop.h不存在OpenCV CPU 版本和 CUDA 冲突重新安装非 CUDA 版 OpenCV;或删除系统中 CUDA 相关 OpenCV 头文件
ORB-SLAM3 编译时usleep报错在新版 glibc 中usleep声明被移除在源码文件中添加#include <unistd.h>;若仍报错,在system.cc里加int usleep(useconds_t usec);声明
Pangolin 版本太新,API 变动导致编译失败使用了 Pangolin 0.8/0.9切换到 v0.6 tag 重新编译
TUM 数据集运行后轨迹明显漂移相机内参配置不对或者 RGB-D 深度图时间戳没配对好检查 TUM1.yaml 中 fx、fy、cx、cy 是否正确;重新生成 associations.txt
单目模式初始化失败,一直显示trying to initialize场景纹理不够丰富,或者相机移动幅度太小改用纹理丰富的序列;平移相机而不是原地旋转
编译时g2o报大量链接错误G2O 的库版本和 ORB-SLAM3 自带的第三方库冲突优先使用 ORB-SLAM3 自带的Thirdparty/g2o,不要用系统安装的 g2o

5.1 例:Pangolin编译失败的解决

Pangolin 是一个依赖很多图形库的项目,常见报错包括:缺少xkbcommon、缺少Wayland、缺少libepoxy。可以按如下顺序安装:

sudo apt install -y libxkbcommon-dev libwayland-dev libepoxy-dev libx11-dev libxrandr-dev libxi-dev libxcursor-dev libxinerama-dev libxxf86vm-dev

然后再重新编译 Pangolin,基本可以解决大部分图形库依赖问题。

5.2 例:RGB-D序列显示“no depth image”问题

运行 TUM RGB-D 序列时,如果控制台一直提示找不到深度图,大概率是associations.txt生成失败。此时可以用head命令检查文件内容:

head -n 5 associations.txt

正常内容应该是:

1305031102.175304 1305031102.175304.png 1305031102.183763 1305031102.183763.png

如果发现文件内容是空白的,说明associate.py的路径参数写错了。

5.3 例:并行编译内存不足导致卡死

ORB-SLAM3 的编译过程比较吃内存,默认的make -j会耗尽内存。建议使用make -j4甚至make -j2,特别是虚拟机环境下。如果卡死,先kill进程,再降低并行编译线程数重试。

6. 工程实践与进阶建议

6.1 理论学习路线

如果你完全零基础,我建议按下面的顺序推进:

  1. 先学习 C++ 基础和 Linux 操作,至少会写类、STL 容器、编译 Makefile/CMake。
  2. 看《视觉SLAM十四讲》前 6 章,重点掌握三维空间刚体运动、旋转矩阵、四元数、李群李代数、相机模型和非线性优化。
  3. 看第 7 章,实现一个基于特征点的视觉里程计,跑通 2D-2D 对极几何和 3D-2D PnP。
  4. 看第 8 章,理解光流法和直接法的区别,了解为什么直接法在纹理缺乏场景更有效。
  5. 看第 9-10 章,理解前端设计、后端 BA 和图优化。
  6. 看第 11-13 章,理解回环检测和建图,了解词袋模型、八叉树地图和点云拼接。
  7. 跑 ORB-SLAM3 作为综合实践。

6.2 代码阅读顺序

直接看 ORB-SLAM3 源码容易迷失。我建议按“线程”来读:

  • 跟踪线程(Tracking):System.ccTracking.cc,理解每帧图像如何变成相机位姿。
  • 局部建图线程(LocalMapping):LocalMapping.cc,理解关键帧筛选、地图点创建和局部 BA。
  • 回环检测线程(LoopClosing):LoopClosing.cc,理解回环候选帧搜索、Sim3 求解和全局优化。
  • 地图管理(Map / MapPoint / KeyFrame):理解数据结构如何组织。

6.3 工程落地建议

在真正的机器人或无人驾驶项目中使用 SLAM,不能只停留在跑通 Demo,还要注意以下几点:

传感器标定与同步
视觉 SLAM 的精度上限由传感器决定,而不是算法。相机内参、畸变、IMU 外参、相机到机器人基座的外参、时间戳同步,都要做到尽量精确。很多“算法效果差”的问题,最终定位到是标定错误。

坐标系约定
团队里必须统一坐标系约定。不同 SLAM 系统输出的是“相机系到世界系”还是“世界系到相机系”, ROS 中的tf树如何连接,都要有清晰文档。否则算法联调时会出现方向翻转的问题。

参数调优与鲁棒性
ORB-SLAM3 提供了大量 yaml 参数。灰度阈值、特征点数量、金字塔缩放因子、RANSAC 迭代次数、局部 BA 窗口大小等,都需要根据应用场景反复实验。不要直接拿着默认参数去跑真实场景,不同的光照、运动速度和传感器分辨率会带来显著差异。

失败检测与恢复
工程系统必须有“跟踪丢失”检测机制。比如长时间特征匹配数量过少、重投影误差突然增大,都要触发重定位或重新初始化。ORB-SLAM3 有重定位机制,但你需要在自己的项目里定义什么时候报告失败,什么时候切换传感器模式。

计算资源规划
SLAM 算法通常要跑在嵌入式设备或者车辆计算平台。需要提前评估 CPU 占用、内存占用和延迟。ORB-SLAM3 在普通 x86 上可以做到实时,但在资源受限的机器人平台,需要裁剪关键帧数量、降低图像分辨率或者使用稀疏特征提取策略。

6.4 从视觉SLAM到具身智能

具身智能需要的不只是定位和建图,还包括语义理解、任务规划、运动控制。但视觉 SLAM 提供的“环境几何结构”和“自身位姿”,是所有上层能力的地基。一个常见的学习路径是:

  1. 视觉 SLAM:解决“我在哪里、周围长什么样”。
  2. 机器人导航:在 SLAM 地图上做路径规划与避障,学习 ROS 2 Nav2 框架。
  3. 语义感知:用目标检测、语义分割给地图添加语义标签,形成语义地图。
  4. 机械臂操作:结合视觉伺服和目标抓取,完成“看到-决策-执行”闭环。

因此,不要觉得 SLAM 只是传统机器人方向。它实际上是通向具身智能、无人驾驶的关键前置技能之一。

7. 总结与学习建议

视觉 SLAM 的学习可以分为“数学基础-模块实现-完整系统-工程优化”四个阶段。本文从 SLAM 的核心概念出发,介绍了视觉 SLAM 的整体框架、数学基础、ORB 特征匹配原理、非线性优化方法,然后带你在 Ubuntu 上从零配置依赖、编译并运行 ORB-SLAM3,最后总结了常见的环境问题和工程落地建议。

如果你的目标是快速上手,建议优先完成以下三件事:

  1. 把《视觉SLAM十四讲》前 7 章的公式推导和代码跑完,不追求全部背下来,但要知道每个模块解决什么问题。
  2. 运行至少一个数据集(TUM 或 EuRoC),把 ORB-SLAM3 跑通,并保存轨迹与真实轨迹比较,算出 ATE 或 RPE 误差。
  3. 用 ROS 2 和真实摄像头采集一段自己的数据,尝试用 ORB-SLAM3 实时运行,感受真实场景和数据集场景的差异。

如果你在学习过程中卡住了,先不要急着换资料,更不要直接跳到深度学习和多传感器融合方向。多花点时间把坐标变换和优化理论弄扎实,这些知识会在后面帮助你解决几乎所有看似“玄学”的问题。视觉 SLAM 的门槛不低,但只要你按步骤走,每一步都能看到可视化结果,成就感会推着你继续往前走。

如果你觉得本文对你有帮助,可以收藏备用。后续我还会写一些关于 ORB-SLAM3 代码导读、视觉惯性里程计和机器人导航地图构建的内容,敬请关注。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 14:12:18

2026国产AI工具选型:场景化匹配已成刚需,榜单排名不再可靠

1. 先把格局看清&#xff1a;2026年的国产AI工具&#xff0c;已经分层了经常有人拿着一张截图跑来问我&#xff1a;“这个AI工具排行榜里排名第一的到底好不好用&#xff1f;”我的回答通常是一句反问&#xff1a;你要用它干什么&#xff1f;2026年聊AI工具选型&#xff0c;最怕…

作者头像 李华
网站建设 2026/9/8 14:11:54

AI赋能家居门店获客:从内容生产到私域承接的全链路实操指南

1. 为什么家居门店的获客问题&#xff0c;AI正好能搭把手先讲一个挺扎心的场景。我过去两年接触过不少做家具、建材、全屋定制的门店老板&#xff0c;聊起获客&#xff0c;大家普遍的状态是&#xff1a;以前靠自然进店、老带新、装修公司介绍&#xff0c;日子能过&#xff1b;现…

作者头像 李华
网站建设 2026/9/8 14:09:17

OpenCV集成zxing-cpp实现二维码识别:从配置到实战踩坑全记录

简介&#xff1a;面向C开发者的ZXing二维码识别移植版&#xff0c;将开源解码库与OpenCV图像处理无缝衔接&#xff0c;支持QR码、Data Matrix、Aztec、UPC等多种格式&#xff0c;可直接传入cv::Mat进行识别&#xff0c;适用于无人机导航、工业自动化、物联网设备等需要本地高性…

作者头像 李华
网站建设 2026/9/8 14:09:08

RK3588视觉算法渐进式集成实战:从刷机、NPU推理到外设联动

做边缘端视觉项目这些年&#xff0c;RK3588一直是我最常用的主力平台。6 TOPS的NPU算力加上4颗A76大核&#xff0c;跑视觉算法刚好够用&#xff0c;周边的MIPI CSI、PCIe、USB3.0这些接口也齐全&#xff0c;比同价位的其他方案省了不少外围功夫。这篇文章想复盘的是&#xff0c…

作者头像 李华
网站建设 2026/9/8 14:08:28

DAS直连存储性能优化:MBTCP多路径TCP传输方案解析与实践

简介&#xff1a;这是一款由施耐德电气推出的通讯驱动程序包&#xff0c;面向工业自动化项目中的控制器与人机界面联调场景&#xff0c;专门解决67160系列可编程控制器与InTouch上位机软件之间的网络通讯问题。适用于电气工程师、系统集成商以及需要维护老旧产线的技术人员&…

作者头像 李华
网站建设 2026/9/8 14:08:22

E104-BT02 BLE透传模块详解:从快速上手到驱动与电路设计

先说个真实感受&#xff1a;我第一次把E104-BT02这块BLE蓝牙通信模块焊到转接板上时&#xff0c;确实有种“模块这么小&#xff0c;上手指日可待”的错觉。可真跑起来才发现&#xff0c;麻烦根本不在这颗模块本身&#xff0c;而在BLE协议栈、广播参数、GATT服务和MTU这些看不见…

作者头像 李华