跳转至

Depth Estimation and 3D Reconstruction⚓︎

2237 个字 预计阅读时间 11 分钟

Depth estimation⚓︎

Introduction⚓︎

计算深度图(depth map):

对于很多 CV 应用,深度(depth) 是一个关键线索,涉及到以下领域:

深度感知(depth sensing) 分为:

  • 主动深度感知(active depth sensing):通过扰动被感知环境来感受深度,有以下应用:

    • LiDAR(光探测与测距 (Light Detection And Ranging)(比如 Velodyne

      • 基于飞行时间 (time of flight, ToF)
      • 开销大
      • 能获取极其精确的深度信息
      • 高分辨率
      • 360° 视角

    • 结构化光 (structured light)(比如 Kinect 1

    • 主动立体 (active stereo)(比如 Intel RealSense
  • 被动深度感知(passive depth sensing)

Stereo Matching⚓︎

Stereo Vision⚓︎

  • 一个物体点将投影到图像中的某个点
  • 该图像点对应于世界中的某条射线
  • 两条射线在单个点上相交,因此若要在三维空间中定位点,就需要两只眼睛

假设给定相对的相机位姿,计算图像中每个点的深度的方式有:

  • 找到 2D-2D 点对点的对应关系
  • 三角剖分 (triangulate)

立体匹配(stereo matching) 的目标是高效匹配所有的像素。

极线几何 (epipolar geometry)

其实上节课介绍过了,这里只是简单回顾一下。

  • 基线 (baseline):连接两个相机中心的线(\(OO'\)
  • 极点 (epipolar point):像平面和基线的交点(\(e, e'\)
  • 极面 (epipolar plane):包含 \((XOO')\) 的平面
  • 极线 (epipolar line):极面和像平面的交线(\(l, l'\)

给定 \(X_L\),它在另一个图像 \(X_R\) 上的匹配必定落在极线(下图的红线)上。

Basic Algorithm⚓︎

基本的立体匹配算法为:对于第一幅图像的每个像素,

  • 寻找在右侧图像上对应的极线
  • 沿着极线搜索,找到最佳匹配

在最简单的情况下,极线是水平的扫描线,此时

  • 相机的像平面相互平行,并且也和基线平行
  • 两台相机中心的高度也相等
  • 焦距也是相等的
  • 因而极线落在像之间的水平扫描线上

Depth from Disparity⚓︎

由纯水平平移相机捕获的两幅图像(校正立体对

\(x_2 - x_1\) = \((x_1, y_1)\) 的像素视差(disparity)

原理图如下:

\[ disparity = x - x' = \dfrac{B \cdot f}{z} \]

也就是说视差与深度成反比

注意,\(x\) \(x'\) 分别是相对于图像中心的图像坐标。

Stereo Image Rectification⚓︎

假如极线不是扫描线,那么需要将图像平面重新投影到一个与相机中心之间的线平行的公共平面上;这一操作需要两个单应性(3x3)变换,每个变换对应一个输入图像重投影操作。

例子

Stereo Matching Algorithms⚓︎

立体匹配算法的思路是:在共轭 (conjugate) 极线中匹配像素(假设亮度恒定。这是一个具有挑战性的问题。目前已提出了数百种方法;这个链接给出了一项相关调查和评估:http://www.vision.middlebury.edu/stereo/

基础的立体匹配算法就是找到能够最小化差异的最佳匹配。

一些比较流行的匹配分数:

  • SSD(平方差之和 (sum of squared differences)\(\sum\limits_{x,y}|W_1(x,y)-W_2(x,y)|^2=\)
  • SAD(绝对差之和 (sum of absolute differences)\(\sum\limits_{x, y}|W_1(x,y)-W_2(x,y)|\)
  • ZNCC(零均值归一化互相关 (zero-mean normalized cross correlation)\(\dfrac{\sum_{x,y}(W_1(x,y)-\overline{W_1})(W_2(x,y)-\overline{W_2})}{\sigma_{W_1}\sigma_{W_2}}\),其中
    • \(\overline{W_i}=\frac{1}{n}\sum_{x,y}W_i\quad\sigma_{W_i}=\sqrt{\frac{1}{n}\sum_{x,y}(W_i-\overline{W_i})^2}\)
    • 优点:TBD

Window Size⚓︎

窗口搜索的结果:

存在更好的方法(基于图割的方法

Stereo as Energy Minimization⚓︎

\[ E(d)=E_d(d)+\lambda E_s(d) \]
  • 变量:每个像素的视差 \(d\)
  • \(E_d(d)\)匹配(希望每个像素能在另一张图像上找到良好匹配)成本

    • 比如 SSD, SAD, ZNCC
    \[ E_d(d)=\sum_{(x,y)\in I}C(x,y,d(x,y)) \]
  • \(E_s(d)\)平滑度(smoothness)(相邻像素(通常)要移动相同的量)成本

    \[ E_s(d)=\sum_{(p,q)\in\mathcal{E}}V(d_p,d_q) \]
    • \(\mathcal{E}\):邻近像素的集合

    • \(V\) 的选择:
      • L1 距离:\(V(d_p,d_q)=|d_p-d_q|\)
      • Potts 模型:\(V(d_p,d_q)=\begin{cases}0&\mathrm{if~}d_p=d_q\\1&\mathrm{if~}d_p\neq d_q&\end{cases}\)

Stereo Reconstruction Pipeline⚓︎

步骤:

  1. 校准相机

    • 选择立体基线

      • 太大会导致较大的深度误差
      • 太小则让搜素问题变得困难

  2. 校正图像

  3. 计算视差
  4. 估计深度

误差的来源包括:

  • 相机校准误差
  • 图像解析度低
  • 遮挡
  • 亮度不恒定(镜面反射)
  • 无纹理区域

Active Stereo with Structured Light⚓︎

“结构化”的红外光模式("structured" infared light pattern) 投射到物体上

  • 简化了(点对点的)对应问题
  • 是一些设备上(如 Kinect iPhone X(使用红外 (IR))的主动深度传感器 (active depth sensors) 的基础
例子

Multi-View Stereo⚓︎

例子

多视角立体(multi-view stereo) 的优势:

  • 可以使用多个邻居来匹配窗口,提供更强的约束
  • 如果有很多潜在邻居,可以选择每个参考图像的最佳邻居子集进行匹配
  • 可以为每个参考帧重建深度图,并合并成一个完整的 3D 模型

基本思路:

  • 正确的深度能给出一致的投影

  • 错误的深度给出不一致的投影

  • 计算参考图像中每个点的每个深度值的误差,寻找给出最小误差的深度值

PatchMatch⚓︎

块匹配(PatchMatch) 一个用于解决对应问题的有效算法。假设:

  • 大量随机采样将产生一些好的猜测
  • 邻居具有相似的偏移

步骤:

  1. 随机初始化(random intialization):每个像素都被赋予一个随机的块偏移量,作为初始化
  2. 传播(propagation):每个像素检查邻近块的偏移量是否提供了更好的匹配块;如果是,则采用邻居的块偏移量
  3. 局部搜索(local search):
    • 每个像素在当前偏移量周围的同心半径内搜索更好的块偏移量
    • 搜索半径从图像大小开始,每次减半,直到达到 1
  4. 回到步骤 2,直至收敛

MVS(多视角立体)中,将上述算法中的块偏移量替换为深度值

3D Reconstruction⚓︎

三维重构(3D reconstruction) 的管线:

  1. 为每张图像计算深度图
  2. 将深度图融合成三维表面
  3. 纹理映射

3D Representation⚓︎

有多种三维表示方式,如下所示:

  • 点云(point cloud):一组三维点

  • (volume)

    • 占用体(occupancy volume):一个包含每个体素 (voxel) 的三维体

      \[ V_{ijk} = \begin{cases}1 & \text{if occupied} \\ 0 & \text{if empty}\end{cases} \]

    • SDF

      • 符号距离函数(signed distance function, SDF):点到形状边界的距离

        • 距离由度量定义,通常是欧几里得距离
      • 截断符号距离函数(truncated signed distance function, TSDF):将 SDF 值限制在 [-1, 1]

  • 网格(mesh):有顶点和边的多边形网格

    • 通常是三角形

3D Surface Reconstruction⚓︎

将深度图融合成完整的三维网格的方法:

  1. 深度图 -> 占位体

    • 泊松重构 (Poisson reconstruction)
  2. 占位体 -> 网格

    • 行进立方体 (marching cube)

之所以有构建占位体这一中间步骤,是因为:

  • 便于转换为网格
  • 适合去噪

Poisson Reconstruction⚓︎

  • 将深度图转换为点云

- 计算每个点的法向量 - 通过指示(占用)函数(indicator(occupancy) function) 表示表面

![](images/lec8/37.png){ align=right width=15% }

$$
\chi_M(p)=\begin{cases}1&\mathrm{if~}p\in M\\0&\mathrm{if~}p\notin M&\end{cases}
$$

构建指示函数的关键——梯度关系 (gradient relationship)

  • 点的法线与指示函数的梯度之间存在关系
  • 向量场(vector field) \(\overrightarrow{V}\) 表示有向点
  • 通过对以下式子最小化,来寻找梯度最佳近似 \(\overrightarrow{V}\) 的函数 \(\chi\)

    \[ \min\limits_{\chi} \|\nabla \chi - \overrightarrow{V}\| \]
  • 用泊松方程求解

Marching Cubes⚓︎

在了解行进立方体之前,为便于理解,先来看二维的行进正方形(marching squares)。对于每个有符号变化的网格单元:

  • 在每个网格边缘上创建一个具有符号变化的顶点
  • 通过线条连接顶点
    • 这些线不应该相交
    • 使用预先计算好的查找表(look-up table)
  • 顶点的位置可以通过 SDF(符号距离函数)值的线性插值来确定

回到三维的情况——对于每个有符号变化的网格单元:

  • 在每个网格边缘创建一个具有符号变化的顶点
  • 通过三角形连接顶点

    • 三角形不应该相交
    • 显然比二维情况复杂得多

  • 查找表

    • 2 8 = 256 个符号配置
    • 对于每个符号配置,它存储了构成三角形的顶点所对应的网格边的索引
    • 总共有 15 个配置(考虑对称)

示例:表面提取结果

Texture Mapping⚓︎

CG 笔记「Texture Mapping」一节。

评论区

如果大家有什么问题或想法,欢迎在下方留言~