颜色空间——Gamma与线性颜色空间
后学末进才疏学浅,试图用不那么抽象的方式聊聊我理解的颜色空间。
必然有误与疏漏,恳请各位大大指正,拜谢。
- 学习参考内容:
一、颜色空间
- 做图形相关工作的大多都见过颜色空间这么四个字,它里面包含Gamma颜色空间和线性颜色空间。
线性空间:颜色按线性渐变的空间
Gamma空间:暂时理解为颜色不按线性渐变的空间
——这不是废话嘛,问题来了:
-
线性空间好理解,颜色按线性渐变。
- 你可以理解为一个为一个纯黑墨水池子,每次往里加一滴(等量)纯白色颜料,颜色逐渐变浅,直到纯白。记录下每次的色值,你就得到了一个从黑到白的线性渐变。
- 使用线性渐变的颜色空间,咱们就叫他线性空间。
-
既然有线性空间,就一定有不是线性的空间——Gamma空间。
二、Gamma是啥
正式讲Gamma是啥之前,咱们先做一个有趣的对比试验:
(一)第一步
- 这是我在PHOTOSHOP中新建一个文件,如下图:
- (话说你要是不信我的图,你自己也可也去PS里建一个~)
- 图1:500*150 / 分辨率75 / 颜色模式RGB 8位 / 背景白色
- 然后从左(黑)到右(白),水平拉一条渐变,起点终点位于画布左右两端。
-
来让我们进行如下操作:
-
找出图1中你认为的明暗分界线的大概位置。说的直白一点,你认为亮部和暗部大概从哪里分割比较合适。
-
我估摸着大多数人选择的位置应该是下图红线(或差不多)的位置吧?
-
在图1里,我们之所以选择了一个大概在中间的位置做明暗分界线,是因为我们认为红线左面(暗部)和红线右面(亮部)的信息一样多。
- 因为最左面是纯黑,最右面是纯白,而且咱们对这个渐变过程的体验也挺自然。
- 对于黑,白,渐变过程自然这三点咱们应该都没什么异议。
- 所以自然暗部亮部信息一样多,否则就是渐变不自然嘛~
-
现在,和你的大电脑击掌庆祝吧!巧了,它也是这么认为的。你们在图1的明暗分界线这一点上,达成了令人惊喜的共识。
-
你问我怎么知道电脑也是这么认为的?当然是一系列缜密优雅又符合逻辑的数学运算————跟着我进行如下骚操作:
- 打开你的大QQ,用它的截图工具的大箭头,瞄准图1最(“最!”敲黑板)左面,最黑的地方,观察箭头数值,是不是RGB(0,0,0),嗯,记在心里或本儿上。
- 好,咱们再去最(敲黑板)右面,最白的地方,大箭头瞄准它,是不是RGB(255,255,255)?差那么1-2个数的,一定是你自己撸多了手抖吸不准,也别较这个真儿了,无所谓的,差不太多就得了。
- 现在咱们去红线附近吸一吸~注意别傻乎乎的去吸红线的红色,要吸红线附近的灰色,咱们观察的是从黑到白的渐变,跟红没关系。你在红线低端或者顶端吸都行。
- RGB数值是多少?是不是RGB(128,128,128)左右?
- 重点来了!缜密优雅又符合逻辑的数学运算来了!现在我们知道从黑到白是从0-255的过程,那么我们开始计算——255+1(+1是为了0,0,0占去的那1位,也就是说黑到白经过了256个过程),再除以2,我们得到了这个渐变的中间点,咔嚓——结果正好是128!
- 惊不惊喜,意不意外?————把这个128,128,128记在心里,他就是你和你家大电脑都认为的明暗分界线,也就是中间亮度。这个结果合情合理符合逻辑。
-
这时,相信你一定有一个疑问,为什么是256?这就要说到这张图片的格式了——RGB8位,这个格式是电脑用来存储图片的,你可能听说过的sRGB也是8位的。
- 8位代表了什么?8代表2进制的2的8次幂,就是256。也就是说它代表三原色(红绿蓝RGB)的色阶最多只有256(从0到255)种,就是256种红,256种绿,256种蓝,用这么多的颜色我们能调成256 X 256 X 256 = 16777216种颜色。怎么样,够你折腾了吧?说实话,并不是所有人都能分辨出256种不同的红,反正我是不能~
-
那为什么要有8位图?因为8位图的色彩够你折腾了啊!在这么多色彩给你折腾的前提下,占用的存储空间也比较小啊!
- 再观察图1,注意图一边框下部的:文档:219.7K,看到木有,还不到1/4MB啊!一张500*150大小的图还不到1/4MB啊!你拿8位图网络传输、做个贴图渲染什么的,存储空间成本和效率成本都比较好啊。
- 所以!(敲黑板),拿页游,手游举例,等一系列对图像品质要求不高的平台,我们使用的贴图都是8位的,你听说过的sRGB也是8位的,没听说过就无视。因为8位占空间小,色彩表现能力(数量)又符合平台需求,渲染效率更符合平台能力(比如适合网络传输,适合手机GPU渲染等)。
-
好了,说了这么多,你得到了两个新姿势!
- a. 从黑到白的明暗分界线的色阶是RGB(128,128,128)。
- b. RGB8位是什么,有什么用。
- c. 我有姿势我自豪。
第二步
- 既然是对比试验,就一定要有对比对象,下面我们来进行第二步:
-
下面是我在PHOTOSHOP中新建的另一个文件,如下图:
-
(建议你照着我的,去PS里再建一个~一会可能用得到)
- 图2:500*150 / 分辨率75 / 颜色模式RGB 32位 / 背景白色
- 然后从左(黑)到右(白),水平拉一条渐变,起点终点位于画布左右两端。
- 咱们都知道了一个从黑到白的渐变里,明暗分界线的色阶是RGB128,COMEON,咱们在图2里找到这个点!
- 掏出QQ截图的大箭头,瞄准图2,在上面移动箭头,找RGB(128,128,128)。
-
- ……傻了吧?无语了吧?纠结了吧?为什么不在中间了?而是出现在了约等于渐变过程0.2的位置?
- 为什么明暗分界线跑到了0.2的位置,少了的30%的暗部去哪了,相应的多了30%的亮部又是什么鬼?而且这个渐变过程看起来好像不自然啊,白的那么多,黑的太少了!
- 好的,你提出了三个问题,暗部减少,亮部增多,渐变不自然。
- 下面我们依次回答这三个问题:
-
暗部去哪了:
- 暗部没减少,反倒增多了。
- 因为图片格式变成了32位,它有了更多的色阶来表现颜色。
- 你不应该再用QQ吸管,而是应该去PS里建一个32位RGB图片观察色板。
- 它不再是RGB0-255,而是变成了0.0000-1.0000。
- 代表了RGB三原色的更多色阶。
- 你之前划分的暗部仍然在红线的左侧,那128个暗部色值都没有消失。
- 相反,32位图提供了更多的色阶来表现暗部,数量也远大于128。具体数量不需要关心,也不是2的32次方,感兴趣的可以自行查阅32位RGB,不在本文展开。
- 也就是说32位格式下,使用了0.2的空间,表现了8位格式下占一半的暗部,不仅如此,还附送了多得多的暗部细节,因为色阶变多了嘛,虽然作为人类,我们可能感受不到那么多色阶变化..。
-
亮部增多了:
- 没错,确实多出来许多的亮部信息。
- 32位格式下,多出来的亮部信息,包含8位原本的亮部信息,以及大量你可能难以区分的亮部信息。
- 至于原因,下文看完就懂了。
-
渐变不自然
- “黑少白多,渐变不自然”————那是你以为。
- 这才是自然界中真实的渐变,因为这才是线性的,每次滴入等量白色颜料的从黑到白的渐变。
- 之所以你会觉得渐变不自然,是因为人类的眼睛对暗部的变化更为敏感(至于理论方面的依据,请自行搜索,本文只说结论)。
- (图中的英文意思是:基本相同。)
- 综上所述,你之所以会认为一个线性的渐变过程“不自然”,是因为你对亮部的细节变化不敏感,或者难以察觉。因此得出了“黑少白多,渐变不自然”的结论。
- 也就是说,你觉得32位下的线性渐变,亮部区域出现了过多的冗余信息。
- 通过32位的线性渐变,我们得出了一个什么结论:
- 原本我们在8位图中找到的明暗分界线RGB(128,128,128)在自然界的线性渐变中,大致处于前20%的位置,即0.2的位置。
- 之前的8位图1欺骗了我们,它如实的把你认为的0.5老老实实的记做了0.5,而不是实际的0.2。它出了问题。
- 跟着我唱:“你说黑不是黑,你说的白是什么白~~”
- 8位图为什么要骗我
- 8位图君:
- 我也不想啊,我要是把你认为的明暗分界线转(0.5)换成实际线性渐变记成0.2,色阶不够用啊。
- 你们人类对于暗部敏感,我要是把你认为的0.5,记成0.2,那暗部色阶就只有256*0.2=50个左右的色阶来存储暗部,50个左右,明显不够用啊。
- 然后余下的色阶却要用来表现你们人类可能感受不到的亮部,太浪费啊。色阶有限啊。
- 所以我只能把你认为的明暗分界线就记做0.5,然后去掉一部分你们感受不明显的亮部色阶,以此换来跟多的暗部色阶存储空间,来适应你们人类的感受啊。
- 8位图怎么把那个实际的0.2,转换成0.5的?
- 当然不是直接的把0.2记成0.5就行了。
- 0.2-0.5的转换过程本质上是一个全局提亮的过程,这个过程被称作Gamma校正。
三、迟来的正文
Gamma校正
- Gamma校正被使用在8位RGB图中。
- 用来解决在有限的存储空间中保存尽可能多的人类感受敏感的色彩内容。
Gamma怎么校正
- Gamma校正的方式就是采样时,和输出到显示器给人类看时,对亮度进行的调整.
- 采样时 Gamma=1/2.2 调亮Gamma
- 显示时 Gamma=2.2 调暗Gamma
- 下图:配合后文说明看下图 , 彩色曲线为Gamma曲线
- 实际亮度(X轴)=>内部存储(Y轴) 存储数值 = 物理亮度的1/2.2次方
- (即对应使用1/2.2位置的Gamma曲线)
- 假设实际亮度X轴为0.2,存储数值将为0.2的1/2.2次方,即Y轴0.5
- 内部存储(X轴)=>显示还原(Y轴) 显示的物理亮度 = 存储数值的2.2次方
- (即对应使用2.2位置的Gamma曲线)
- 假设内部存储X轴为0.5,显示物理亮度将为0.5的2.2次方,即Y轴0.2
Gamma校正与8位图
- 看完上面的说明,有点抽象了吧?没关系,咱们直接说结果。
- 8位图使用的颜色就经过Gamma校正过的颜色。
- 经过Gamma校正后,得到了更多的暗部存储空间,牺牲掉了一些不重要的亮部存储空间。
- 它把你认为的0.2通过Gamma校正成了0.5,因为Gamma校正本身是一个非线性的调整过程(观察Gamma曲线图:Gamma为1,即是中间那条直线,表示未校正,那么Gamma为1时,渐变是线性的。其他的不是直线,不是直线你就当他是非线性,好理解吧?)。
- 那么问题来了:显示器显示8位图片时,我们已知现在主流显示器的色彩要大于8位,多数都是32位真彩色,那么请问,显示器接受到8位图片存储的0.5时,显示的是32位颜色中(以图2位例)0.5位置的颜色,还是0.2位置的颜色。
- 没错,显示器显示的时候也经过了一次Gamma校正,它把0.5又变成了0.2.
- 如果不经过这一步,直接输出0.5,因为显示器是32位的,那么你在屏幕上得到的将是位于图2中间位置的那个颜色,你会说这个显示器有问题,颜色不准确,亮瞎了。
- 综上所述,我们用了一大圈,总算明白了8位图为什么是非线性的。
四、Gamma色彩空间与线性色彩空间与渲染
- 色彩空间简单的理解就是我们在创作一张图片时使用的颜色表。
- 线性色彩空间就是没经过Gamma校正的颜色表 - 如图2。
- 非线性的色彩空间就是经过Gamma校正的颜色表 - 如图1。
(一)渲染时使用的颜色空间
- 在下刚学Unity,所以只能拿Unity举例:
- 在Unity渲染中,存在两个颜色空间
- Gamma(非线性)颜色空间
- Linear(线性)颜色空间
- 现在再来看这两个颜色空间应该不陌生了吧,至少我们知道他们表达的是什么意思。
- Gamma颜色空间里使用的是一个进过校正(阉割)过的颜色表。
- Linear颜色空间里使用的是一个线性的完整的颜色表。
(二)渲染
- 渲染是一个很复杂的过程,涉及步骤有许多,不在此展开讨论。
- 但无论多复杂的过程,多复杂的灯光、材质等等乱七八糟的东西,它始终离不开图片,颜色。
- 图片是通过颜色空间中的颜色创作出来的,那它就一定存在着一个问题,是否经过Gamma校正。
Linear颜色空间
- 在Unity中,如果使用Linear颜色空间,除非对指定图片选择了ByPass sRGB(忽略sRGB,你理解为忽略Gamma校正),否则所有的图片都会默认变成sRGB格式。
- 这样做的目的是把你在Gamma颜色空间里创作的图片里面的颜色给校正到正确的32位颜色,再参与GPU渲染计算。
- ByPass sRGB的意思就是直接使用这个0.5,不用再校正了,除非你是在线性颜色空间里创作的图片,否则不建议这么干。
- 然后,GPU再把结果Gamma校正一次,0.2-0.5,这样做的目的是:显示器不管你到底干了什么,他老人家是一定要在最后Gamma校正一次的(0.5-0.2)。
- 显示器按照接受到的值进行Gamma校正(0.5校正到0.2)给你看。
- 在这个空间里进行渲染,因为使用的是线性的颜色空间,因此你会得到非常真实的表现效果。
- 但是,因为色彩丰富的同时,带来的各项成本,如硬件渲染能力的需求也会增加。
Gamma颜色空间
- 在这个颜色空间内渲染,GPU不会再Gamma校正,而是直接使用存储的值参与渲染计算,因为大家使用的都是阉割版的颜色嘛。
- 但是在这个空间里进行的渲染,因为使用的是阉割过的Gamma颜色空间,因此你会得到不符合真实表现的效果。
- 在最终输出到显示器的时候,仍然会经过Gamma校正,将渲染后的0.5,表现成0.2给你看。
- 因为使用了较少的颜色(相对于线性颜色空间),因此会得到比较好的渲染效率以及较低的渲染能力需求。但是图像会存在失真(偏暗,因为亮部细节表现不够)等一系列问题。