高动态范围(High-Dynamic Range,简称HDR)
一.HDR介绍
高动态范围(High-Dynamic Range,简称HDR),又称宽动态范围技术,是在非常强烈的对比下让摄像机看到影像的特色而运用的一种技术。 当在强光源(日光、灯具或反光等)照射下的高亮度区域及阴影、逆光等相对亮度较低的区域在图像中同时存在时,摄像机输出的图像会出现明亮区域因曝光过度成为白色,而黑暗区域因曝光不足成为黑色,严重影响图像质量。摄像机在同一场景中对最亮区域及较暗区域的表现是存在局限的,这种局限就是通常所讲的“动态范围“。HDR图片是使用多张不同曝光的图片,然后再用软件组合成一张图片。它的优势是最终你可以得到一张无论在阴影部分还是高光部分都有细节的图片。在正常的摄影当中,或许你只能选择两者之一。
广义上的“动态范围”是指某一变化的事物可能改变的跨度,即其变化值的最低端极点到最高端极点之间的区域,此区域的描述一般为最高点与最低点之间的差值。这是一个应用非常广泛的概念,在谈及摄像机产品的拍摄图像指标时,一般的“动态范围”是指摄像机对拍摄场景中景物光照反射的适应能力,具体指亮度(反差)及色温(反差)的变化范围。
宽动态摄像机比传统只具有3:1动态范围的摄像机超出了几十倍。自然光线排列成从120,000Lux到星光夜里的0.00035Lux。当摄像机从室内看窗户外面,室内照度为100Lux,而外面风景的照度可能是10,000Lux,对比就是10,000/100=100:1。这个对比使人眼能很容易地看到,因为人眼能处理1000:1的对比度。然而以传统的闭路监控摄像机处理它会有很大的问题,传统摄像机只有3:1的对比性能,它只能选择使用1/60秒的电子快门来取得室内目标的正确曝光,但是室外的影像会被清除掉(全白);或者换种方法,摄像机选择1/6000秒取得室外影像完美的曝光,但是室内的影像会被清除(全黑)。这是一个自从摄像机被发明以来就一直长期存在的缺陷。
HDR可以令3D 画面更像真,就像人的眼睛在游戏现场中。在HDR的帮助下,我们可以使用超出普通范围的颜色值,因而能渲染出更加真实的3D场景。
HDR是一种表达超过了显示器所能表现的亮度范围的图像映射技术,已成为目前游戏应用不可或缺的一部分。通常,显示器能够显示R、G、B分量在[0, 255]之间的像素值。而256个不同的亮度级别显然不能表示自然界中光线的亮度情况。比如,太阳的亮度可能是一个白炽灯亮度的几千倍,是一个被白炽灯照亮的桌面的亮度的几十万倍,这远远超出了显示器的亮度表示能力。
想象在一个房间中,刺眼的阳光从窗外照进来,若使用常规方法渲染这个房间,房间中白色的墙壁的颜色是(255, 255, 255),阳光的颜色也是(255, 255, 255),墙壁将表现得和窗外的阳光颜色一样。很明显,这和我们现实看到的差异很大,现实场景中阳光要比墙壁刺眼很多,我们需要使用某种技术对阳光的亮度和墙壁的亮度进行处理,让其在显示器上的效果接近现实效果。
简单的将高范围的亮度按比例缩放后映射到[0, 255]是不可行的,比如将[0, 511]的范围按照2:1映射到[0, 255],虽然表示的亮度范围扩大了,但是将导致色带(Color Banding)问题,色带如图1所示。
图1 左图有色带问题,右图显示正常
在有限的亮度范围内显示自然界中相当宽广的亮度范围,正是HDR技术所要解决的问题。
何时应开启HDR?
风景照
HDR功能的一项经典应用就是蓝天白云下的风景照。开启HDR后可以让天更蓝,草更绿。不过唯一的的例外是日出和夕阳,由于HDR功能会对太阳的曝光亮度做出错误判断,反而会丧失了原有的动人色彩。
户外人像
大太阳下拍摄人像往往不是件容易的事情,逆光拍摄经常会导致黑脸或黑眼圈,顺光时则容易出现皮肤或高亮度物体过曝现象。HDR功能对这些问题的解决效果相当好,但使用时需要一些技巧。
图2
图中的四幅照片,左上为直接拍摄,右上为开启HDR拍摄,左下为触摸对焦至人物面部,右下则是触摸对焦后再开启HDR的结果。结果很明显,在遇到户外背光人像的拍摄状况时,我们应当首先将对焦点选择在人物面部,然后再使用HDR功能拍摄,让人物和背景都能有一个合适的曝光水平。
准备进行后期处理
如果你准备对拍摄的照片进行后期修改处理,那么HDR照片会帮助你保留原始图片中的更多细节。如果你不满意HDR模式导致的饱和度和对比度下降,只要在Photoshop等软件中稍作调节即可。
何时应关闭HDR?
拍摄运动物体
HDR模式下会连拍三张照片并进行合成。虽然连拍速度很快,但如果拍摄对象正在运动当中,合成的照片还是会出现重影现象。如果你经常碰到这种状况,苦练稳手功和尝试三脚架是唯一的解决方案。
高对比度照片
很多照片的意境都要通过鲜明的亮暗对比来实现。比如在专门拍摄阴影、倒影时,开启HDR都只会让对比度降低,失掉预想的效果。
捕捉鲜艳色彩
图3. 右侧为开启HDR效果
HDR模式可以找回暗部和亮部的色彩,但是当拍摄对象本身就明亮鲜艳时,开启HDR只会导致饱和度降低。比如,同样是拍摄风景照,但你要拍摄的主体是蓝天,并不在乎地面出现阴影的时候,关闭HDR就能让天色看起来更蓝。
闪光灯照相
使用闪光灯时不需要使用HDR技术。当你使用外部光源照亮暗部物体时,也一定要保持手持平稳或使用三脚架。
二.HDR技术方案
1. HDR渲染步骤
1)将整个场景渲染到一张浮点纹理上(16bit或32bit都可以);
2)色调映射(Tone Mapping);
3)渲染泛光(Bloom)效果;
4)将泛光和色调映射的结果进行叠加。
第一步很简单,只需要硬件支持浮点纹理即可,比较重要的是本文重点介绍的2、3两步,最后将2、3两步的结果进行叠加,形成最终效果图。
【显示设备上[0, 255]的亮度范围在着色器程序中使用[0, 1]的浮点数表示,下文的亮度和颜色值表示均使用着色器程序的标准。在算法中都用到了亮度的计算,每个像素的亮度的计算方法是L=0.27R+0.62G+0.06B】
2. 色调映射
色调映射是在有限动态范围媒介上近似显示高动态范围图像的技术。对于人眼来说也有类似的映射方式,因为人眼对亮度的感知范围远低于自然界的亮度范围,只能感知到某个范围内的光照。和显示设备不同的是,人眼对光的感知范围是动态变化的,例如从光亮的室外环境突然走入一个黑暗的室内环境,刚刚开始一片漆黑,过一会儿才可以看清周围环境,人眼的这个调节过程叫做光适应(Light Adaptation)。所以要模拟出真实的光照效果,除了表现出合适的光照,还需要模拟出人眼对光线的调节过程。
最简单的色调映射是将亮度超过1的值置为1,这种做法会出现文章开始提到的墙壁和阳光一样亮的问题;另一种简单的色调映射是将每个像素的除以最高亮度像素的亮度值,可以很好的将所有像素的亮度映射到[0, 1]之间,这种方法会导致场景中某些特别亮的像素会导致场景中的其他部分特别暗。比较好的方式是采用平均亮度值进行调节,由于平均亮度值反映了场景中的整体亮度,所以受到场景中少部分过亮或过暗的像素影响不大。
2.1 计算平均亮度
计算平均亮度的公式为:
该公式先对亮度取对数,平均后再进行幂运算。之所以不是直接对亮度平均,而是取了对数,是为了防止过亮的像素对整体造成的影响过大,该公式来源于参考文献1。
计算平均亮度的最简单的方法是遍历所有像素,用上述公式求平均值。该方法需要CPU完成,效率不高,DirectX的“HDRLighting”例子采用了一种基于GPU加速的方法,利用像素着色器多次DownSampling,最后求得平均值,具体流程如下:
1)首先将场景渲染到纹理中,在此基础上,对该纹理取样并计算相应像素亮度的ln()值并进行平均(相当于上述公式去掉exp),存入64*64的纹理中;
2)对上一步的纹理4*4 DownSampling,生成16*16的纹理;
3)对上一步的纹理4*4 DownSampling,生成4*4的纹理;
4)对上一步的纹理4*4 DownSampling,生成1*1的纹理,并计算其exp()值。
最后生成的1*1的纹理中的像素为公式中要求的平均亮度Lavg。
2.2 光适应
为了模拟人眼对于不同光强会自动调节适应范围的效果,只需要对这一帧求出的平均亮度Lavg与上一帧的平均亮度Lavg进行插值即可,当然这个插值不是线性插值,“HDRLighting”中的代码如下:
float fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * ( 1 - pow( 0.98f, 30 * g_fElapsedTime ) );
其中,fAdaptedLum为上一帧的Lavg,fCurrentLum为当前帧的Lavg,g_fElapsedTime为当前帧和上一帧的时间间隔,fNewAdaptation为最终Lavg的计算结果。
2.3 计算缩放因子
场景的整体亮度可以通过缩放因子进行调节,公式如下:
其中Lscale(x,y)是当前像素的亮度值。Key是一个常数,Key 的大小决定了映射后场景的整体明暗程度,一般取0.18(在伽马校正理论中,0.18经过校正后大概是0.5,也就是我们感官上的中等灰度级)。Key值的选择可以看作摄像机的曝光程度,我们可以使用这个公式控制自由的摄像机的曝光程度,Key越大整个场景就显得越白。一般来说,高曝光的Key最高为0.72,低曝光的Key最低为0.045,一般程度的曝光Key选择0.18附近的值。
2.4 归一化处理
到此为止,色调映射已经基本完成,剩下的只需要将Lscale(x,y)映射到[0, 1]范围内即可,公式如下:
其中其中Color(x,y)是当前像素的颜色值。
3. 渲染泛光效果
泛光是一种光学效应,它是指在来自于强光源的光线看起来像是影响到了周围物体。想象一间房间,窗户外面阳光明媚,若往窗外看去,感觉窗户光亮的边缘有一圈模糊,这就是泛光效果。在游戏中适当的增加泛光效果,能够增强画面的真实感。
渲染泛光效果的思路很简单,主要分为两个步骤,第一步是使用bright-pass filter提取出场景中高亮部分,第二步对高亮部分进行模糊处理。"HDRLighting"中bright-pass filter的代码如下:
1 // Determine what the pixel's value will be after tone mapping occurs
2 vSample.rgb *= g_fMiddleGray/(fAdaptedLum + 0.001f);
3
4 // Subtract out dark pixels
5 vSample.rgb -= BRIGHT_PASS_THRESHOLD;
6
7 // Clamp to 0
8 vSample = max(vSample, 0.0f);
9
10 // Map the resulting value into the 0 to 1 range. Higher values for
11 // BRIGHT_PASS_OFFSET will isolate lights from illuminated scene
12 // objects.
13 vSample.rgb /= (BRIGHT_PASS_OFFSET+vSample);
第二步则是对第一步的结果进行模糊,首先对第一步的结果进行2*2或4*4的downsampling,再使用2*2的高斯核心对其进行模糊。其中先对图像downsampling再模糊的做法是利用GPU进行图像模糊的一种提高性能的方法,因为downsampling后图像分辨率降低了,计算量自然就少了;而downsampling后的图片再放大,本身又是一种模糊,可以减少高斯模糊的采样数量。最终效果如图2所示
图4. 图片来源于微软DirectX SDK中“HDRLighting”例子,左图为过度曝光的场景,中间图片为bright-pass filter处理后的结果,右图为模糊之后的效果
4. 融合
现在需要将色调映射的图像与泛光的图像进行融合。在融合操作中除了常见的α融合外,还有一种叠加(Additive Blending)操作,它可以将两种颜色的值进行加法操作,通常会使得颜色越变越白,这正是我们所要的效果。将色调映射的图像与泛光的图像进行叠加操作,即可生成最终图像。
5. 最终效果
“HDRLighting”中LDR和HDR的效果对比如图3所示。
图5. “HDRLighting”中LDR和HDR的效果对比,左图为LDR,右图为HDR
其他的一些HDR渲染效果如图4-7所示。图4中很明显的观察到汽车窗户的镜面光,图5中蓝色的灯光显得比较亮,但是暗的地方也很清晰;图6和图7来自游戏“孤岛危机”,效果相当不错,其中就有HDR的功劳(当然要做到这样的画质,HDR只是冰山一角)。图6场景明暗得当,透过树叶可以看到天空略微模糊;图7中可以看到爆炸产生的碎片以及车上的显示屏有泛光效果,充分体现了亮度的差别,而这些细节让游戏更加逼真。
图6. Unity3D文档中的HDR渲染效果图1
图7. Unity3D文档中的HDR渲染效果图
图8. “孤岛危机”截图1
图9. “孤岛危机”截图2