Gamma校正基础:人眼视觉特性与Gamma曲线、CRT显示器的非线性响应、Gamma编码与解码原理
说到Gamma校正,很多人第一反应就是“调亮度”。其实没那么简单。Gamma校正的根,扎在三个地方:人眼怎么看东西、老式CRT显示器怎么发光、以及我们怎么在数字世界里保存图像信息。这三个东西凑在一起,才有了我们今天调ISP时绕不开的Gamma曲线。
我个人习惯把Gamma校正叫做“图像界的翻译官”。它负责把物理世界的光信号,翻译成人眼看着舒服、显示器也能正常显示的数字信号。翻译得不好,画面要么死黑一片,要么亮得刺眼。
人眼视觉特性:我们不是线性传感器
先问一个问题:一个光源亮度翻倍,人眼感觉到的亮度也翻倍吗?
答案是:不会。
人眼对暗部变化极其敏感,对亮部变化相对迟钝。这是进化出来的能力——在昏暗环境里能看清猎物,在烈日下也能分辨物体。这种非线性响应,可以用一个简单的幂函数来近似描述:
感知亮度 ∝ (物理亮度)^(1/γ)
其中γ大约在0.4~0.5之间。也就是说,物理亮度从0.1提升到0.2,人眼感觉到的亮度变化,比从0.8提升到0.9要明显得多。
我在项目中遇到过一件事:有次调试一款安防摄像头,客户反馈夜间画面“太暗”。我一看原始RAW数据,暗部信噪比其实还行。问题出在哪?Gamma曲线没匹配好人眼特性。默认的Gamma把暗部压得太狠,人眼看着就觉得“黑乎乎一片”。后来我把暗部斜率调高了一点,客户立刻说“画面亮了”。其实物理亮度没变,只是人眼感知被“骗”过去了。
核心结论:人眼是“暗部放大器,亮部压缩器”。Gamma校正的本质,就是模拟这个特性来分配数字码值。
CRT显示器的非线性响应:历史的“巧合”
你可能会问:为什么Gamma曲线是那个形状?这得感谢(或者说“怪”)CRT显示器。
CRT的电子枪电压和屏幕亮度之间,存在一个天然的幂律关系:
显示亮度 ∝ (输入电压)^γ
这个γ值大约在2.2~2.5之间。也就是说,你给CRT输入一半的电压,它不会显示一半的亮度,而是显示大约(0.5)^2.2 ≈ 0.22的亮度。画面会明显偏暗。
我记得第一次看到这个数据时,心里想:这设计也太“坑”了吧?但后来理解了,这其实是物理器件的天然特性,不是谁故意搞出来的。就像LED有正向压降一样,CRT就是这种脾气。
| 输入电压比例 | CRT显示亮度(γ=2.2) | 人眼感知亮度 |
|---|---|---|
| 0.0 | 0.00 | 0.00 |
| 0.25 | 0.04 | ≈0.20 |
| 0.50 | 0.22 | ≈0.47 |
| 0.75 | 0.53 | ≈0.73 |
| 1.00 | 1.00 | 1.00 |
你看,中间区域偏差非常大。如果不做任何补偿,CRT显示的图像会暗部细节丢失、整体偏暗。这就是为什么我们需要Gamma校正——在发送信号之前,先做一个“预失真”。
Gamma编码与解码原理:一对“反函数”
Gamma校正的核心,就是一对互为反函数的操作:
- Gamma编码(Encoding):在发送端(相机/图像生成),对线性光信号做
V_out = V_in^(1/γ)的变换。目的是把信号“拉伸”到适合人眼感知和CRT显示的范围。 - Gamma解码(Decoding):在接收端(显示器),对信号做
V_out = V_in^γ的变换。CRT天然就做这件事。
编码和解码组合起来:(V_in^(1/γ))^γ = V_in。完美还原。
你想想看,如果没有编码这一步,直接给CRT送线性信号,画面会偏暗。如果编码过度,画面又会偏亮。这个平衡点,就是标准Gamma曲线。
实战小技巧:在ISP pipeline中,Gamma校正通常放在黑电平校正之后、色彩校正之前。顺序不要搞反。我曾经见过有人把Gamma放在黑电平前面,结果黑电平偏移被Gamma放大,暗部出现奇怪的色偏。
标准Gamma曲线:sRGB与Rec.709
目前最通用的Gamma标准是sRGB和Rec.709。它们的Gamma值接近2.2,但在暗部有一段线性区,用来避免噪声被过度放大。
sRGB的Gamma曲线分段定义:
if (V_linear <= 0.0031308)
V_srgb = 12.92 * V_linear
else
V_srgb = 1.055 * V_linear^(1/2.4) - 0.055
为什么要有线性段?说白了,就是防止暗部噪声被Gamma放大。如果全程用幂函数,暗部稍微有点噪声,经过Gamma编码后会被拉伸成明显的闪烁。线性段相当于给暗部加了个“保险”。
我在调试手机摄像头时,经常需要根据传感器噪声水平调整这个线性段的阈值。噪声大的传感器,线性段要长一点;噪声小的,可以短一点。没有固定参数,全靠实测。
Gamma校正的视觉影响:一张图看懂
下面这张SVG图,展示了Gamma编码、CRT解码和最终感知亮度的关系。你可以看到,编码曲线和解码曲线互为镜像,最终输出接近线性。
Gamma校正的“坑”与避让
做Gamma校正调试这么多年,我踩过不少坑。挑几个典型的说说:
坑1:Gamma与黑电平的耦合效应
我曾经在调试一款宽动态传感器时,发现暗部出现奇怪的“台阶”。查了两天才发现,黑电平校正后的残留偏移,被Gamma曲线在暗部的陡峭斜率放大了。解决方案:先做黑电平校正,再做Gamma,并且Gamma暗部斜率不要超过2.0。
坑2:不同显示设备的Gamma差异
你调好的Gamma曲线,在手机上看着正常,换到显示器上可能就偏亮或偏暗。因为不同设备的实际Gamma值不一样。我的做法是:在调试时同时监控sRGB和Display P3两个色彩空间,确保Gamma曲线在两个空间下都能接受。
避坑指南:调试Gamma时,永远不要只看灰阶图。一定要用包含人脸、天空、植被的真实场景图。因为Gamma对肤色和绿色的影响最明显,灰阶图看不出来。
总结:Gamma校正的“三个为什么”
最后,用三个问题帮你理清思路:
- 为什么需要Gamma编码?——因为人眼对暗部敏感、CRT显示非线性,编码可以预补偿。
- 为什么Gamma值选2.2?——这是CRT显示器的典型γ值,也是人眼视觉特性的近似倒数。
- 为什么暗部要有线性段?——为了防止噪声被Gamma放大,这是工程上的妥协。