InfiniTAM是对voxel hashing的改进,voxel hashing介绍见InfiniTAM解析(1):
http://blog.csdn.net/fuxingyin/article/details/51707057
参考文献:”Very High Frame Rate Volumetric Integration of Depth Images on
Mobile Devices”
InfiniTAM的存储结构和voxel hashing不一样,voxel hashing是每个bucket中备用几个entry来解决hash value collision问题,InfiniTAM每个bucket中只有一个entry,论文中也提到,每个bucket中存储2-3倍的entry,不如存储2-3倍的bucket,2-3倍的bucket会减少hash value collision,并且这样做代码也更简洁。
存储结构如上图所示,hash table中的entry存储了指向voxel block的指针、3D Block在世界坐标系中的位置和指向excess entries片段的index。Ordered entries是hash table,用哈希值访问,当出现collision时,在excess entries中存储。
根据world position和hash function计算hash value,从hash table中和在unordered entries中找具备相同world position的entry。
同voxel hashing对于每次测量的深度在 d−μ 和 d+μ band内计算和ray相交的block,通过block的world position计算hash value,如果多个bucket的hash value值相同,则在bucket中随机选取一个分配,计算hash value时一般不会出现collision,但是会在第一帧的时候因为待allocate的blocks太多,出现collision的block的会很多,解决方法是对于第一帧allocate两次,而对于其它帧只allocate一次。
删除的时候只需要把相应的entry标记为removed,并且把block的pointer挂到unallocated entries上即可。
Fusion过程如下,主要分为4步:
Allocation:在hash table中创建新的entries和voxel blocks。
Visible list update:Maintain在当前视角下可见的visible blocks。
Camera data Intergraph:将新获取的camera data融合到当前可见的visible voxel blocks中。
Swapping:在long storage和active memory中交换数据,保持对当前visible blocks的更新。
作者使用increamental的方式更新当前视角下可见的blocks,这里假设,在当前视角下可见的visible blocks只会在previous视角下可见,或者在当前视角下可见。
在当前视角下可见的blocks在allocation阶段就已经check了,所以我们只对上一帧视角下visible的并且没有被当前视角下标记的blocks进行check就可以。
更新的方式同KinectFusion。
但是更新的时候只是对当前visible的blocks做更新。
在host memory中hash table中的每个entry对应一个voxel block,当一个voxel block被删除时,它对应的hash不会被删除只是在active memory中被标记为unavailable,在host memory中为available。
因为host memory向active memory传输速度限制,二者之间进行传输时会比online reconstruction要慢很多 ,为了stable tracking和maintain overall reconstruction accuracy,online system会不断地融合新的深度数据,即使这些深度数据已经在host memory中已经有存储了,这样可以确保可以稳定地跟踪相机(至少和最近重建的model比较做跟踪),当host memory向active memory传输完成时,online system可能已经重建了场景的局部信息,在传输完后,再用secondary integration来融合从host memory传到active region的数据。
Voxel block swap in和swap out如上图所示,voxel block如果投影到预定义和当前live camera预定义的边界之内则会swapped in,否则会被swap out。
例子如上图所示swapping in操作:
根据world position计算的hash value indices,并存储在active memory的entry中,如上图1到2的拷贝过程。
indices还会拷贝到host memory的transfer buffer中,如上图从2到3的拷贝过程。
根据3中的indices可以在Long Term Storage中索引host memory中的存储块4。
索引到的存储块4拷贝到Transfer Buffer 5。
Transfer Buffer 5再拷贝到device transfer buffer 6。
最后再把block拷贝到device存储7。
类似Swap out操作如上图。
Raycasting range:给定voxel block对于每个像素点计算最小和最大ray lengths。
Raycasting:计算每个ray和3D surface的交点。
Surface normal:计算normal在跟踪的时候和在显示的时候使用。
Forward projection and other consideratios:raycasting并不是必须的,这里在精度和速度上权衡。
和KienctFusion不同的是用voxel blocks和spare represention,对于每个像素点可以计算最小和最大的search range
对于voxel hashing算法(InfiniTAM解析1)在所有可见的blocks计算triangle meshes(论文里没说怎么做的),根据计算的triangle mesh计算Z-buffer,计算的Z-buffer包含了最小和最大的观测到的深度值。
作者将所有的当前视角下可见的blocks投影到图像上,对于每个block计算投影到图像上后的bounding box,存储在相机坐标下最小和最大的Z坐标。和rendering类似,bounding box被分成16x16个像素点的fragments,然后再用parallel prefix sum归并这些fragments,归并之后,再用一轮操作更新Z-buffer中的值。
用上述raycasting的方式计算的bounds只是一个近似,实际使用80x60分辨率的图像对640x480的图像做近似,计算raycasting range。
Raycasting ray在显存中march的过程如下图所示:
normal是根据投影得到的点云计算的,而不是根据TSDF模型计算的。
实际上在做跟踪的时候,不需要用当前帧和上一帧投影做配准,如果相机视角变化不大,用上一帧和第前k帧投影的计算位姿也可以,这里当视角视角变化大于一定阈值或者和上一帧投影的帧间隔大于一定帧数时,再raycasting,示意图如下:
如上图,第一个full Raycast的结果用来对下一帧,下下帧和下下下帧做跟踪,显示的时候,会根据下一帧或者下下帧的位姿将full raycast得到的点云根据位姿做变换,变换后再显示。
Tracking的时候用IMU测量的rotating代替用ICP和photometric consistency测量到的rotating。