跳转至

双目与结构光

概述

双目视觉和结构光是两种主要的深度感知技术。双目视觉模仿人类双眼通过视差计算深度,结构光通过投射已知图案来测量形变获取深度。本节深入介绍其数学原理、工程实现和性能对比。

双目视觉原理

基本几何

双目相机由两个水平排列的相机组成,通过三角测量计算深度:

左相机 O_L          右相机 O_R
  *-------- B --------*
  |\                 /|
  | \               / |
  |  \             /  |
  |   \    P(X,Y,Z)  |
  |    \   *     /    |
  |     \ / \   /     |
  |------*---*--------| 图像平面
      x_L    x_R

视差与深度

视差(Disparity)是同一点在左右图像中的水平位置差:

\[ d = x_L - x_R \]

由相似三角形关系:

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

因此深度为:

\[ \boxed{Z = \frac{fB}{d}} \]

其中:

  • \(Z\):深度(米)
  • \(f\):焦距(像素)
  • \(B\):基线长度(米)
  • \(d\):视差(像素)

深度分辨率

深度的最小分辨率(相邻视差值对应的深度差):

\[ \Delta Z = \frac{Z^2}{fB} \cdot \Delta d \]

\(\Delta d = 1\)(整像素视差)时,深度分辨率随距离平方增长。

深度分辨率计算

参数:\(f=400\text{px}\)\(B=0.12\text{m}\)(ZED 2i)

  • 在1m处:\(\Delta Z = \frac{1^2}{400 \times 0.12} = 0.021\text{m} = 2.1\text{cm}\)
  • 在5m处:\(\Delta Z = \frac{25}{48} = 0.52\text{m} = 52\text{cm}\)

亚像素视差(0.1px精度)可将分辨率提高10倍。

深度误差分析

\[ \sigma_Z = \frac{Z^2}{fB} \cdot \sigma_d \]

要提高深度精度的三条路径:

  1. 增大基线 \(B\):但近距离盲区也增大(\(Z_{\min} \approx \frac{fB}{d_{\max}}\)
  2. 增大焦距 \(f\):但FOV变小
  3. 减小视差误差 \(\sigma_d\):更好的匹配算法、亚像素插值

对极几何

对极约束

对于已标定的双目系统,左图中的一点对应到右图中时,必然落在对极线(Epipolar Line)上:

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

其中 \(\mathbf{F}\)基础矩阵(Fundamental Matrix)

对于校正后的双目(rectified stereo),对极线变为水平线,搜索范围从2D降低到1D:

左图:                        右图:
┌──────────────────┐        ┌──────────────────┐
│     *P_L         │        │         *P_R     │
│────────对极线─────│  →     │────────对极线─────│
│                  │        │                  │
└──────────────────┘        └──────────────────┘
P_L和P_R在同一行上(y坐标相同)

校正(Rectification)

双目校正使两个相机的图像平面共面,且行对齐:

import cv2
import numpy as np

# 已知标定参数
K_left = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]])
K_right = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]])
D_left = np.array([k1, k2, p1, p2, k3])
D_right = np.array([k1, k2, p1, p2, k3])
R = rotation_matrix_3x3  # 右相机相对左相机的旋转
T = translation_vector    # 右相机相对左相机的平移

# 立体校正
R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(
    K_left, D_left, K_right, D_right,
    image_size, R, T,
    flags=cv2.CALIB_ZERO_DISPARITY,
    alpha=0
)

# 生成映射表
map1_left, map2_left = cv2.initUndistortRectifyMap(
    K_left, D_left, R1, P1, image_size, cv2.CV_16SC2
)
map1_right, map2_right = cv2.initUndistortRectifyMap(
    K_right, D_right, R2, P2, image_size, cv2.CV_16SC2
)

# 应用校正
left_rectified = cv2.remap(left_img, map1_left, map2_left, cv2.INTER_LINEAR)
right_rectified = cv2.remap(right_img, map1_right, map2_right, cv2.INTER_LINEAR)

视差匹配算法

块匹配(Block Matching)

# OpenCV Semi-Global Block Matching
stereo = cv2.StereoSGBM_create(
    minDisparity=0,
    numDisparities=128,     # 必须是16的倍数
    blockSize=5,             # 匹配窗口大小
    P1=8 * 3 * 5**2,        # 视差平滑参数1
    P2=32 * 3 * 5**2,       # 视差平滑参数2
    disp12MaxDiff=1,         # 左右一致性检查
    uniquenessRatio=10,      # 唯一性约束
    speckleWindowSize=100,   # 去斑点
    speckleRange=32
)

# 计算视差图
disparity = stereo.compute(left_rectified, right_rectified)
disparity_float = disparity.astype(np.float32) / 16.0  # 去除定点小数

# 视差转深度
depth = (focal_length * baseline) / (disparity_float + 1e-6)
depth[disparity_float <= 0] = 0  # 无效视差

匹配算法对比

算法 精度 速度 特点
BM (Block Matching) 最快(~100fps) 简单局部匹配
SGBM (Semi-Global) 中(~30fps) 多方向代价聚合
ELAS 中高 中(~20fps) 自适应支撑点
AANet (深度学习) 中(~20fps on GPU) 端到端学习
RAFT-Stereo (深度学习) 最高 慢(~5fps on GPU) 迭代光流

深度学习双目匹配

import torch
from raft_stereo import RAFTStereo

# 加载预训练模型
model = RAFTStereo(args)
model.load_state_dict(torch.load('raft-stereo.pth'))
model.eval()

with torch.no_grad():
    # 输入左右图像
    left = torch.from_numpy(left_img).permute(2,0,1).float().unsqueeze(0).cuda()
    right = torch.from_numpy(right_img).permute(2,0,1).float().unsqueeze(0).cuda()

    # 预测视差
    _, disparity = model(left, right, iters=20)
    disparity = disparity.squeeze().cpu().numpy()

结构光

原理

结构光通过向场景投射已知的光图案,通过观察图案的形变来计算深度:

投射器          相机
  *               *
  |\             /|
  | \  已知图案 / |
  |  \  ↓↓↓   /  |
  |   \ |||  /   |
  |    \||| /    |
  ======物体======
  图案形变反映表面形状

散斑图案(Speckle Pattern)

RealSense D435i使用红外散斑投射:

  • 投射随机红外点阵
  • 左右IR相机观察散斑图案
  • 图案的偏移量 = 视差

优势:在无纹理表面(白墙、桌面)也能获得深度

劣势:室外阳光会淹没红外散斑

编码结构光(Coded Pattern)

使用空间或时间编码的图案:

编码方式 图案数量 速度 精度 代表
二值编码 多帧 工业三维扫描
格雷码 \(\log_2 N\) 结构光扫描仪
相移法 3-4帧 最高 精密测量
单帧编码 1帧 Azure Kinect

结构光深度计算

类似双目视觉,但一个"相机"替换为投射器:

\[ Z = \frac{fB}{d_{\text{pattern}}} \]

其中 \(d_{\text{pattern}}\) 是图案在相机图像中的偏移量。

飞行时间(ToF)

原理

ToF相机发射调制光,测量光往返时间:

\[ d = \frac{c \cdot \Delta t}{2} \]

其中 \(c\) 是光速(\(3 \times 10^8\) m/s),\(\Delta t\) 是光往返时间。

连续波ToF(iToF)

实际中使用调制光的相位差测距:

发射信号:\(s(t) = A \cos(2\pi f_m t)\)

接收信号:\(r(t) = A' \cos(2\pi f_m t + \phi)\)

深度:

\[ d = \frac{c \cdot \phi}{4\pi f_m} \]

最大无歧义距离:

\[ d_{\max} = \frac{c}{2 f_m} \]

最大测量距离

调制频率 \(f_m = 20\text{MHz}\)

\[d_{\max} = \frac{3 \times 10^8}{2 \times 20 \times 10^6} = 7.5\text{m}\]

直接ToF(dToF)

使用SPAD(单光子雪崩二极管)直接测量光子飞行时间:

  • 精度更高(mm级)
  • 抗环境光更强
  • 苹果LiDAR Scanner (iPad Pro) 使用dToF
  • 成本较高

三种技术对比

特性 被动双目 主动双目 结构光 ToF
室外性能
无纹理表面
深度范围 0.5-20m 0.3-10m 0.2-4m 0.1-8m
精度@1m 3-5mm 1-2mm <1mm 1-3mm
分辨率 低(VGA)
帧率 高(100fps) 高(90fps) 低(30fps) 高(60fps)
计算量 最小
多设备干扰 可能 严重 可能
功耗
成本

实际应用选择

场景匹配

应用场景 推荐技术 理由
室内导航 主动双目 无纹理墙面需要投射
室外导航 被动双目 + LiDAR 阳光下IR不可靠
机械臂抓取 结构光/主动双目 近距离高精度
人体跟踪 ToF/主动双目 速度快、人体形状简单
3D扫描 结构光(多帧) 最高精度
高速场景 被动双目/ToF 帧率高、低延迟

点云融合

import open3d as o3d

# 从深度图生成点云
intrinsic = o3d.camera.PinholeCameraIntrinsic(
    640, 480, fx, fy, cx, cy
)

# 多帧点云融合
volume = o3d.pipelines.integration.ScalableTSDFVolume(
    voxel_length=0.005,  # 5mm体素
    sdf_trunc=0.02,
    color_type=o3d.pipelines.integration.TSDFVolumeColorType.RGB8
)

for depth, color, pose in frames:
    rgbd = o3d.geometry.RGBDImage.create_from_color_and_depth(
        o3d.geometry.Image(color),
        o3d.geometry.Image(depth),
        depth_trunc=3.0
    )
    volume.integrate(rgbd, intrinsic, np.linalg.inv(pose))

# 提取网格
mesh = volume.extract_triangle_mesh()
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh])

小结

  1. 双目深度公式 \(Z = fB/d\) 是立体视觉的核心
  2. 深度误差与距离平方成正比,基线和焦距决定精度上限
  3. 对极校正将2D搜索降为1D,是立体匹配的前提
  4. 结构光在无纹理表面优势明显,但室外受限
  5. ToF不依赖纹理和环境光,但分辨率较低
  6. 实际系统通常组合使用多种深度传感技术

参考资料

  • Hartley, R., & Zisserman, A. Multiple View Geometry in Computer Vision
  • Scharstein, D., & Szeliski, R. "A Taxonomy and Evaluation of Dense Two-Frame Stereo Correspondence Algorithms"
  • Intel RealSense White Paper: Active IR Stereo
  • Geng, J. "Structured-light 3D surface imaging: a tutorial"

评论 #