漫谈计算摄像学

计算摄像学(Computational Photography)是近年来越来越受到注意的一个新的领域,在学术界早已火热。本来计算摄像学的业界应用在群众中一直没什么知名度,直到Lytro公司推出了外观十分酷炫的光场相机,打着“先拍照再对焦”的噱头,这个学科一下子被很多研究领域以外的人开始注意到。那什么是计算摄像学呢?让我们看看清华大学和中科院的教授们怎么说[1]

“计算摄影学是一门将计算机视觉、数字信号处理、图形学等深度交叉的新兴学科,旨在结合计算、数字传感器、光学系统和智能光照等技术,从成像机理上来改进传统相机,并将硬件设计与软件计算能力有机结合,突破经典成像模型和数字相机的局限性,增强或者扩展传统数字相机的数据采集能力,全方位地捕捉真实世界的场景信息。”

这种定义虽然没什么错误,可其实相当于什么都没说。。个人觉得计算摄像学的定义得从一般的数码摄影对比着来理解。一般的数码摄影分为两个大步骤:1) 通过相机采集图像;2) 后期处理。而在每个大步骤里又有很多小的要素,比如1)里,需要考虑光照,相机角度,镜头组(光学系统),传感器等等,2)里的方方面面就更多了,降噪,调曲线,各种PS滤镜等等。如果这其中的每一个要素,我们都想办法进行拓展和改变。比如用特殊手段照明,可以从不同角度,或者按一定的时序打闪光灯,再或者用可见光之外的光。又比如改变光学系统,可以调整光圈大小,调整相机镜头位置,或是改变光圈形状等。而每一项采集图像的改变,往往都需要相应的计算机算法后期处理,甚至采集到的数据可以用除了普通显示器以外的方式呈现,那么前面这些一套的成像办法,就都可以归入计算摄像学的范畴。更笼统一下,就是拓展了传统数码摄影中的某个或多个因素的维度来成像的方法,就是计算摄像学。其实现在早就被用的烂熟的HDR就是计算摄像学中的一种办法,拓展的是传统成像中的光圈大小。那么,就当前计算摄像学的发展而言,这些拓展和改变都主要集中在哪些因素上呢?MIT的Raskar教授早就给出过结论:光学系统传感器照明后期处理[2]。作为漫谈计算摄像学的第一篇,今天要谈的光场,就是基于光学系统和后期处理上的拓展。

光场的定义

光场,顾名思义,就是关于光的某个物理量在空间内的分布。这个概念第一次被明确提出是在1939年A. Gershun的一篇论文中[3],后来被E. H. Adelson和J. R. Bergen在上世纪末的一篇论文中完善,并给出了全光函数(Plenoptic Function)的形式。简单来说,光场描述空间中任意一点向任意方向的光线的强度。而完整描述光场的全光函数是个7维函数,包含任意一点的位置(x, y, z),任意方向(极坐标中的Θ, Φ),波长(λ)和时间(t)。附上从Raskar教授的讲义里截的图:

在实际应用中,颜色和时间维度的信息通常是被RGB通道和不同帧表示,所以就光场而言,只关注光线的方向和位置就可以了,这样就从7维降到了5维。而再一般的,大部分成像系统中光线都是在一个有限的光路里传播,所以一种更简单的,用两个平面表示光场的方式被引入:

这种表示方式中,分别用两个平面上的两个点表示光线经过的两个点,这样一来光线的方向和位置都可以确定,并且维度降到了4个。注意到这样虽然简化了处理,可是局限性是,在实际应用中,两个平面都不是无限大的(即使是无限大也只能描述一半空间),光场可以描述的范围被两个平面的有效面积限制住了。

用数码相机采集光场

知道了光场的定义,那么是不是有什么专门的神奇设备能够在空间中采集这样的4维信息呢?没有的,光场虽然听上去比较高大上,可通常采集的办法还是传统的成像系统:相机。最经典的光场采集办法就是相机阵列,比如下图是Stanford Multi-Camera Array:

所以就是把相机排列在了一个平面上而已。为什么这样的相机阵列就采集了光场呢?我们先从最原始的针孔(Pinhole)相机模型谈起:

小孔成像模型是最直观也是最古老的成像模型,小孔相当于把光束的宽度限制得很小,所以如左图光束通过小孔之后再像面上成了一个倒像。这种成像虽然简单,然而一个重大不足是成像的分辨率被小孔大小限制着,小孔越小,则成像越清晰,然而光量也越小,像会很黯淡。为了成明亮的像我们希望光束的量大,也就是小孔大,但也不希望光束的不集中导致成像模糊,所以很自然的,凸透镜成像解决了这个问题。在凸透镜成像系统中,不过镜头怎么复杂,模式都是和中间的示意图一样,一个空间中的点发出的光束,打在透镜的一块面积上后,折射,然后汇聚到一点。所以单从光线采集的角度而言,和小孔成像系统的没有差别。那么这和光场的联系在哪呢,回顾前面说的用两个平面上的两点坐标表示广场的办法,如果我们这里把镜头中心所在平面看成uv平面,定义镜头中心为(0,0),而成像平面,也就是传感器所在平面看成xy平面,则在普通的成像系统中捕捉到的一幅图像可以看成是u=0, v=0出发的光线在传感器平面上的采样,也就是说我们采集了

L(0,0,x,y)|x,ysensor plane

其中每个L(0,0,x,y)的值就是传感器上的像素值。一个直观的例子是上图的第三个光路图,简化到二维情况的话,只看L(u,x),假设在传感器平面上有6个像素,那么采集到的6条光线就分别是L(0,-1), L(0,-0.6), L(0,-0.2), L(0,0.2), L(0,0.6), L(0,1)。那么很自然地,如果改变uv的位置,也就是镜头中心的位置,不仅能采集xy平面的光线,uv平面的也可以采集了,所以就能采集整个uv和xy间的光场了,所以相机阵列就相当于在uv平面上布满了很多采样点。

当然,上面说的是最直观最理想的情况,把相机近似成针孔模型还有个前提是景深足够,另外我的例子里xy平面是用传感器所在平面定义,另一种流行的定义方法是用相机的焦平面,也就是在镜头前方,也就是上图中的虚线箭头,这种方法相对来说就更为直观了,尤其是在假设焦距很小的情况下,虚线所在的平面就是相机平面距离为焦距的地方。事实上,在几何光学里,因为光线是严格直线传播,所以沿着光轴中心的不同位置上,如果都能采样的话,那么采到的像都是相似的,所以理论上讲uv和xy平面是可以沿着光路的中心轴任意位置定义的。另外,除了用x和y,也有很多学者喜欢用s和t描述像平面,不过这仅仅是字母使用习惯上的不同。

相机阵列只是采集光场的最基本模型,实际实现的系统都是基于相机阵列的原理,但是具体结构非常不一样。

Lytro

Lytro采用的是在传感器表面覆盖一层微镜头阵列[4]

微镜头阵列就是类似如下,近距离覆盖在传感器表面:

这个图是Lytro创始人博士论文里的原型机的阵列,(A)是阵列宏观的可视效果,(B)和(C)是微观结构,后来在Lytro中已经改进成了六边形的镜头阵列。一个Lytro在传感器成像的原始图片如下:

可以看到和相机阵列不同,Lytro采集到的图像是虚脱6边型构成的,不过其实背后的原理都是一样的,这一大幅看着像昆虫眼睛采到的图像是能够通过算法转化成前面提到的相机阵列等效图像的,而每一幅等效的图像又叫Sub-Aperture图像。和Lytro类似的还有Raytrix的光场相机,不过Raytrix的采样精度和采样数都大幅高于玩具般的Lytro,属于工业级光场相机。

Adobe Plenoptic Lenses

名字已经写得很清楚了,lenses,和Lytro还有Raytrix不同,Adobe的光场相机把光场采样镜头置于主镜头组前[5]

PiCam

这是个微缩版的相机阵列,用的就是手机上的那种镜头,4x4阵列,特点是用提出的算法优化了分辨率和深度图估计[6]

微缩相机阵列里还有一个例子是去年发布的华为荣耀6 Plus。

光场和3D

知道了光场的直观意义,那么很自然地就会想到和普通的照片比起来,获取的信息不再是一幅简单的2D像素阵列,而是三维空间中的光线,也就是说光场中是包含三维信息的。一个简单的例子来说明:

左边的例子是不同uv平面上的相机成像的差别,假设成像后焦平面都取相同的区域的话,可以看到因为uv的不同,所以不同距离上的物体在最终的图像上的位置也不一样,其实这个就是典型的视觉中的Stereo问题。另外既然提到了Stereo,也需要特别提到的是,在相机阵列采集到不同拍照位置的图像之后,有个非常重要的步骤叫做Calibration,也就是在选定的x平面上,要保证两个相机视野是重合的,如左图所示。那么深度的信息是如何获得的呢,来看下图:

假象我们可以保持右边的相机的光场不变,然后向左平移,使得蓝色的光线在成像面上重合,那么最终蓝色方块在两个相机成像的照片里位置就会完全相同,这其实就等效于把原始位置成的像向左移动了一段距离,然后和左边相机成的图像叠加,那么就会发现蓝色方块重合了。类似的,如右图所示,如果把右边相机成的图像向左移动一大段距离,那么更远的绿色三角图像就重合了,要想是不同位置的物体重合就要对应不同的移动距离,而这个距离实际上是和物体到镜头的距离相关的,通过移动距离和相机采样点之间距离的比值就可以轻易求出,进而就相当于我们得出了蓝色方块和绿色三角的深度信息。顺带提一句,让蓝色方块和绿色三角重合的过程其实就已经是所谓的先拍照后聚焦的聚焦过程了,这篇文章不会展开来讲。那么再回到第一幅图中的插值问题,如何通过两个相机得到的图像求出一个虚拟的在两个相机之间的图像呢?

以绿色三角为例子,因为我们用的是镜头前像平面的二维例子,所以这里用L(x,u)表示入射到虚拟位置的光线,则有

L(x,u)=λ0L(x0,u0)+λ1L(x1,u1)

其实就是以虚拟位置到已有采样位置的距离为权重的线性插值。那具体到采集到的图像这个过程是怎么实现的呢,在相机阵列中需要注意的一点是不仅仅是相机采样是离散点,图像因为是像素构成的所以也是离散采样。示意图如下:

所以实际上用来插值L(u,x)的光线采样有4条,公式如下:

L(x,u)=λ0L(x00,u0)+λ1L(x01,u0)+λ2L(x10,u1)+λ3L(x11,u1)

其中

λ0=(1|xx00||x01x00|)(1|uu0||u0u1|)

λ1=(1|xx01||x01x00|)(1|uu0||u0u1|)

λ2=(1|xx10||x11x10|)(1|uu1||u0u1|)

λ3=(1|xx11||x11x10|)(1|uu1||u0u1|)

这是二维光场的情况,如果实际应用中需要对4维光场插值,则这个公式一共涉及到16条光线,下面是个示意图:

公式看上去很复杂,不过直观地理解也不困难,每根光线前的系数里,和u有关的部分就是指将图像按照相机采样位置差异进行移动的幅度,也就是把采到的图像进行平移(如下图),而和x有关的部分就是在传感器上对光线通过的位置进行插值。利用深度信息的辅助,在整幅图像上进行这个过程就能得到一个没有采样点上的虚拟相机采到的插值图像。

来做个简单的实例试一试,用手机拍9幅照片,也就是3x3的采样:

接下来是前面提到的Calibration,以中心的字母U作为聚焦平面,并且重新构图裁剪画面:

做Calibration的过程中可以得到照片拍摄时的位置信息:

可以看到由于手持手机的误差,我的采样位置是很不规则的,不过能大概看出是在“田”字格上采样,除了位置信息还能提取出深度信息,提取深度的算法有很多,为了方便我这里使用的是最原始的disparity比较:

接下来进行采样插值,我采取的策略是在每四个采样点之间进行Quadrilinear采样:

采样的效果怎么样呢,沿着我的采样点我画了条轨迹试试,起点和终点分别是左下角和右下角的采样点,把对应的插值图像提取出来,轨迹和对应的动图如下:

在上一篇直观理解光场中,谈到了光场的基本概念、3D性质、实际应用中的采集办法和插值求任意光线的办法。这一篇继续上一篇的基础上给出利用光场实现“先拍照后聚焦”的原理和基本步骤。

对焦与光路

首先,什么是对焦呢,我们先简单回顾一下中学物理。

先看左图,物体端的对焦面就是最上方的平面,从这个平面上的每一点发出的光线最后都汇聚在另一端的像平面上,一个典型的光路如加粗的四色直线所示。如果希望物体端的焦面移动到和原焦面到透镜之间的位置,可以看到光线仍然是那些光线,但是聚焦到像面的光线组合就不再是之前的光线了,比如右图里,加粗的光线除了红线以外,黑绿蓝三色的光线都不再是原来的那几根。对应对焦的基本光路,再回来看光场,根据上一篇文章中介绍过的光场的基本原理,很自然的,我们会想到,只要把在一个物平面上发出的光线所对应的像素叠加在一起,不就实现了重聚焦了吗?事实上这就是最简单的基于光场的重聚焦算法,叫Shift-and-Add[1]

先拍照后对焦的算法

还是借助上一篇文章中的配图来讲解Shift-and-Add算法:

如左图所示,在原始的采集位置上,蓝色光线在两幅采集到的图像里分别对应于不同的位置,所以如果要对焦于蓝色的方块,则需要将他们的相对位移消除,这一步就是Shift,然后在把两个像素的平均值求出作为对焦后的新图像的像素值,则得到了对焦于蓝色方块的图像。同样道理,对于更远的绿色三角,则进行更大距离的位移来消除对应像素之间的相对距离,然后叠加得到新的对焦于绿色三角的图像。需要注意的是,如上面的小图所示,移动叠加之后,边缘部分总是有些像素是不重合的,所以或多或少都会形成瑕疵。

具体到上篇文章里手机拍的照片例子,就是按照每张照片采样位置相对于中心位置进行等比例的移动,就可以得到在不同物平面上重聚焦的图像,比如我们选取9个采样点的中心点作为中心位置的话,将其他8个采样点放置到不同位置上,就对应得到不同的重聚焦图片:

绿圈位置对应图像:

蓝圈位置对应图像:

就这么简单。那么,Lytro中的算法是不是Shift-and-Add呢?答案是否定的,Lytro的算法是把平移-叠加这种空域的算法放到了频域执行。基于的原理叫做中心切片定理,这里只简单提两句,中心切片定理是二维的,不过其基本原理可以拓展到任意维度,Lytro中用的是其在4维时的应用。简单来说就是把4维的光场进行傅里叶变换之后,在4D的傅里叶空间内,不同位置的重聚焦图片分别对应一个穿过中心的不同角度的二维傅里叶空间的插值切片的逆傅里叶变换。所以本质上而言,这种办法和Shift-and-Add没有区别,只不过是把线性操作换到了频域空间。shift-and-Add每次产生新的重聚焦图片时都需要用到所有采集的光场信息,算法复杂度是 O(n4)。而如果是从变换后4D数据里产生新的重聚焦图片,则分为两步:1) 求插值得到2D的傅里叶空间切片,复杂度是 O(n2);2) 二维傅里叶逆变换,复杂度是 O(n2log⁡n),当然为了得到4D的傅里叶变换还有一步初始化计算,复杂度是 O(n4log⁡n)。所以在已经有了采集到的4D数据需要不断生成新的重聚焦图片的场景下,在频域的重聚焦算法时间上更经济一些。更多关于频域重聚焦算法的详细,有兴趣的朋友可以参考[1]

另外特别要提的一点是,在这种Shift-and-Add框架下的重聚焦算法,和实际相机成像的图片是有区别的。原因就是第一节中对焦与光路部分。可以看到在凸透镜光路中,不同位置上对焦的光线是互相不平行的,而Shift-and-Add算法下,所有光线都被认为是“平行”移动的,所以在重聚焦后的照片中,虚化的部分图像是不一样的,然而这种差距对于人眼来说,其实也没那么大差别。

插值法去重影

可能有的朋友看到这里已经发现了,虽然重聚焦是完成了,可是重对焦后图像的质量并不好,比如上一节中对焦在Dell标志上的一张:

花朵的部分有很明显的重影,和用相机镜头照出来的显然不一样。通过前面部分的原理讲解,这个原因也是很显然的:因为只有9个采样点,在移动-叠加的过程中,不同图像对应像素的移动超过了一个像素,则叠加后的图像就会出现这种类似于重影的瑕疵。其实这个问题解决起来也很简单,记得在上篇文章中,已经讲过如何通过插值得到虚拟位置采样的图像,所以很自然地,我们只要通过插值,让采样点更密,密到每一个采样点和相邻采样点的图像上的对应像素的位移都小于或接近一个像素,那么视觉上这种重影的现象就可以消除了。得到的结果如下:

最后来个连续变焦的动图:

光圈的模拟

许多人在用传统相机拍摄“虚化”照片时喜欢通过调整光圈来控制虚化的程度。这在基于光场的重聚焦中也是可以模拟的,道理很简单,就是将采样的范围调整就可以了。还是用上一篇文章中的例子,比如用所有的采样点(包括插值得到的):

得到的图像:

而如果只采用中间一小部分的采样点的话,相当于小光圈:

则得到虚化程度比较低的图片:

[1] R. Ng, "Digital Light Field Photography," PhD thesis, Stanford University, Stanford, CA (2006)


参考文献:

[1] http://wenku.baidu.com/link?url=ViSzmcYvSZNN-NYa-mxlqy8hnKJWxqj1hukSUYLIuVm79LUjYG54dfEOZTHVDGeMwsd4hFMTUepFMnsVLINlZ1o0-s5oGucwWg4o4RlejYG

[2] http://web.media.mit.edu/~raskar/photo/

[3] A. Gershun, “The light field,” J. Math. Phys., Vol. 18, pp. 51–151, 1939

[4] R. Ng, "Digital Light Field Photography," PhD thesis, Stanford University, Stanford, CA (2006)

[5] T. Georgiev, A. Lumsdaine, "Focused plenoptic camera and rendering," Journal of Electronic Imaging 19(2), 2010

[6] K. Venkataraman, et. al "PiCam: An Ultra-Thin High Performance Monolithic Camera Array," ACM Transactions on Graphics(SIGGRAPH) 2013

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java安全漫谈是一本关于Java安全的书籍,深入探讨了Java应用程序在网络环境中的安全性和相关的安全漏洞。该书内容涵盖了Java安全基础、Java虚拟机的安全机制、Java安全管理、Java安全开发等方面的知识。 首先,Java安全基础部分介绍了Java安全模型的原理和特点,包括Java类库的安全特性、权限管理和访问控制、安全策略配置等。这部分内容可帮助开发人员了解Java应用程序的安全需求,并提供相应的解决方案。 其次,Java虚拟机的安全机制是Java应用程序的基石。该书介绍了Java虚拟机的安全沙箱和类加载机制,并讨论了如何利用这些安全机制避免恶意代码的执行和隐患的防范。 此外,Java安全管理部分从用户角度出发,介绍了Java应用程序的安全管理工具和技术,如Java安全策略文件、权限管理和安全认证等。开发人员可以通过合理配置和使用这些工具来提高Java应用程序的安全性。 最后,该书还涉及了Java安全开发过程中的一些最佳实践和常见安全漏洞,如输入验证、跨站脚本攻击(XSS)、SQL注入、跨站请求伪造(CSRF)等。通过习和掌握这些知识,开发人员可以编写出更加安全的Java应用程序。 总而言之,Java安全漫谈是一本全面讨论Java安全的书籍,内容涵盖了Java安全基础、Java虚拟机的安全机制、Java安全管理和Java安全开发等方面的知识。它对于开发人员和安全从业人员来说,都是一本重要的参考书,有助于提高Java应用程序的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值