从点云到网格(二)VRIP介绍
VRIP(Volumetric Range Image Processing),顾名思义,是从深度图重建网格的一种方法。VRIP是Brian Curless和Marc Levoy在1996年提出来的方法,距今已经有20年的历史了,依然属于最好的方法之一。
VRIP的核心问题是
已知世界坐标系下,某物体表面\(f\)在不同视角下的深度图\(\hat{f_1},...,\hat{f_K}\),求\(f\)。这里隐含深度图在世界坐标系下的位姿是已知的。
许多三维测量方法,比如激光、TOF、结构光、双目视觉等,都可以得到深度图。因此这是一个非常有意义的问题。如何将这些深度图融合成为一个平滑的单一网格呢?这就是VRIP要解决的问题。
下面给出一个结构光成像的例子。左上图是将不同视角拍摄到的深度图(已转化为三维网格)匹配在一起后的情形。右上图是左图中某一部分的切面,可以看到很多层网格重叠在一起,噪声、匹配误差、采样率等都反映在这个局部中。左下图是VRIP的结果,右下图是VRIP融合的结果和深度图放在一起(棕色是深度图,蓝色是融合后的网格,只能看到一点点)。
VRIP的基本假设
VRIP最重要的假设是测量误差沿着光线传播方向(投影方向)并服从高斯分布。假设\(\hat{f_k}(u,v)\)是在第\(k\)个视角下,光线从传感器\((u,v)\)位置沿着传播方向到达\(f\)的距离的测量值,\(f_{k}(u,v)\)为其真实值。那么条件概率满足
\(P(f_{k}(u,v)|\hat{f_k}(u,v))=c_k(u,v)\exp[-\frac{1}{2}(\frac{\hat{f_k}(u,v)-f_k(u,v)}{\sigma_k(u,v)})^2]\)
因此,VRIP算法和视角非常相关。
VRIP的模型
VRIP尝试从概率的角度来描述核心问题。对任意曲面\(f\),\(P(f|\hat{f_1},...,\hat{f_K})\)为\(f\)的条件概率。那么求解核心问题转化为一个最大似然问题
\(\max_{f}P(f|\hat{f_1},...,\hat{f_K})\)
经过一系列独立性假设,
\(P(f|\hat{f_1},...,\hat{f_K})= \prod_{k=1}^{K}\prod_{i=1}^{M}\prod_{j=1}^{N}P(f_{k}(i,j)|\hat{f_k}(i,j))\)
取对数,并转化为求和
\(E(f)=-\Sigma\Sigma\Sigma \log[P(f_{k}(i,j)|\hat{f_k}(i,j))]\)
将离散情形转换为连续情形
\(E(f)=-\Sigma\int\int_{A_k}\log[P(f_{k}(u,v)|\hat{f_k}(u,v))]dudv\)
定义\(d(u,v,f_k)=\hat{f_k}(u,v)-f_k(u,v)\),代入\(P\)的表达式,则有
\(E(f)=\frac{1}{2}\Sigma\int\int_{A_k}w_k(u,v)d_k(u,v,f_k)^2 du dv\)
上式还是建立在各个视角下的局部坐标系(传感器坐标系)。将上式转换到世界坐标系下,有
\(E(f)=\frac{1}{2}\Sigma\int\int_{A}w_k(x,y,z)d_k(x,y,z)^2[\mathbf{v_k}(x,y,z)\cdot (\frac{\partial z}{\partial x}) ,\frac{\partial z}{\partial y},-1)] dx dy\)
其中\(z=f(x,y)\) ,\(\mathbf{v_k}\)是第\(k\)个视角的投影方向,\(d_k(x,y,z)=\hat{f}(x,y,z,\mathbf{v_k})-f(x,y)\) ,为三维点\((x,y,z)\)沿着第\(k\)个视角的投影方向与深度图对应点的测量值\(\hat{f}\)的距离,即Signed Distance Function。积分中点乘那项是从\(uv\)坐标系转换到\(xyz\)坐标系的\(Jacobian\)矩阵。
下图是SDF的示意图。注意靠近传感器的方向距离为正,远离传感器的方向距离为负。

下图是同一个三维点在两个视角下的SDF示意图。注意SDF是沿着视角方向(光线传播反方向)的。图中\(d_1<0,d_2>0\)。

于是,问题转换为
求\(,使得z=f(x,y),使得\)\(E(f)\)最小。
求解这个问题涉及到很多偏导数、方向导数的知识,本人也并没有完全搞明白。但问题的解却是出乎意料的简单
若\(z=f(x,y)\)满足\(\Sigma w_k(x,y,z)d_k(x,y,z)=0\) ,则\(z\)是最优解。
VRIP算法流程
定义\(D(\mathbf{x})=\frac{\Sigma w_k(\mathbf{x})d_k(\mathbf{x})}{\Sigma w_k(\mathbf{x})}\),那么\(D(\mathbf{x})=0\)就是我们要重构的三维表面。实际应用中,\(D(\mathbf{x})\)可看作一个三维体数据(volume),\(D(\mathbf{x})=0\)通过提取\(D\)的零等值面即可得到。因此,算法先增量构建\(D\),然后通过等值面提取方法得到三维网格。例如,Marching Cube就是一种高效提取等值面的算法,而且非常适合在GPU上实现。
需要指出的是,作者在论文中采用了TSDF(Truncated signed distance function),即在一条光线上,只考虑测量值\(\hat{z}\)附近一定范围\(\hat{z}\pm \delta z\)内的体素。一方面是因为一条光线可能会穿过物体不止一次。另一方面这样也可以减小搜索范围,加速算法。
VRIP算法的框架如下:
/* 初始化 */
对每个三维体素,设其权重为0。
/* 深度图融合 */
对每个深度图 {
/* 准备 */
网格化深度图;
计算每个点的权重;
/* 更新体素 */
对该视角下FOV中的体素 {
沿投影方向找到深度网格中的对应点;
计算其沿投影方向的SDF;
插值得到其权重;
更新这个体素的权重和SDF。
}
}
/* 表面提取 */
提取零等值面。
着重强调一点,深度图的权重需要尽量准确,特别是(1)对噪声大的点能够赋予较小的权重,(2)对于法向量和视角方向角度比较大的三维点,可以降低其权重(曲率大,采样率不够,重建误差大)。
下图是两个视角下的TSDF的融合的示意图。

下图是多个视角下TSDF的融合(两颗真实的牙齿)

VRIP的优缺点
VRIP的优点主要有
- 它是一定意义下的最大似然解。这保证了解的精度。
- 它是一个增量方法,每一次得到新的深度图后,可简单快速地加入到TSDF中。
- 适合并行处理,可用GPU加速
VRIP的主要缺点有
- VRIP生成的网格会附加一定的平滑效果,在存在噪声和匹配误差的情况下有时不能重建出细微的结构。
- 如果深度图存在匹配误差,VRIP并不能消除这些误差。这些误差会反映在融合后的网格中(分层、噪声等)。
VRIP的加速
VRIP算法的时间复杂度比较高。作者在CPU端做了很多优化和加速工作。假设深度图平行于\(xy\)平面,且投影方向为正交投影,那么沿\(z\)方向的所有体素在深度图上的投影相同,因此其TSDF可以在\(z\)方向上简单计算得到,而且权重相等,不必要重复运算。作者的主要思路是,将不同视角下的深度图和坐标系,通过仿射变换和重采样,映射到相对标准的位置(深度图平行于\(xy\)平面),从而减少投影和权重的计算量。
如下图所示,(a)某个视角下的深度图及正交投影方向,投影方向和Voxel slices有一个夹角。(b)通过一个仿射变换,将投影方向变换为与Voxel slices相垂直。一般而言,仿射变换后深度图和Voxel slices仍然有夹角,因此还要将它在平行于slices的平面上重采样。(c)将计算得到的TSDF变换回原坐标系下的距离。

VRIP在SLAM中的应用
VRIP算法在RGBD SLAM中有着广泛的应用。Kinect Fusion的作者并没有采用CPU加速的方法,而是将VRIP算法移植到GPU上,利用Ray casing算法做到了网格的实时显示,效果非常好。后来的Kintinuous、Elastic Fusion、Dynamic Fusion也都采用类似的架构去生成网格。
从点云到网格(二)VRIP介绍的更多相关文章
- 从零开始一起学习SLAM | 点云到网格的进化
点击公众号"计算机视觉life"关注,置顶星标更快接收消息! 本文编程练习框架及数据获取方法见文末获取方式 菜单栏点击"知识星球"查看「从零开始学习SLAM」一 ...
- 开发指南专题十四:JEECG微云高速开发平台MiniDao 介绍
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zhangdaiscott/article/details/27068645 开发指南专题十四:J ...
- 阿里云 OCS SDK for NodeJS介绍
阿里云 OCS SDK for NodeJS介绍 阿里云技术团队:熊亮 阿里云 SDK for NodeJS 是为 NodeJS 开发者提供使用阿里云各项服务的统一入口,由阿里云UED团队负责开发维护 ...
- {Django基础九之中间件} 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证
Django基础九之中间件 本节目录 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证 六 xxx 七 xxx 八 xxx 一 前戏 我们在前面的课程中已经学会了 ...
- {MySQL数据库初识}一 数据库概述 二 MySQL介绍 三 MySQL的下载安装、简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 初识sql语句
MySQL数据库初识 MySQL数据库 本节目录 一 数据库概述 二 MySQL介绍 三 MySQL的下载安装.简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 ...
- {python--GIL锁}一 介绍 二 GIL介绍 三 GIL与Lock 四 GIL与多线程 五 多线程性能测试
python--GIL锁 GIL锁 本节目录 一 介绍 二 GIL介绍 三 GIL与Lock 四 GIL与多线程 五 多线程性能测试 一 背景知识 ''' 定义: In CPython, the gl ...
- 坚果云如何使用二次验证码/谷歌身份验证器/两步验证/虚拟MFA?
一般步骤:登陆后点邮箱名——安全设置——开通两步验证,用二次验证码微信小程序绑定即可 具体步骤见链接 坚果云如何使用二次验证码/谷歌身份验证器/两步验证/虚拟MFA? 二次验证码小程序于谷歌身份验证 ...
- 华为云如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器?
一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接 华为云如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器? 二次验证码小程序于谷歌身份验证器APP的优势 1.无需下载ap ...
- 阿里云如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器?
阿里云如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器? 见如上链接中视频
- 腾讯云OCR服务二次开发
本文记录了对腾讯云OCR服务二次开发的代码和开发过程中遇到的问题.
随机推荐
- 2016 ICPC青岛站---k题 Finding Hotels(K-D树)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5992 Problem Description There are N hotels all over ...
- [更新设计]跨平台物联网通讯框架ServerSuperIO 2.0 ,功能、BUG、细节说明,以及升级思考过程!
注:ServerSuperIO 2.0 还没有提交到开源社区,在内部测试!!! 1. ServerSuperIO(SSIO)说明 SSIO是基于早期工业现场300波特率通讯传输应用场景发展.演化而来. ...
- tomcat 504 gateway time-out
今天有个环境ajax调用一个请求的时候,出现一个504 gateway time-out响应,原以为是nginx找不到资源的问题,恰当我们的服务器上又配置了nginx,看了配置文件,没有指向tomca ...
- 理解Java对象的交互:时钟显示程序
实现: 结构: 对象:时钟 - 对象:小时 - 对象:分钟 小时和分钟具有相同属性(值,上限),可以用一个类Display来定义这两个对象: 但是两者之间又具有联系( ...
- AEAI ESB培训大纲
1. 概述 本文档的目的是为了让使用者能更好的操作.维护.服务于整个ESB系统平台,该信息系统平台不仅需要成熟稳定的产品,更需要技术熟练的运行维护人员,以便能更好地进行科学有效的运行维护工作. AEA ...
- MyEclipse 2016正式版更新内容
MyEclipse 2016 Stable 1.0正式发布!在保留之前CI系列的工具之外,又新增了许多非常棒的新功能.正式版下载地址 Eclipse Mars MyEclipse 2016基于Ecli ...
- C# 知识特性 Attribute
C#知识--获取特性 Attribute 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体关联后,可在运行时使用"反射"查询 ...
- .Net开源Excel、Word操作组件-NPOI、EPPlus、DocX
一.NPOI 简介: NPOI is the .NET version of POI Java project. With NPOI, you can read/write Office 2003/2 ...
- LAMP坏境和LNMP环境安装Nagios4.1.1和基本配置
----------------------------------------以下内容为笔者生产环境的监控,安装都是经过一步步测试的-------------------------------- ...
- 萌新笔记——封装hiredis——C++与redis对接(一)(string的SET与GET操作)
在菜鸟教程自学了redis,总想着像Mysql一样,在C/C++中进行对接.于是查询了一些资料,最后找到了hiredis.然而直接用它的话,难免有点不方便.于是,对其进行封装. hiredis直接去g ...