TSDF:截断符号距离函数

http://t.csdnimg.cn/ZjYQq

如何从零学习基于 TSDF 的三维重建? - Merce的回答 - 知乎
https://www.zhihu.com/question/486921125/answer/2406613708

1 概念定义

截断符号距离函数(Truncated Signed Distance Function,简称TSDF)是一种用于表示三维空间中物体表面的数据结构。它将空间划分为一个规则的体素网格,并为每个体素存储一个有符号距离值。这个距离值表示该体素中心到物体表面的距离。在物体表面内部的体素具有负值,而在物体表面外部的体素具有正值。为了减少存储和计算的开销,TSDF通常会对距离值进行截断,即只存储距离物体表面一定范围内的体素的距离值。

2 TSDF用途:

  1. 三维重建:TSDF常用于从多视角的深度图像重建三维模型。通过将来自不同视角的深度信息融合到一个统一的TSDF表示中,可以生成一个完整且连续的三维模型。
  2. 表面提取:TSDF可以用于提取物体表面的三维网格模型。通过在TSDF中找到距离值为零的体素,可以得到物体表面的一个近似表示。常用的算法有Marching Cubes算法。
  3. 机器人导航和避障:TSDF可以用于表示环境中的障碍物,从而帮助机器人进行导航和避障。

TSDF 算法的特点

(1) 计算简单,没有复杂的计算,但是需要大量的并行,需要比较大显存的显卡。

(2) TSDF 生成的网格的细节保持比较好,但是在边缘处以及前后景交界处,会出现较大的拖尾现象。因为在体素p像素坐标系投影时会有一定的误差.

(3) TSDF占据非常大的显存空间,适合诸如室内环境的小场景三维重建。

3 TSDF 实现方法

TSDF的实现通过包括以下几个步骤:

  1. 从深度图像计算点云:首先,将深度图像转换为点云表示,即每个像素对应一个三维空间中的点。
  2. 融合多视角的点云:将来自不同视角的点云融合到一个统一的坐标系中。这通常需要估计相机的位姿(位置和方向)。
  3. 构建TSDF:将融合后的点云数据映射到一个规则的体素网格中,并为每个体素计算有符号距离值。这通常需要对距离值进行截断,以减少存储和计算的开销。
  4. 表面提取(可选):如果需要提取物体表面的三维网格模型,可以使用如Marching Cubes等算法在TSDF中找到距离值为零的体素。

TSDF思路很朴素,用一个大的空间包围盒(volume)去包括进去待3D构建的场景,volume成多个voxel(小立体方块):

如何计算tsdf?假设已经从深度相机获得多帧RGBD图像以及相机的位姿T。

左图中灰色小方格表示体素voxel,蓝色三角性表示视场,绿色线为截面对应的线。

第一步:计算体素 xx世界坐标系下的坐标。记体素 xx在TSDF地图上得坐标为(vx,vy,vz)(v_{x}, v_{y}, v_{z}) 。则该体素在世界坐标系下的位置为:

Px,world=(x0+vxVoxel.x,y0+vyVoxel.y,z0+vzVoxel.z)P_{x,world}=(x_{0}+v_{x}\cdot Voxel.x, y_{0}+v_{y}\cdot Voxel.y, z_{0}+v_{z}\cdot Voxel.z);

第二步:计算体素在相机坐标系下的坐标。相机的旋转为 RR 平移为 TT ,则

Px,camera=RPx,world+TP_{x,camera} = RP_{x,world} + T

第三步:根据相机内参 KK 计算体素在相机坐标系下 zz 向深度camz(x)cam_{z}(x)

camz(x)=[KPx,camera]第三维cam_{z}(x) = [KP_{x,camera}]_{第三维}

第四步:重投影计算沿光心经过体素 xx 到达物体表面 pp 点对应的zz向深度:因为RGBD的信息已经知道,所以根据 Px,cameraP_{x,camera} 可以直接查到 p 的深度值 depth(pic(x));

第五步:得到sdf: sdfi(x)=depthi(pic(x))camz(x)sdf_{i}(x) = depth_{i}(pic(x)) − cam_{z}(x)

第六步:截断:tsdfi(x)=max(1,min(1,sdfi(x)t))tsdf_{i}(x) = max(−1, min(1,\frac{sdf_{i}(x)}{t})) 即将sdf截断在[-t, t]内,sdf超过这个范围的voxel点不用计算,直接得1或者-1。

TSDF就非常直观了,只需要将像素点中距离绝对值大于1的值截断到1即可。然后提取绝对值最接近0的像素点进行连接即可生成图像轮廓.

第七步:将当前帧得到的值合并到已有的volume。通过将多帧合并成一个TSDF,既可以提升精度又可以补全单帧缺失的信息。

$TSDFi(x) = \frac{W_{i−1}(x)TSDF_{i−1}(x) + w_{i}(x)tsdf_{i}(x)} {W_{i−1}(x) + w_{i}(x)} $

$W_{i}(x) = W_{i−1}(x) + w_{i}(x) $

对于需要更新的voxel wi(x)=1,没在当前视场内的点为0。

最后:重复遍历所有帧,得到合并后的TSDF。

TSDF也有不少改进值,例如权重是可以由光心到x的入射角度余弦值计算得到;也有适合慢速移动场景的TSDF++等等,在实践中,根据需要去选择。

并行化考虑:

非常适合并行化操作。