真实场景的虚拟视点合成(View Synthsis)详解
上一篇博客中介绍了从拍摄图像到获取视差图以及深度图的过程,现在开始介绍利用视差图或者深度图进行虚拟视点的合成。虚拟视点合成是指利用已知的参考相机拍摄的图像合成出参考相机之间的虚拟相机位置拍摄的图像,能够获取更多视角下的图片,在VR中应用前景很大。
视差图可以转换为深度图,深度图也可以转换为视差图。视差图反映的是同一个三维空间点在左、右两个相机上成像的差异,而深度图能够直接反映出三维空间点距离摄像机的距离,所以深度图相较于视差图在三维测量上更加直观和方便。
- 利用视差图合成虚拟视点
- 利用深度图合成虚拟视点
一、利用视差图合成虚拟视点
由于视差图反映的是三维空间点在左、右两个相机上成像的差异,并且由于提前进行了立体校正,这种差异就反映在图像的同一行上。在立体匹配的SGBM算法中就是以其中某一副为参考图像,在另一幅图像的同一行上搜索匹配点。因此在合成虚拟视点时也只需在同一行上平移虚拟摄像机位置即可。流程如下:
(1). 假设视差图中某一个像素点的视差值为dmax,也就是说从左摄像机camL到右摄像机camR之间,该像素点的视差值变化范围为0~dmax。为了方便介绍我将其归一化到alpha取值范围为0~1。
(2).那么如果我要获取alpha=0.5位置时候虚拟相机位置的图像呢,那么此时该像素点和左图像匹配点的坐标差异就是0.5 * dmax,和右图像匹配点的坐标差异也是0.5 * dmax;如果alpha=0.3,那么此时该像素点和左图像匹配点的坐标差异就是0.3 * dmax,和右图像匹配点的坐标差异也是0.7 * dmax;
(3).根据上面提到的原理,显而易见,合成新视点时候只需要将左图像的像素点位置向右移动alpha *dmax,或者右图像的像素点向左移动(1-alpha)*dmax,就可以得到alpha位置处虚拟相机拍摄的虚拟视点图像。
合成虚拟视图即可以利用左参考图像和对应的左视差图,也可以利用右参考图像和对应的右视差图,更好的是都利用上得到两幅虚拟视点图像,然后做图像融合,比如基于距离的线性融合等。
在算法的实现中,又有两种选择,一个是正向映射,一个是反向映射(逆向映射)。
1.正向映射
① 将原参考图像中整数像素点根据其对应上视差值平移到新视图上。
② 平移后像素点坐标可能不是整数,为了获取整数坐标,采用最近邻插值,将原图像像素值赋值到新坐标位置。
③ 由于最近邻插值会损失精度,因此在物体的边缘会出现锯齿效应。
2.反向映射
① 利用参考视点的视差图dispL,算出虚拟视点位置的视差图dispV;
② 由于遮挡等因素影响,dispV肯定会出现空洞和裂纹,所以需要做一个空洞填充holeFilling;
③ 利用dispV将虚拟视点图像中的整数坐标平移到参考视点位置下的坐标,此时也可能不是整数,而是浮点数坐标。这就面临一个从哪里取值的问题。
④ 取参考视点图像浮点数坐标附近4个点的像素值,用双线性插值算出对应虚拟视点图像位置处的像素值即可。
⑤ 由于双线性插值属于一种加权平均的思想,能够有效避免精度损失造成的锯齿现象,但是算法复杂度要高。
下面给出利用左视点图像和对应视差图获取虚拟视点位置图像的效果(反向映射+双线性插值):
不进行空洞填充
空洞填充
二、利用深度图合成虚拟视点
和利用视差图合成新视点一样,利用深度图合成新视点也有两种选择:1. 正向映射 2. 反向映射。由于正向映射比较简单并且效果不理想,因此目前大多采用反向映射方法。
已知内参矩阵K,下面仍然以左图像imgL和depthL为参考图像,获取alpha=0.5位置处的虚拟视点图像,简要步骤如下:
(1). 利用内参矩阵K, 将depthL映射到三维空间点,平移到虚拟相机坐标下后,重投影到虚拟视点图像平面,得到虚拟视点位置处的深度图depthV;
(2). 对depthV进行空洞填充;
(3). 利用内参矩阵K和深度图depthV,将虚拟视点图像imgV上的坐标点反向投影到三维空间点,平移后再重投影到参考图像imgL上, 在imgL上利用双线性插值获取imgV上的像素值。
具体流程如下:
(1). 利用内参矩阵K,以及参考深度图depthL,如下图,将参考图像坐标点(u, v)投影到参考相机的摄像机坐标系下,得到对应的三维空间点(X, Y, Z),计算方法如下:
d * u = fx * X + cx *Z
d * v = fy * Y + cy * Z
d = Z
其中d是深度值,fx, fy, cx, cy均从内参矩阵中得到,那么(X, Y, Z)可以表示如下:
X = ( u - cx ) * d / fx
Y = ( v - cy ) * d / fy
Z = d
参考深度图depthL 参考左图像imgL
(2). 将三维点(X, Y, Z)平移到虚拟摄像机坐标系下,得到虚拟摄像机坐标系下的三维点(X1, Y1, Z1), 计算如下:
X1 = X - alpha * baseline
Y1 = Y
Z1 = Z
(3). 将(X1, Y1, Z1)重投影到虚拟视点图上,得到坐标(u1, v1):
u1 = ( fx * X1 + cx * d ) / d
v1 = ( fy * Y1 + cy * d ) / d
d = Z1
//注意此处d != 0
利用最近邻插值得到虚拟视点深度图depthV。如下图所示,alpha=0.5位置虚拟视点深度图:
(4). 对depthV进行空洞填充。填充后depthV如下图:
(5). 利用depthV和内参矩阵K,反向重复上述操作。将虚拟视点图像imgV坐标点反向投影到三维点,平移,再重投影到参考视图imgL上,在imgL上利用双线性插值得到imgV上的像素值。从而获取虚拟视点图像imgV,如下图:
(6). 综合上述步骤,可以获取alpha从0 到 1, 也就是从左相机位置到右相机位置的一系列虚拟视点图像,gif动图展示如下:
上面效果中在深度不连续区域有较为明显的失真,这是由于该区域为遮挡区域,无法计算出准确的视差值,可以通过观察前面立体匹配博客的视差图或者深度图看出。而采用的空洞填充将附近的视差值填充过去,所以会造成前景出现在背景部分,出现较为明显的伪影。去除伪影也有很多种方法,比如结合右参考相机合成同样位置的虚拟视点,然后将两个视点融合等方法。
其实3D Warping技术的核心就是下面几条语句,二维图像点到三维空间点,平移,旋转,再重投影到新的二维图像点。上面没有加入旋转,旋转的话就是直接用三维点乘以3x3的旋转矩阵后平移,然后再重投影。
float dep = pDepthV[i*imgW + j];
if (dep < 0.001) continue;
//反投影
float X = (j - cx)*dep / fx;
float Y = (i - cy)*dep / fy;
float Z = dep;
//平移
float X2 = X + offsetX;
float Y2 = Y;
float Z2 = Z;
//重投影
float uf = (fx*X2 + cx* Z2) / dep;
float vf = (fy*Y2 + cy * Z2) / dep;
真实场景的虚拟视点合成(View Synthsis)详解的更多相关文章
- 真实场景的双目立体匹配(stereo matching)以及虚拟视点合成(virtual view synthsis)示例
双目立体匹配一直是双目视觉的研究热点,双目相机拍摄同一场景的左.右两幅视点图像,运用立体匹配匹配算法获取视差图,进而获取深度图.而深度图的应用范围非常广泛,由于其能够记录场景中物体距离摄像机的距离,可 ...
- 使用 /proc 文件系统来访问 linux操作系统 内核的内容 && 虚拟文件系统vfs及proc详解
http://blog.163.com/he_junwei/blog/static/19793764620152743325659/ http://www.01yun.com/other/201304 ...
- SurfaceView 与view区别详解
SurfaceView 与view区别详解 https://blog.csdn.net/u011339364/article/details/83347109 2018年10月24日 17:20:08 ...
- View绘制详解(五),draw方法细节详解之View的滚动/滑动问题
关于View绘制系列的文章已经完成了四篇了,前面四篇文章主要带小伙伴们熟悉一下View的体系的整体框架.View的测量以及布局等过程,从本篇博客开始,我们就来看看View的绘制过程.View的绘制涉及 ...
- View绘制详解(四),谝一谝layout过程
上篇博客我们介绍了View的测量过程,这只是View显示过程的第一步,第二步就是layout了,这个我们一般译作布局,其实就是在View测量完成之后根据View的大小,将其一个一个摆放在ViewGro ...
- View绘制详解(三),扒一扒View的测量过程
所有东西都是难者不会,会者不难,Android开发中有很多小伙伴觉得自定义View和事件分发或者Binder机制等是难点,其实不然,如果静下心来花点时间把这几个技术点都研究一遍,你会发现其实这些东西都 ...
- View绘制详解(二),从setContentView谈起
掐指一算,本来今天该介绍View的测量了,可是要说View的测量,那就要从setContentView谈起了,setContentView本身涉及到的东西也是挺多的,所以今天我们就先来看看这个setC ...
- View绘制详解,从LayoutInflater谈起
自定义View算是Android开发中的重中之重了,很多小伙伴可能或多或少都玩过自定义View,对View的绘制流程也有一定的理解.那么现在我想通过几篇博客来详细介绍View的绘制流程,以便使我们更加 ...
- Android游戏开发之旅 View类详解
Android游戏开发之旅 View类详解 自定义 View的常用方法: onFinishInflate() 当View中所有的子控件 均被映射成xml后触发 onMeasure(int, int) ...
随机推荐
- ABP 数据迁移
我主要是在项目部署的时候.当添加一个租户的时候.那么租户是有一个单独的数据库.而我的并没有用多租户单数据库. 因此我的模块里面有一个领域事件 当租户添加时将生前表生成到对应的数据库中.如果那位网友有更 ...
- 如何将top命令输出重定向为文件
命令: # top -b -n 2 -d 3 > /tmp/top.out 解析: -b: batch 模式,可以重定向到文件中 -n:一共取2次top数据 -d:每次top数据间隔为3秒
- 扩展 KMP
扩展KMP解决这样一些问题: 给定两个字符串 S 和 T(长度分别为 n 和 m),下标从 0 开始,定义extend[i]等于S[i]...S[n-1]与 T 的最长相同前缀的长度,求出所有的ext ...
- BZOJ 3091: 城市旅行 [LCT splay 期望]
3091: 城市旅行 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1454 Solved: 483[Submit][Status][Discuss ...
- [Android] Toast问题深度剖析(二)
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者: QQ音乐技术团队 题记 Toast 作为 Android 系统中最常用的类之一,由于其方便的api设计和简洁的交互体验,被我们所广泛采用 ...
- CentOS上安装Git服务器
1.安装Git 打开控制台,执行以下命令进行安装 $ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel ...
- xml对象序列化
public static class XSerializer { /// <summary> /// 将对象序列化为xml字符串 /// </summary> /// < ...
- WPF字典集合类ObservableDictionary
WPF最核心的技术优势之一就是数据绑定.数据绑定,可以通过对数据的操作来更新界面. 数据绑定最经常用到的是ObservableCollection<T> 和 Dictionary<T ...
- nodejs http post 请求带参数
// We need this to build our post string var querystring = require('querystring'); var http = requir ...
- mac给文件批量添加后缀名
for i in *;do mv "$i" "$i.mp4";done