跳转至

空间几何与三维视觉

计算机视觉不仅要理解图像中"是什么"(语义),更要理解"在哪里"(几何)。空间几何与三维视觉研究如何从二维图像中恢复三维世界的结构信息。


一、从 3D 到 2D:相机成像模型

为什么需要理解相机模型?

一张照片是三维世界在二维平面上的投影。要从图像恢复 3D 信息,首先要理解这个投影过程的数学描述。

针孔相机模型

最基本的相机模型,假设光线通过一个无限小的孔(针孔)投射到成像平面上。

graph LR
    A[3D 世界点<br/>X,Y,Z] -->|投影| B[2D 图像点<br/>u,v]
    B --> C[像素坐标]

一个三维世界点 \(\mathbf{P} = (X, Y, Z)^T\) 投影到图像平面上的像素坐标 \((u, v)\) 的过程:

\[ \lambda \begin{pmatrix} u \\ v \\ 1 \end{pmatrix} = \underbrace{\begin{pmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{pmatrix}}_{\mathbf{K}:\text{内参矩阵}} \underbrace{\begin{pmatrix} \mathbf{R} & \mathbf{t} \end{pmatrix}}_{\text{外参}} \begin{pmatrix} X \\ Y \\ Z \\ 1 \end{pmatrix} \]

简写为:

\[ \lambda \mathbf{p} = \mathbf{K} [\mathbf{R} | \mathbf{t}] \mathbf{P}_w \]

内参与外参

描述相机自身的光学特性,与相机在世界中的位置无关:

参数 含义
\(f_x, f_y\) 焦距(以像素为单位)
\(c_x, c_y\) 主点坐标(图像中心偏移)

内参矩阵 \(\mathbf{K}\) 确定后(通过标定),同一台相机拍任何场景都不变。

描述相机在世界坐标系中的位姿:

参数 含义
\(\mathbf{R} \in SO(3)\) 旋转矩阵(\(3 \times 3\),正交矩阵)
\(\mathbf{t} \in \mathbb{R}^3\) 平移向量

外参描述了从世界坐标系到相机坐标系的变换。

镜头畸变

实际镜头并非理想的针孔,会产生畸变:

  • 径向畸变:图像边缘的直线变弯(桶形畸变 / 枕形畸变)
\[ x' = x(1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \]
  • 切向畸变:镜头与成像平面不完全平行导致的畸变
\[ x' = x + 2p_1 xy + p_2(r^2 + 2x^2) \]

其中 \(r^2 = x^2 + y^2\)

实际应用

相机标定时通常估计 5 个畸变参数 \((k_1, k_2, p_1, p_2, k_3)\)。OpenCV 的 calibrateCamera 函数可以自动完成标定。


二、相机标定

什么是相机标定?

确定相机的内参矩阵 \(\mathbf{K}\) 和畸变系数的过程。

张正友标定法

最广泛使用的标定方法,只需要一个棋盘格:

  1. 从不同角度拍摄棋盘格图像(至少 3 张,建议 10~20 张)
  2. 检测每张图中棋盘格角点的像素坐标
  3. 利用棋盘格的已知物理尺寸,通过单应性矩阵建立约束
  4. 求解内参和畸变参数

单应性矩阵(Homography)

当 3D 点都在同一平面上时(如棋盘格),投影关系简化为:

\[ \lambda \begin{pmatrix} u \\ v \\ 1 \end{pmatrix} = \mathbf{H} \begin{pmatrix} X \\ Y \\ 1 \end{pmatrix}, \quad \mathbf{H} = \mathbf{K} [\mathbf{r}_1 \; \mathbf{r}_2 \; \mathbf{t}] \]

\(\mathbf{H}\)\(3 \times 3\) 的单应性矩阵,可以通过至少 4 对对应点求解。


三、立体视觉与深度估计

人眼的深度感知

人类用双眼感知深度——左右眼看到的图像略有差异(视差),大脑据此推断距离。立体视觉就是模拟这个过程。

双目立体视觉

对极几何

两个相机观察同一场景时,存在几何约束关系:

graph TB
    P[3D 点 P] --> L[左相机像点 p_L]
    P --> R[右相机像点 p_R]
    L --- E1[极点 e_L]
    R --- E2[极点 e_R]

对极约束

\[ \mathbf{p}_R^T \mathbf{F} \mathbf{p}_L = 0 \]

其中:

  • \(\mathbf{F}\)基础矩阵(Fundamental Matrix),\(3 \times 3\),秩为 2
  • \(\mathbf{E} = \mathbf{K}_R^T \mathbf{F} \mathbf{K}_L\)本质矩阵(Essential Matrix),当内参已知时使用

对极约束的意义

知道左图中一个点 \(\mathbf{p}_L\),它在右图中的对应点 \(\mathbf{p}_R\) 一定在极线上。这将匹配搜索从 2D 区域缩减到 1D 直线,极大减少计算量。

视差与深度

当两个相机水平排列且光轴平行(标准立体配置)时:

\[ Z = \frac{f \cdot B}{d} \]

其中:

  • \(Z\):深度(物体到相机的距离)
  • \(f\):焦距
  • \(B\):基线长度(两相机之间的距离)
  • \(d = u_L - u_R\)视差(同一点在左右图中的水平坐标差)

直观理解

伸出一根手指,交替闭左右眼,手指会"跳动"。近的物体跳动更大(视差大),远的物体跳动小(视差小)。视差和深度成反比

立体匹配算法

计算视差的核心问题是立体匹配——找到左图每个像素在右图中的对应点。

方法类别 代表算法 特点
局部方法 SAD、SSD、NCC 计算快,但对遮挡和弱纹理区域效果差
全局方法 Graph Cut、Belief Propagation 精度高,计算量大
半全局方法 SGM(Semi-Global Matching) 平衡精度和速度,工业界广泛使用
深度学习 DispNet、GC-Net、AANet 数据驱动,效果最好

单目深度估计

仅用一张图像估计深度,是一个不适定问题(ill-posed)——同一张图像可能对应无穷多种 3D 场景。

深度学习通过从大量数据中学习先验知识(如近大远小、纹理梯度等)来解决这个问题。

代表方法

方法 年份 方式 特点
Eigen et al. 2014 监督学习 首次用 CNN 做单目深度估计
Monodepth 2017 自监督 用左右图像重建损失训练,无需深度标注
MiDaS 2020 多数据集混合 泛化能力强,相对深度估计
DPT 2021 ViT backbone Transformer 用于密集预测
Depth Anything 2024 大规模自监督 最强泛化的单目深度模型

单目 vs 双目

  • 双目:物理约束明确,深度精确,但需要两个相机且需要标定
  • 单目:只需一个相机,但深度是推测出来的,绝对精度不如双目
  • 实际应用中两者往往结合使用

四、三维重建

从图像中恢复完整的三维模型是计算机视觉的终极目标之一。

Structure from Motion(SfM)

从多张无序图像中同时恢复相机位姿和 3D 点云

graph LR
    A[多张图像] --> B[特征提取 + 匹配]
    B --> C[初始化两帧重建]
    C --> D[逐步加入新图像]
    D --> E[Bundle Adjustment]
    E --> F[相机位姿 + 稀疏点云]

核心步骤

  1. 特征提取与匹配:用 SIFT/SuperPoint 提取关键点,用特征描述子匹配对应点
  2. 两帧初始化:从两张图像估计本质矩阵 \(\mathbf{E}\),分解得到相对位姿 \([\mathbf{R} | \mathbf{t}]\)
  3. 三角化:已知两个相机位姿和对应点,通过三角化恢复 3D 点
\[ \mathbf{P} = \text{triangulate}(\mathbf{p}_1, \mathbf{K}_1[\mathbf{R}_1|\mathbf{t}_1], \mathbf{p}_2, \mathbf{K}_2[\mathbf{R}_2|\mathbf{t}_2]) \]
  1. 增量式重建:逐步加入新图像,通过 PnP 算法估计新相机位姿,再三角化新的 3D 点
  2. Bundle Adjustment(BA):联合优化所有相机参数和 3D 点,最小化重投影误差
\[ \min_{\{\mathbf{R}_i, \mathbf{t}_i\}, \{\mathbf{P}_j\}} \sum_{i,j} \| \mathbf{p}_{ij} - \pi(\mathbf{K}_i[\mathbf{R}_i | \mathbf{t}_i] \mathbf{P}_j) \|^2 \]

常用工具

  • COLMAP:最流行的开源 SfM + MVS 工具
  • OpenMVG:另一个优秀的开源 SfM 库
  • VisualSFM:带 GUI 的 SfM 工具

Multi-View Stereo(MVS)

SfM 输出的是稀疏点云,MVS 在此基础上重建稠密点云或表面。

方法 输出 代表
深度图融合 稠密点云 COLMAP MVS、PatchMatch
体素方法 体素网格 MVSNet(深度学习)
网格重建 三角网格 Poisson 重建

NeRF(Neural Radiance Fields,2020)

革命性方法:用神经网络隐式表示场景,实现逼真的新视角合成。

核心思想

用一个 MLP 网络 \(F_\Theta\)3D 坐标 + 观察方向 映射为 颜色 + 密度

\[ F_\Theta: (\mathbf{x}, \mathbf{d}) \rightarrow (\mathbf{c}, \sigma) \]
  • \(\mathbf{x} = (x, y, z)\):空间位置
  • \(\mathbf{d} = (\theta, \phi)\):观察方向
  • \(\mathbf{c} = (r, g, b)\):颜色
  • \(\sigma\):体积密度(该位置是否有物体)

体积渲染

沿每条光线积分得到像素颜色:

\[ C(\mathbf{r}) = \int_{t_n}^{t_f} T(t) \cdot \sigma(\mathbf{r}(t)) \cdot \mathbf{c}(\mathbf{r}(t), \mathbf{d}) \, dt \]

其中 \(T(t) = \exp\left(-\int_{t_n}^{t} \sigma(\mathbf{r}(s)) \, ds\right)\) 是透射率(光线到达 \(t\) 处还剩多少强度)。

离散化近似:

\[ \hat{C}(\mathbf{r}) = \sum_{i=1}^{N} T_i (1 - e^{-\sigma_i \delta_i}) \mathbf{c}_i, \quad T_i = \exp\left(-\sum_{j=1}^{i-1} \sigma_j \delta_j\right) \]

NeRF 的突破

  • 隐式表示:不需要显式的网格或点云,网络本身就是场景的表示
  • 渲染质量:生成的新视角图像非常逼真
  • 后续影响:催生了 3D Gaussian Splatting 等一系列工作

3D Gaussian Splatting(3DGS,2023)

NeRF 的渲染速度慢(需要逐像素射线积分)。3DGS 用显式的 3D 高斯椭球表示场景,实现实时渲染。

核心思想:场景由大量 3D 高斯分布表示,每个高斯有:

  • 位置 \(\boldsymbol{\mu} \in \mathbb{R}^3\)
  • 协方差矩阵 \(\boldsymbol{\Sigma} \in \mathbb{R}^{3 \times 3}\)(控制形状和朝向)
  • 不透明度 \(\alpha\)
  • 球谐函数系数(表示与视角相关的颜色)

渲染时将 3D 高斯投影(Splatting) 到 2D 图像平面,按深度排序后 alpha 混合:

\[ C = \sum_{i \in \mathcal{N}} c_i \alpha_i \prod_{j=1}^{i-1}(1 - \alpha_j) \]
对比 NeRF 3DGS
表示方式 隐式(MLP) 显式(3D 高斯)
渲染速度 慢(分钟级) 实时(100+ FPS)
训练速度 数小时 几十分钟
编辑能力 困难 容易(直接操作高斯)

五、点云处理

激光雷达(LiDAR)、深度相机等传感器直接输出 3D 点云 \(\{(x_i, y_i, z_i)\}_{i=1}^{N}\)

点云的特点

  • 无序性:点的排列顺序不影响语义(置换不变性)
  • 稀疏性:3D 空间中大部分位置是空的
  • 不规则性:点的分布不均匀,不像图像有规则的网格

PointNet(2017)

首个直接处理原始点云的深度学习模型

核心解决方案:

\[ f(\{x_1, \ldots, x_n\}) = g(\max(h(x_1), \ldots, h(x_n))) \]
  • \(h\):逐点特征提取(共享的 MLP)
  • \(\max\):对称函数(Max Pooling),保证置换不变性
  • \(g\):全局特征到输出的映射
graph LR
    A[N×3 点云] --> B[逐点 MLP]
    B --> C[N×1024 特征]
    C --> D[Max Pooling]
    D --> E[1024 维全局特征]
    E --> F[分类 / 分割]

PointNet++(2017)

改进:PointNet 中的 Max Pooling 丢失了局部结构信息。PointNet++ 引入层级结构

  1. 采样层:用最远点采样(FPS)选择代表点
  2. 分组层:在每个代表点周围用 ball query 找邻域
  3. PointNet 层:对每个局部邻域用 PointNet 提取特征
  4. 逐层抽象,类似 CNN 的层级特征提取

其他点云网络

网络 方式 特点
DGCNN 图卷积 动态构建 k-NN 图,边卷积提取局部特征
Point Transformer 自注意力 将 Transformer 应用于点云
MinkowskiNet 稀疏卷积 在稀疏体素上做 3D 卷积,高效处理大场景

六、视觉定位与 SLAM

视觉里程计(Visual Odometry)

通过连续图像帧估计相机的运动轨迹。

基本流程

  1. 提取当前帧和上一帧的特征点
  2. 匹配特征点对
  3. 估计帧间运动 \([\mathbf{R} | \mathbf{t}]\)(本质矩阵分解 / PnP)
  4. 累积运动得到轨迹

SLAM(Simultaneous Localization and Mapping)

同时定位与建图——相机在未知环境中运动,同时估计自身位姿和构建环境地图。

graph LR
    A[传感器输入] --> B[前端<br/>视觉里程计]
    B --> C[后端优化<br/>图优化 / BA]
    B --> D[回环检测<br/>识别重访场景]
    D --> C
    C --> E[位姿 + 地图]

经典 SLAM 系统

系统 类型 特点
ORB-SLAM3 特征点法 支持单目/双目/RGB-D,功能完整
LSD-SLAM 直接法 不提取特征点,直接用像素灰度优化
DSO 直接稀疏法 精确度高,但无回环检测
RTAB-Map RGB-D 实时外观词袋回环检测

特征点法 vs 直接法

  • 特征点法(ORB-SLAM):提取关键点 → 匹配 → 估计位姿。对光照变化鲁棒,但纹理稀疏区域效果差
  • 直接法(LSD-SLAM):直接最小化像素灰度误差。能利用更多信息,但对光照变化敏感

七、总结:几何与语义的融合

现代计算机视觉的趋势是几何信息和语义信息的深度融合

方向 代表方法 融合方式
语义 SLAM Kimera、SemanticFusion 在 SLAM 地图上叠加语义标签
3D 目标检测 PointPillars、CenterPoint 在点云上检测 3D 物体
3D 场景理解 ScanNet、3D-SIS 对室内场景做 3D 实例分割
场景重建 + 语义 Semantic NeRF、LERF 在 NeRF 中编码语义信息
自动驾驶感知 BEVFormer、UniAD 多传感器融合 + BEV 空间统一表示

最终目标

计算机视觉的终极目标是构建对环境的完整理解——不仅知道"这是一把椅子"(语义),还知道"它在房间的右前方 2 米处,高 0.8 米"(几何),甚至能推理"可以坐上去"(功能)。这正是机器人视觉、自动驾驶和具身智能的核心需求。