array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 HDR Tone Mapping - 爱码网

在游戏引擎渲染管线中,我们对于R、G、B通道颜色信息的数值范围通常设置在[0,1]之间(或者是[0,255])。其中,0代表没有光亮度,1代表显示器能够显示的最大光亮度。这个表示方式虽然直接易懂,但它并不能反映真实世界中光亮度的情况。在真实世界的光照环境中,光亮强度有时候会超过显示器能够显示的最大亮度。而且,人眼在观察真实世界的物体时,会根据光照强度进行自我调节。因此,更加真实的渲染方式是让颜色值超过1。这种光照计算方式或环境光照图就是我们常常在游戏引擎中看到的HDR(High Dynamic Range)光照或者HDR环境贴图。但是,采用HDR渲染出来的亮度值会超过显示器能够显示最大值。此时,我们需要将光照结果从HDR转换为显示器能够正常显示的LDR。这一过程我们通常称之为Tone Mapping。下图是Unity引擎对采用HDR渲染的图片使用了Tone Mapping和没有使用Tone Mapping的对比结果:

HDR Tone Mapping
其中,上图是没有使用Tone Mapping的结果,下图是使用了Tone Mapping的结果。可以看到,在没有使用Tone Mapping的渲染结果中,有很大一部分像素的光亮度是超过了显示器能够显示的最大值。在视觉上,这些地方变得过曝了。而在使用了Tone Mapping的渲染结果中,像素光亮度变得正常,视觉上也更加真实。

今天我们要介绍的这一篇论文是于2002年发表在Siggraph会议上的论文“Photographic Tone Reproduction for Digital Images”。这篇论文提出了一种新的Tone Mapping的方法,使得经过该方法转换的结果从视觉上看起来更加接近真实世界的物体。首先,我们来看看这篇论文的结果图,如下图所示:

HDR Tone Mapping
其中,左图是采用线性缩放的结果,右图是采用论文中的算法进行转换的结果。可以看到,在简单的线性缩放结果中,许多细节部分丢失了;而论文算法转换的结果则很好地保留了图像的细节部分。接下来,我们将对论文中的算法部分做详细介绍。


一、初始光亮度映射

首先,文章作者对整个图像做了一个光亮度的映射,其作用类似于设置相机的曝光。这一操作实际就是对每一个像素做固定缩放。根据前人对Tone Mapping的研究结论,论文作者认为光亮度的log平均值能够反映图片中像素光亮度的特征。因此,作者用该值对每个像素作缩放。

若用Lω(x,y)表示像素(x,y)的光亮度,则log平均值可表示为:

HDR Tone Mapping

其中,N 表示像素个数,δ 是一个用于避免奇异值的常数。缩放后的光亮度 L(x,y) 可用如下公式表示:

HDR Tone Mapping

其中,α 是一个缩放参数,被称为Key Value,不同的 α 值对应了不同的缩放程度,如下图所示:

HDR Tone Mapping

但是,仅仅做简单线性缩放是不够的。对于光亮度变化不是很大的图片,这种方法可以将像素的光亮度很好地压缩到一定范围,但是对于大多数图片,绝大部分像素光亮度是在某一个范围之内,而少数高亮的像素比平均值高太多,很容易产生过曝,如:光源、高光反射等。因此,通常在经过线性缩放之后,还需要利用非线性的算子对图像进行处理。文中作者列举了一种常用的算子:
HDR Tone Mapping

其中,Ld(x,y)表示经过非线性算子处理后的像素,Lwhite表示图片中被映射到白色亮度的像素中的最小值。由于是非线性的,对于亮度高的像素缩放更大,因此该公式能够防止线性缩放中无法处理的过曝情况。但是,这种简单的算子通常容易导致细节丢失。作者观察到,在传统打印技术中,为了提高打印结果的质量,通常会采用一种dodying-and-burning的方法。该方法的原理是根据打印内容的不同,在不同区域减少光亮度(dodying)或者增加光亮度(burning)。论文作者通过实验,对比了简单非线性映射以及dodying-and-burning处理后的结果,如下图所示:
HDR Tone Mapping

其中,上排图片中太阳被树枝遮挡住,因此不包含高亮的区域,下面的图片则包含高光反射。左边一列图片同样是采用简单非线性算子(Simple Operator)缩放,经过观察可以发现,下图中的书中文字完全被高光覆盖。由此可见,简单的非线性算子缩放会丢失很多细节。

论文作者在经过观察和测试之后,基于dodging-and-burning方法,提出了一种自适应的dodging-and-burning方法,下面我们将详细说明。


二、自适应dodging-and-burning

自适应dodging-and-burning的特点是,找出对比度大的边缘包围的区域,然后对该区域进行处理。因此,作者提出利用高斯核卷积的方法来找出这些区域。对于不同的缩放系数 s,在不同的像素点(x,y),计算高斯核函数 Ri(x,y,s)与图像 L(x,y)的卷积。则卷积结果 Vi(x,y,s)可表示为:

HDR Tone Mapping

其中,Ri(x,y,s)可表示为:

HDR Tone Mapping

然后,论文作者定义了一个误差函数,计算不同 αi 参数的卷积结果之差,来衡量图像局部像素的光亮度分布。则误差函数 V 可以表示为:

HDR Tone Mapping

通过对不同的缩放参数 s 进行计算,找出符合如下公式的参数:

HDR Tone Mapping

其中,ϵ 是一个阈值,sm 是对每个像素计算出的缩放参数。当我们获得每一个像素的缩放参数后,对每一个像素进行不同的缩放计算:

HDR Tone Mapping

从而获得最终的Tone Mapping结果。下图显示了计算过程:
HDR Tone Mapping

其中,左图显示了计算缩放参数的过程,Center表示内圈高斯计算的范围,Surround表示外圈高斯计算的范围。右图显示了用不同缩放参数进行缩放后的结果。通过观察可以发下,当缩放太小时无法有效地提取出图像细节,而缩放太大时会出现黑色的Artifacts。


三、实验对比

论文作者将dodging-and-burning计算结果与前人的结果进行了对比实验。如下图所示:
HDR Tone Mapping
HDR Tone Mapping
HDR Tone Mapping
其中,New operator表示了论文的实现结果。


四、总结

论文作者提出了一种新的Tone Mapping的算法,它通过对dodging-and-burning打印技术的观察和分析,对于不同的区域采用不同的缩放系数,提出了自适应dodging-and-burning的方法,能够将高动态图转换成低动态图时防止高亮部分过曝,并且能达到在亮部和暗部都能保持细节的目的。


五、论文信息

作者信息:
Erik Reinhard,著名计算机图形学学者,目前在Technicolor Research and Innovation做研究工作;
Michael Stark,计算机图形学研究者,曾就读于美国犹他大学;
Peter Shirley,著名计算机图形学大牛,真实感渲染专家,犹他大学客座教授,NVidia首席科学家;
James Ferwerda,著名计算机图形学学者,罗彻斯特理工学院副教授。

论文链接:
http://www.cmap.polytechnique.fr/~peyre/cours/x2005signal/hdr_photographic.pdf

相关文章: