序
Gamma的概念在我们的CG工作中很少得到重视和深入的认识,而实际上这个环节又极具意义,因为我们的工作结果总是有太多的不一样,得不到标准化的统一,所以这是我写这篇文章的主要原因,为此,我也放下了Vray全面详解的写作进度,转而把精力放在了LWF的研究中来,意在和大家共同探讨在线性工作空间进行制作的可行性和其意义,文中谈到Gamma的概念是比较抽象和相对化的,有很多相对的理论,需要读者仔细思考,当然,由于本人水平有限,错误之处在所难免,欢迎批评指正。
第一节 颜色的真实性
我们应该感谢上帝给予了我们生活的世界众多美丽的色彩,并让我们可以用自己的肉眼以极其真实的体验来感觉它们,当然,我们并不满足于此,对于从事CG工作的我们而言,把这些丰富的色彩真实地还原到计算机图像中才是我们关心的。然而,把世界中尽乎无穷的颜色表现在计算机世界中却并不简单。
首先,物质世界的颜色是无穷连续变化的,是一个线性量,但人的眼睛对亮度的感觉却并非呈线性分布,而是呈指数分布的。人眼只是对亮度的比率敏感,而并非对亮度本身敏感,我们观察到的亮度从0.10到0.11之间的差别与0.50到0.55之间的差别是一样的。这种非线性在日常生活中很容易感觉,比如你把灯泡功率从20W调到80W再调到140W,你会发现20W到80W之间亮度的增加比后一次调节来得更大。所以,当真实世界中线性无穷的颜色量到达人眼时,它们实际上被人眼感觉的非线性做了一次“校正”,只是这种“校正”从某种意义上说是错误的背离真实的,但我们自身无法避免,这是人类眼睛的特质,没有办法,所以我们只能对源色彩向相反的方向进行指数校正(也就是让颜色不呈线性分布,而呈指数分布),来让我们觉得亮度分布均匀。
上面的论述所提出的校正,基于这样一个事实,我们真实的源是真实世界中的颜色,这是标准,我们所做的校正,是让眼睛看到的东西尽可能贴尽真实世界。 然而,把情况放到实际CG应用中来,就有更多变化:
一、没有人关心也没有人知道源世界真实颜色到底应该是什么样,我们所提及的真实颜色,都是在眼睛看到以后的结果,所以,我们在CG制作中,真实的标准是眼睛看到真实世界后的结果。
二、CG制作中颜色的变化和失真发生在多个环节: 1. 从真实世界采样信息到计算机过程中的失真 2. 从计算机软件中制作生成的格式转换中的失真
3. 从计算机数字化图像到物理显示设备转换中的失真 所以我们的校正也要针对不同情况,考虑的问题更多。
在一般情况下,CG制作主要分为两种情况,一种是完全的数字化从无到有的创作过程(比如你在三维软件中从无到有建模,打灯光,渲染输出),另一种需要对现实世界采集信息并加工处理(比如你用一台单反胶片或数码相机拍下一张照片并导入到计算机中来进行处理,此后有可能拿到三维软件中作为一张贴图来使用),就第一种情况而言,因为不需要从现实环境中采样数据,所以我只需考虑失真的后两种情况,即制作生成的格式转换中的失真和数字化图像和物理显示设备之间的转换失真 。
第二节 Gamma和Gamma的问题
设想一下,当我们开始用电脑制作某CG内容时,我们首先是通过电脑显示器来与应用程序之间发生交互和信息交换的,如果显示器本身不能很好的还原数字化内容本身的真实颜色,也不能准确显示标准的颜色,那么这就意味着,只要你开始选择一个颜色,就是错误的。然后接下来不管怎么样都会是错误的。
这样,我们就得明白一个问题,显示器为什么会失真,我们如何校正?
拿CRT显示器来说,显示器的亮度变化是因为其输入电压发生变化,但是由于输入电压的变化函数和亮度的变化关系是不成正比的,这就存在了失真。
说得通俗点就是,当显示器要表现一数字化图像内容时,假如我们这时把这个内容看成是一个线性连续量,这时显示器的电压变化就不能很好的表现这个连续量,就出现了失真。换句话说,我们可以这样理解,显示器在显示那个数字化内容时,做了一个不正确的校正,非常巧合的,这个校正的函数关系也是指数关系。工业上我们一般把显示器的这种错误校正或者说失真度,用一个参数来衡量,那就是Gamma。
如果我们把显示设备要显示的原始数据称之为输入(Input),把原始数据通过显示设备后显示出来的结果称之为(Output),那么它们之间的关系实际就是:
Output=InputGamma
不难发现,这就是一个指数关系,而输出的结果,实际上就是给输入做了一个gamma值大小的指数级映射变化,Gamma,也就是衡量了这个指数变化的程度,当Gamma为1时,也就是Output=Input,因此,如果Gamma值为1就意味着不发生改变,或不校正,不失真,输入和输出相等,而Gamma值越大时,失真也就越大。
事实上,不同的CRT显示器其失真度都不相同,也就是Gamma值都不尽相同,但一般来说都是2.2-2.5这个范围,假如一个显示器的gamma值为2.5,这意味着什么呢,就是一个线性连续图像在显示时会被做一个gamma2.5的错误校正,或一个gamma2.5的失真,线性分布的图像会变成指数分布的图像,就像下面这个例子,当我们输出以下这个黑白渐变:
(原始黑白渐变图像)
由于CRT显示器的gamma2.5特性,图像将变成下图所示情况:
可见,显示器的这种错误“校正”使得中性灰在指数关系下变黑了,总体的表现就是暗部增加,图像整体变暗,暗部细节丢失。
那么,知道了错误发生的症结,我们该如何校正这一错误呢?由于显示器的Gamma是显示器的固有特性,我们是无法改变的,所以,思路应该是这样,既然显示器做了一个gamma2.5的改变,而我们需要的是让Gamma保持为1,这样输出结果就是无失真的,那么我们只要再显示器输出过程之前多做一次Gamma校正,让最终的Gamma值为1就可以了。也就是: Display_Gamma=CRT Gamma * 校正Gamma=1
以CRT Gamma为2.5为例,那就是要做一个Gamma0.4的校正,这样
Display_Gamma=2.5*0.4=1
在计算机系统中,在显示器之前做的这个Gamma校正事实上由显卡完成,但问题在于,上述的例子是我们事先知道显示器CRT_Gamma为2.5的情况下,我们用一个Gamma0.4来做校正,但显卡并不知道我们的显示器实际是什么Gamma值,更坏的情况是,也许做为用户
的我们,自己都不知道自己的显示器CRT_Gamma为何值。
操作系统怎么解决这个问题呢?它提供了一个LUT系统(Look UP Table),也就是查色表,当我们知道自己的显示器的CRT_Gamma值后,告诉LUT,现在这台显示器的Gamma值为多少,LUT得知后,调用对应的Gamma校正函数,用合适的Gamma值来控制显卡输出校正后的电频信息给显示器,所以,我们也把这个校正Gamma数值称之为LUT_Gamma。又由于这是系统内部做的校正,我们又称它为系统Gamma(System_Gamma)。 但问题还没得到完全解决,那就是,如果我不知道自己的显示器CRT_Gamma值呢?事实上,这才是问题的关键,我们需要大概地测试一下自己的显示器,在没有专业仪器的帮助下,这种测试只可能是大概的,我这里提供一个简易的办法:
根据上图,调节显示器亮度使得你能看到尽可能多的暗灰色块,但要同时保持背景为纯黑,并且以保证背景为纯黑为最基本前提,设置好以后,再看下图:
接着,你离显示器一定距离(大概三米),然后把眼睛眯成一条缝,看看上图中右边哪个小灰度条和左边的长条最能容到一起,那么,你们显示器CRT_Gamma基本上就是表上的数值了。因为是大概的测试方法,所以难免有误差,这里只是希望能力求精准。
现在大多数显示器以CRT_Gamma为2.2居多,而以前一些老显示器可能以2.5居多
第三节 将Gamma的概念细化
在上一节里,我们了解了用CRT显示器显示一个线性图像的问题,我们也了解了什么是CRT_Gamma以及LUT_Gamma,但我在第一节中就提到过,图像失真还可能发生在文件格式的储存和调用以及格式的转换上,在这一节,我们就将讨论这一问题。
当我们用一部数码单反相机拍下一张自然风景照片,并且存储为RAW格式的图像文件时,问题还不是很大,因为RAW是浮点格式的高精度存储格式,我们可以认为它近似线性连续地记录下了我们的原始数据,但一旦你将它转换为一些非浮点低精度图像格式,如JPG、BMP、TIFF等格式时,因为这些格式是以整数来记录数据的,这样就造成数据被离散化,不再那么连续,导致失真。
并且,另一个问题是,线性的RAW文件格式中的数据被映射在0-255这样的整数范围时,是否也是线性分布呢?这可不一定,所以在这里引入一个新的概念,编码Gamma,也就是Encode_Gamma,如果系统或软件在写入某文件格式时,将原有的线性数据也按线性映射在整数范围内,那么它的Encode_Gamma就是1,即不改变,这时数据的失真仅仅是因为近似无限连续的线性数据变成了离散化的线性数据。如果写入时将原有的线性数据按指数分布映射在整数范转内时,Encode_Gamma就不为1了,此时Encode_Gamma代表的就是这个指数。反应的就是数据存进文件后有了怎样程度的失真。当然,有写就有读,既然有编码Gamma自然就有解码Gamma,也就是Decode_Gamma,当一个软件打开并读取一个图像文件时,它是否对这个图像数据做变换处理,这个度是好多,就由Decode_Gamma来决定,如果Decode_Gamma为1,就是不改变,不校正,如果不为1,就表示要改变或校正,它的数值决定了做多大程度和什么样的改变。
绝大多数情况下Encode_Gamma和Decode_Gamma都是为1的,比如,默认的操作系统中IE浏览器的Decode_Gamma就为1,ACDsee看图软件在没设置的默认情况下,Decode_Gamma也为1,所以用它们两个去看一张标准的线性图片是会有问题的,因为显示
器的CRT_Gamma是2.2-2.5左右,而默认情况下LUT_Gamma为1 ,所以我们实际看到的图像的Gamma也就是CRT_Gamma,是非线性的,这就发生了错误。而如果你用Adobe photoshop去打开这张图片往往和那两个软件中看到的不一样,并且结果是对的,因为Adobe photoshop默认是进行色彩管理的,就是在软件使用过程中调用了LUT查色表并让LUT_Gamma不为1,所以这时就做了对的校正处理。 事实上,我们不难在应用软件中发现Encode_Gamma和Decode_Gamma 的应用身影,比如在MAX的优先设置面板中,在GAMMA子选项里,有这么一组参数,如下图:
这个里面的InputGamma呢,指的是当MAX调入任何一张图片格式时,做什么样的Gamma校正,这个操作显然是读操作,假如InputGamma为2.2,那么当MAX调入一张贴图时,这个贴图就会在调入内存时被事先校正,MAX通过把InputGamma,也就是2.2这个值告诉LUT查色表,查色表接着告诉MAX应该对贴图进行了一个Decode_Gamma为0.4545的校正,这里是很容易产生混淆的一个概念,很多人会以为InputGamma取值为2.2时,是MAX对文件调入内存之前做Gamma2.2的校正,这是错误的,当InputGamma取值为1时,LUT查色表告诉MAX需要对其做Decode_Gamma为1的校正,也就是不校正,不发生改变。反过来,再去理解OutputGamma就和上面的情况类似了,只不过它的校正发生在即将写入文件数据之前,是写入操作时发生的校正,并且通过将OutputGamma值传递给LUT告诉MAX该用什么样的Encode_Gamma作校正。
这时,你可能要问,是不是总是应该保持Encode_Gamma和Decode_Gamma为1 呢,这样反正就保持原样了,岂不省事?这就要具体情况具体分析了。
如果你用单反数码相机拍照存成了RAW文件,并转换成诸如JPG、TIFF、BMP这样的格式,这时,就会有一个问题,因为数码相机感光器的特性,从相机里输出的文件,比如RAW都是做过了一个Gamma0.45校正的,这时,往往在写入文件时编码就应该做一个 Encode_Gamma2.2的校正才能得到正确结果,或是在读文件时做一个Decode_Gamma为2.2的校正才能正确显示或使用这个图像,所以不同的情况是不一样的,如果图像本身是从计算机内部从无到有创建的,那么保持Encode_Gamma和Decode_Gamma为1是一个比较好的作法。
通常,我们把一个文件自身呈现的Gamma特性称之为File_Gamma,如果文件由外界摄取自计算机,那么:
File_Gamma=Device_Gamma * Encode_Gamma
(其中,Device_Gamma是指设备的Gamma,如果是数码单反,通常是0.45)
如果文件由计算机本身凭空创造,那么,就不存在设备,就有: File_Gamma=Encode_Gamma
然而,为了保证整个工作流程的线性化,所以我们应时时保证文件自身的Gamma为1,也就是File_Gamma为1。
事实上,MAX在打开和存储图像文件时,都具备非常详细的Gamma选项供用户控制,如下图:
其中
第一个选项Use image’s own gamma,就是使用文件自己的文件Gamma,不对其作任何改变的打开。
第二个选项Use system default gamma,就是说根据先前MAX优先设置面版里的input或output里的Gamma值对文件Gamma相应进行Encode_Gamma或Decode_Gamma的校正。
第三个选项Override,是说用户指定一个Gamma值,对这个图像进行一次这个Override_Gamma值的校正,注意,这次就和上面讲到的优选设置面板里的OutputGamma和InputGamma情况不一样,这次是直接做一个Override_Gamma取值的校正,你给2.2,就做Gamma2.2的校正,结果是图像变暗,给0.45,就做Gamma0.45的校正,结果是图像提亮,它是不会去查什么LUT查色表的,这就是实实在在做校正,要加以区别。
那么,通过这三个选项,我们就能很好地控制素材的文件Gamma,做到调进来的图是否线性化,在线性工作流程下,有一个准则,如果图像文件本身的文件Gamma不为1,那么我们就要通过设置这些参数来让它调入后为1,如果图像文件本身的文件Gamma已经为1,那么我们可以选择第一项来使用文件自己的Gamma设置就可以了,这样,你的图像至始至终都是在线性空间下工作的。这点在整个流程中也至关重要,因为校正是不可以多作的,校正多做了就是错误的结果。如果某张图像文件由数码相机拍摄并转为JPG或其它整数结构格式,这时,它的文件Gamma事实上不为1,前面我提到了,由于摄像机感光器特性,加上默认情况下软件或系统的Encode_Gamma为1,所以文件Gamma就是Camera_Gamma也就是大约0.4545,那么当我们把这个文件调入到MAX里来做贴图时,事实上该文件的数据就是非线性的,因为文件Gamma不为1嘛,我们要让它变成 1,这里我们就可以使用第三个选项,将Override_Gamma设为2.2,这样就对它做了一个Gamma2.2的校正,基本就线性化了。
那么,讲到这里,我想Gamma的概念在我们的脑袋里应该有了不同的定义,在不同的阶段不同的时候Gamma都有其特殊的意义,最后呢,我为这个小节做个总结,列出一些我在文中提到过的概念:
Camera_Gamma 摄像机Gamma,因为摄像机感光器的特性,拍下来的图像相当于会自动进行一次Gamma校正,其值一般约为0.4545
Encode_Gamma 编码Gamma,在文件形成,数据写入时,对数据变换分布所相当于造成的Gamma校正。
Decode_Gamma 解码Gamma,在文件调用至内存时,数据按新的分布方式读出所相当于造成的Gamma校正。
LUT_Gamma 系统Gamma或查色表校正Gamma,作用于显卡层面的帧缓冲,对其进行Gamma校正以适应设备输出。
CRT_Gamma 显示器自身电压特性相当于造成的Gamma校正。不可修正,一般为2.2或2.5。 根据以上概念为基础,我们还加入一些附加概念:
File_Gamma 图像文件相对于要反应的原始数据的Gamma特性,是文件自身的Gamma特性,表征了数据在存储为文件后的改动特性。 如果文件来源于外部设备如摄像机,
File_Gamma=Camera_Gamma * Encode_Gamma 如果文件来源于计算机内部创作
File_Gamma=Encode_Gamma
特殊地,如果文件在写入之前有软件功能上的人为Gamma校正,如Vray帧缓冲的Gamma曲线调节,那么
File_Gamma=Calibration_Gamma * Encode_Gamma(其中Calibration是校正的意思) Display_Gamma 显示输出Gamma,表征显示设备最终显示的结果相对于要显示数据的改变特性
以CRT显示器为例:Display_Gamma=LUT_Gamma * CRT_Gamma
View_Gamma 全局Gamma,是所有Gamma校正和变换结果的总和,通常用来表征我们最后看到一幅图像的样子时它相对于原始是什么样的改变特性,事实 上,在我们提及的线性
VR高级-LWF线性工作流(Linear - Work - Flow - )
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)
![](/skin/haowen/images/icon_star.png)