色彩校正中的 gamma
的有关信息介绍如下:
Gamma Correction的概念的确比较抽象,但在计算机图形学中非常重要。一般的解释,比方说已有的答案中,往往忽略两个背景知识:人类的视觉特性和古老的 CRT 显示器。在我看过的所有资料中,都没有人提到过,Gamma 的广泛应用很大程度上是因为一个神奇的巧合。
从字面上看,Gamma指的是指数运算中的指数。比方说 A 的2.2次方,Gamma 指的就是2.2这个数字。计算机图形学中颜色值,特别是 RGBA 值都是用0到1的浮点数表示。颜色的 Gamma 矫正本质上就是一系列介于0到1之间的浮点数进行指数运算,通常来说这个数字是2.2。
为什么要进行矫正?为什么是2.2?
从人类的视觉特性说起。人类的视觉系统进化出了一个特性,黑暗环境下的辨识能力要强于明亮环境,这可能有助于我们及时发现黑暗中隐藏的危险。如果有兴趣,可以在计算机上绘制一条从白到黑的渐变条,你会发现明显黑色部分的色阶要多于白色部分。这并不是你的显示器问题(当然也有可能真的是你的显示器太差……),而是因为我们对于暗色的分辨能力远超过亮色。那么在有限的计算机颜色(民用显示器和操作系统中黑色到白色256个色阶)中,亮色和暗色均匀分布的话,那亮色部分就会精度过剩而暗色部分就会精度不足。如何解决这个问题?进行 Gamma 矫正。
现在我们知道了对图像进行 Gamma 矫正的本质上的原因——因为我们的眼睛。那么为什么是2.2的倒数?
因为老式的 CRT 显示器。
阴极管显示器有一个物理特性——输入值和输出值呈现指数关系,这个指数是2.2。也就是说,当你输入0.5的亮度,在屏幕上得到的不是0.5,而是0.5的2.2次方,约等于0.218。仍旧是这个图:
当我们在 CRT 显示器上显示一张 Gamma 矫正过的图像,也就是上面的那根曲线,就会获得所期望的线性图像——中间那跟灰色的直线。你看,对图像进行Gamma 矫正即可以获得我们想要的精度,又能在 CRT 显示器上正确显示,这岂不是一个美好的巧合?
事实上我们之所以选择2.2的倒数进行图像矫正,那是为了迎合 CRT 显示器的特性。如果显示器的 Gamma 值不是2.2,那么图像矫正 Gamma 值也需要相应变更,比方说早年的 Mac 操作系统都是使用1.8的 Gamma 值。现代的 LCD 显示器已经不再具有这个特性,但是生产厂商仍旧会加入模拟 Gamma 曲线的硬件功能,也就是说所有显示器都期待软件输出 Gamma 矫正过的图像。
总结一下,所谓 Gamma 矫正就是对颜色进行指数运算。对图像进行矫正是为了获得符合人眼特性的可辨识精度。矫正使用的Gamma 值取决于显示器,现代系统基本上都统一使用2.2。
Gamma 矫正的确是一个隐藏的比较深的问题,别说普通人,长久以来游戏界也一直没有重视。计算机图形学中的算法普遍需要输入值处于线性空间,而读入的图像却都是矫正过的——处于 Gamma 空间。最终得到的计算结果自然也是不正确的。当然游戏图像往往可以通过美术师的人为修改来得到符合期望的图像,但从数学上来说,这是错误的……而且整个行业错了几十年,直到这几年这个问题才被重视起来,产生了所谓了 Gamma Corrected Pipeline。
3D 图像的渲染本质上是对真实世界进行模拟,近几年(特别是2014年)兴起的 Physically Based Rendering 特别强调贴图材质灯光的统一性和物理真实的渲染效果,自然不能容忍在整个系统的底层存在不正确的 Gamma 矫正这样的大乌龙……
2018年7月4日更新重要视频:《美术中灰色的物理光强——演示人眼亮度感知的非线性》
各位网友好,您现在阅读的是2017年12月19日修改后的版本。如果您看过我之前的答案版本,我必须要指出新老答案版本的核心区别:我之前版本的答案认为 sRGB 标准中的 Gamma 校正的幂函数曲线来自于心理学上的韦伯-费希纳定律(Weber-Fechner Law)或斯蒂文思幂定律(stevens'power law)(这个观点是没啥问题的)。同时认为这条幂函数曲线和 CRT 显示器的物理属性毫无关系(这个“毫无关系”大大的有问题,说的太绝对了)。
我之前认为,既然眼睛的特性从心理学上讲是这条曲线,那我们通过实验是可以得到 Gamma=2.2 的 sRGB 标准的,和显示器的物理属性没有任何关系,你用蜡笔的灰度做实验也能得到这条曲线,而蜡笔反射的光,和显示器发出的光,必然没有本质区别,所以即使我们抛开电子产品,也能试验出这么一条 Gamma=2.2 曲线。 Gamma 曲线就是把物理光强和美术灰度做了一个幂函数映射 。如果媒介灰阶有限呢,比如8位每通道的图片,就必须要做这个映射,否则浪费存储空间。如果灰阶充裕,就不需要做这个映射,直接记录物理光强就可以,比如32位每通道的图片。
其实我之前的结论没有太大的问题,很简洁,也比较触及本质,很适合用来理解 Gamma,但是直到今年7月份我看到了
之前的答案说了很多,资料也很丰富,但在原理上还没有说通透:
简而言之,gamma值就是对动态范围内亮度的非线性存储/还原算法。
1. gamma值的存在,归根到底,是一个解决方案,用于化解“无限的自然存在,与有限的存储容量/传输带宽”之间的矛盾。
自然界中存在的亮度范围是巨大的:日光环境下100000勒克斯,阴天环境8000 lux,室内办公环境300 lux,路灯下5 lux,星光0.0003 lux……
很显然,亮度级别太多太多。如此庞大的动态范围,如果按照线性方案进行存储,那么存储/传输的代价很昂贵。
2. 人类对于外界刺激变化程度的感受,是指数形式的 (或者说感受到的是外界物理量变化的对数)。例如,10倍的声音我们感受到10分贝的变化,100倍的声音对应20分贝感受变化,1000倍对应30分贝感受……
人们对于物体明亮程度的主观感受,也遵循指数规律。1盏灯→2盏灯产生的亮度变化感受,与2盏灯→4盏灯的变化感受是相同的,也就是说2倍物理亮度改变让我们感受到1“档”变化,4倍物理亮度改变产生2“档”感受改变,8倍亮度对应3“档”主观改变……
根据实验测定,人类对明亮程度的主观感受,线性对应于物理亮度的2.2次方(实际测试结果为1.8-3.5不等,与测试环境的明暗程度有关,也与受试人群有关。)
3. 综合1、2两点,非线性存储方案就是很自然的结论,gamma=2.2就成了影视业的业界标准,并进而成为电脑、IT界的事实标准。
(这种方案有点类似于IEEE浮点数的存储方案:单精度浮点数只用了4个字节,就表示出了10e-38到10e+38的巨大动态范围(此处不考虑0和负数),且在整个动态范围内其相对误差基本固定)
4. gamma 值的变换分为两个部分 :
· 实际亮度→内部存储(或信号传输):存储数值≒物理亮度的1/2.2次方。在限定条件下,这保证了低亮度的分辨精度,降低了高亮度的量化存储开销,从而在总体上获得了最佳效果(亦即小的存储/传输代价,大的动态范围,最多的线性主观感受级别)。这个环节对应于摄像、sRGB图片存储过程。
· 内部存储(或信号传输)→显示还原:显示物理亮度≒存储数值的2.2次方。这个环节对应于摄像、sRGB图片的显示(还原)过程。
原理性介绍完毕,下面是一些对gamma使用的细节性介绍:
① 在目前电脑体系中,一般图片使用sRGB方案,其灰度级别0、1、2…255,对应于线性的主观亮度感受(物理亮度则是非线性的)。
使用gamma=2.2是正确还原大多数图片的必要选择。(鉴于环境明暗的影响,实际上根据环境亮度而在1.8-2.5范围内调整gamma值有其道理)
② 对于完整的摄制(绘图)→存储/传输→显示还原,其整体gamma应接近于1,所谓所见即所得。
当整体gamma不为1时,就类似于音响加了均衡器,可能更适合用户口味但不保真。
③ 本机制作的图片/视频还原时,在本机上会保持原样,与gamma值无关。
但考虑到交换/传输到其他机器上,则两个机器gamma值相同时才会有同样的还原结果。所以本机gamma值还是设为2.2为好。(不考虑交换的请随意,用户至上^_^)
④ 对一个现有图片,在指定显示器上还原时,其总体明暗范围固定。
为观察图片细节,调整显示gamma值是为了让某些细节更清晰,代价是让另一部分不容易分辨细节。
· 当调大gamma时,表现为总体提亮,原暗部占据更多明暗范围、易于分辨细节,原亮部变得更亮(白茫茫,占据明暗范围减小)且细节分辨变得困难。
· 当减小gamma时,表现为总体压暗,原亮部占据更多明暗范围、易于分辨细节,原暗部变得更暗(黑乎乎,占据明暗范围减小)且细节分辨变得困难。
⑤ 纯黑(亮度0)、纯白(亮度255)的交错网点进行模糊,其平均亮度为50%。在gamma=1的机器上,这与灰度128是接近的;在gamma=2.2的环境下,这与灰度186是接近的(这是gamma=2.2规则所决定的,也可勉强理解为硬性规定)。
⑥ 电脑显示系统的亮度动态范围有限,所以黑屋子的背景是黑色,黑屋子里黑纸上的黑色钢笔字还是黑色;白墙是白色,白炽灯、闪光灯、正午太阳也还是白色。这些不在讨论范围之内。
(以上均以灰度作为介绍,RGB单通道的gamma值基本类似)



