您的位置:首页 > 其它

voxel hashing 解析

2016-06-18 20:30 204 查看
为解决 volumetric fusion 重建时,重建的空间划分成等大小的 voxel,显存消耗太多,难以重建大场景,并且大量 voxel 更新耗费 GPU 资源问题,斯坦福图形学组提出了 voxel hashing 算法(参考文献:”Real-time 3D Reconstruction at Scale using Voxel Hashing”),voxel hashing 只在相机测量到的场景表面划分 voxel,而不是将整个空间都划分成 voxel,从而节省显存。算法用 hash 表的形式存储在场景表面划分的 voxel block(8x8x8 voxels),方便 voxel block 的查询。算法代码开源。InfiniTAM 是对 voxel hashing 的改进,算法速度更快,适合在移动端运行。BunldeFusion mapping 部分 code 和 voxel hashing 是一样的。

系统 pipeline 和 KinectFusion 类似,这里为了节省显存,重建的 voxel block 可以从 CPU 向 GPU 移动,或者从 GPU 向 CPU 移动,有 streaming 环节。



hash 表存储数据结构



待重建空间可以等效为无穷多个小的网格(voxel block 组成,每个 block 8x8x8 个 voxel),如上图。hash 表由有 buckets 组成,每个 bucket 对应一个 hash 值,并且有 n 个 hash entries(上图有 4 个),每个hash entry 存储 voxel block 的空间坐标,hash collision 时解决 hash collision 用的 offset 值,和指向 block 实际存储空间的地址,数据结构如下图:

Hash entry的数据结构如下:



每个 block 有 8x8x8 个 voxel,voxel 存储 sdf,color 和 weight 信息,类似于 KinectFusion。

hash 值通过 block 的空间坐标计算得到,计算如下:

H(x,y,z)=(x⋅p1⊕y⋅p2⊕z⋅p3) mod nH(x,y,z)=(x⋅p1⊕y⋅p2⊕z⋅p3) mod n。

采用 hash 表存储较为头疼的问题是不同的 block 映射为同一个 hash 值的问题,也称作 hash collision,解决办法是采用 bucket 中的下一个 hash entry 存储,如果 bucket 满了,需要更复杂点的方式解决,下文有详细写。

Resolving collisions



解决 hash value collision 的方法是,将 hash 表划分成 bucket,每个 bucket 有 n 个(上图 4 个 entry),当不同的 block 映射为同一个 hash value 时,采用 bucket 内一个空的 entry 存储。有种可能是,bucket 内所有的 entry 都被占满了,上图列举了几个比较极端的情况。

hash 表牵扯的几种操作

Insertion

在将当前帧的信息融合到模型前,需要先在显存中分配在相机视场内的 block,首先根据 block 的空间坐标计算 hash 值,在 hash 表对应的 bucket 中查找该 block 是否已经分配(retrieval),如果已经分配,则返回,如果没有分配,则在 bucket 中查找空闲的 entry,如果存在空余的 entry,则将 block 的 hash entry 插入,如果 bucket 占满,则在下一个 bucket 中查找空闲的 entry,如果在下一个 bucket 中查找的 entry 不是 bucket 末尾的 entry,则找到插入位置,对应上图中的 2 所示。注意,解决 hash collision 的方式是每个 bucket 都有个 offset,offset 存储发生 collision 时的链表信息,解决 collision 的方式,是在 bucket 邻近的下面的 bucket 中存储,而不是在整个 hash 表的末尾有个额外的 list。

有种情况是,hash 值对应的 bucket 的下一个 bucket 也满了,如上图中的 3 所示,注意,每个 bucket 的末尾的 entry 值用来存储本 hash 值对应的 block 的信息,末尾的 entry 的 offset 存储当 bucket 的存储空间不够时,额外链接的下面的 bucket entry 的 offset,所以当 hash 值对应的 bucket 的下一个 bucket 也占满时,解决 collision 的方式如上图的中 3 所示。

上图中 block (0, 2, 3),(1, 2, 3),(2, 4, 5) 和 (8, 1, 7) 对应的 hash 值为同一个。

Retrieval

根据 block 的世界坐标计算 hash 值,进而在 hash 表中得到 bucket 的位置,通过比较 hash entry 中存储的 block 坐标值,和待索取的 block 的坐标值,可以判断当前 hash entry 存储的是否是待索取的 block 的信息,注意,为了解决 hash value collision,每个 bucket 中的 hash entry 存储的可能是上面的 bucket 对应 hash 值的信息,并且,在 bucket 中遍历每个 entry 和待索取的 block 的坐标做对比时,碰到空的 entry 需要继续向下寻找,因为由于 hash deletion,bucket 会产生空的 entry。

Deletion

删除时分三种情况:

1、如果待删除的 hash entry 在 hash value 对应的 bucket 中,并且不是末尾元素,或者是末尾元素,但是末尾元素的 offset 是空,则在 bucket 直接将 hash entry 删除,如上图中的 5 所示。

2、如果待删除的 hash entry 是 hash value 对应的 bucket 中的末尾元素,并且末尾元素的 offset 不是空,则需要根据 offset 找到链接的下一个 hash entry,并且将下一个 hash entry 移动到到末尾的 entry,

因为 bucket 末尾的entry 存储的是 bucket 满时,链接的别的 bucket 中 entry 地址,所以这里必须做移动。

3、如果待删除的 hash entry 在别的 bucket 中,删除该 entry 并且修改 offset 的值,如上图中的 4 所示。

Voxel block allocation

跟踪计算得到相机 pose 后,将新获取的 RGB-D 图像融合到模型中,融合的时候,需要计算在当前相机视角内的 block,方法是采用 DDA (AMANATIDES, J., AND WOO, A. 1987. A fast voxel traversal algorithm for ray tracing)算法计算和 ray 相交的 block,如果 block 没有分配,则在 hash 表中插入新的 hash entry,并且分配 block 所需的存储空间。



作者采用 DDA 算法计算和 ray 相交的 block,算法如下。

假设 ray 的方程是 u⃗ +tv⃗ u→+tv→,首先确定 ray 起始 block 的位置,如上图,起始位置是 block a。确定和第一条垂直线相交的 t 值,记为 tMaxXtMaxX,和第一条水平线相交的 t 值,记为 tMaxYtMaxY,如果 tMaxX<tMaxYtMaxX<tMaxY,则在 X 方向前进 stepXstepX,反之,在 Y 方向前进 stepYstepY。stepXstepX 和 stepYstepY 为 +1 或者 -1(由 v⃗ v→ 的方向决定),表示 ray 所处的 block 的位置在 X 或者 Y 方向上前进一个 block。

上图中,ray 起点在 block a,在 1 点和第一条垂直线相交,在 2 点和第一条水平线相交,tMaxX<tMaxYtMaxX<tMaxY,所以在 X 方向前进 1 个 block, ray 的位置移动到 block b。在 3 点和第一条垂直线相交,在 2 点和第一条水平线相交,tMaxX>tMaxYtMaxX>tMaxY,在 Y 方向前进 1 个 block,ray 到达 block c。在 3 点和第一条垂直线相交,在 6 点和第一条水平线相交,tMaxX<tMaxYtMaxX<tMaxY,在 X 方向前进 1 个 block,到达 block d,以此类推,到达 block e f g h。

对于 2 个维度算法流程:



对于 3 个维度算法流程:



block 在显存中的存储空间是事先划分的,在 GPU 中用一个 list 存储还没有分配的 block,新 block 分配空间时,从 list 的末尾元素获取存储地址,当一个 block 删除时,删除的 block 的地址放到 list 的末尾。

Voxel block integration

此时在相机视场内所有的 block 都已分配存储空间,更新重建好的 voxel block 时,并不是 hash 表对应的所有的 block 都做更新,因为 hash 表大部分都是空值,并且 block 许多不在相机的视场内,先用parallel prefix sum算法挑选出已经分配并且在相机视场内的 block,算法图示如下:



首先计算已经有值的并且在对应的 block 在当前帧可见的 hash entry,然后对获取的 0 1 数组做累加得到 index array,在 index array 中数字增加的地方就是 hash entry 有值,并且对应的 block 在当前帧可见的,这这类 hash entry 拷贝出来,在更新模型时,值更新这类 hash entry 对应的 voxel block。

Implicit Surface Update

更新 voxel block 的方式和 KinectFusion 类似,也是加权融合的方式更新。

Garbage Collection

因为噪声或者发生物体移动,一些 block 需要被清理掉。判断 block 是否被清理掉的方式是计算 block 内 voxel sdf 值的最小值和权值的最大值,如果权值的最大值为 0 或者最小的 sdf 值大于阈值,则将这个 block 标记为待删除,将所有的 block 标记完后,再并行删除掉需要清理的 block。

Surface extraction

同 KinectFusion,也是采用 raycasting 提取当前视角下重建好的物体表面,在做 raycasting 前,需要计算每个 ray 的出发点和结束点,也就是需要找到重建好的 block 的 bounding box。方法是,对于每个 block,计算可以囊括 block 的三角面片,然后对于所有的 block 采用 shader 计算当前视角下的最小 z buffer 值和最大 z buffer 值,最小 z buffer 对应 raycasting 时 ray 的起点,最大 z buffer 对应 raycasting 时 ray 的终点。

做 raycasting 时,ray 从起点到终点做 marching 时,采用 tri-linear 插值的方式,估计对应点的 sdf 值,需要找到 8 邻接的 voxel 中存储的 sdf 值,方式是对于每个 voxel ,根据坐标找到所在的 block,然后找到 voxel 对应的 sdf 值。

为了加速,在做 ray marching 时,事先跳过一个预定义的阈值(半个 truncation 大小)。

Camera tracking

和 KinectFusion 一样,采用 ICP 算法计算 pose。

Steaming



将离相机视场远的点,从 GPU 移动到 CPU,寻找待移动 voxel block 的方式是,以相机光心正前方 4m 的点画半径为 8m 的圆,圆以外的 voxel block 从 GPU 移动到 CPU,相机移动到之前重建的位置时

GPU-to-Host Streaming

并行访问 hash 表并且标记移除从 active region 移出去的 hash entry 和 hash block,对于所有待移出去的 hash entry,先将其拷贝到 intermediate buffer,然后再讲 hash entry 对应的 block 拷贝到另外的 intermediate buffer,删除掉原始的 hash entry 和 block,并且将 intermediate buffer 中的 hash entry 和 block 拷贝到 内存。在内存中,voxel 不按照 hash 表存储,而是将空间划分成等大小 chunks(1 m^3),每个 chunk 对应的 voxel block 用链表的形式链接起来,block 对应的 hash entry 也存起来。

Host-to-GPU Streaming

对于 Host 向 GPU 的移动,找到完全在相机视场内的 chunk,GPU-to-CPU 是以 block 的单位移动的,GPU-to-CPU 以 chunk 为单位移动。移动时,每次只移动和相机视角最近的单个 chunk。移回到 GPU 的 block,在 hash 表和 block 的堆存储中,都需要分配新的单元。

Steam and Allocation Synchronization

host 中存储的 block 和 GPU 中存储的 block 需要同步,未解决同步问题,在 GPU 采用一个 bool list 存储哪些在 GPU 中存储,哪些在 CPU 内存中存储,在 CPU 中已经有存储的 block,在 GPU 中要避免插入新的。

voxel hashing 文章出处:

“Real-time 3D Reconstruction at Scale using Voxel Hashing”

版权声明:本文为博主原创文章,未经博主允许不得转载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  实时三维重建