色彩空间基础:从RGB到Lab的进阶之路
做白平衡和色彩校正,绕不开色彩空间。说白了,你得先知道颜色是怎么被数学描述的,才能去调整它。
我记得刚入行那会儿,觉得色彩空间就是个概念,知道RGB就够了。直到有一次做手机摄像头调试,发现同一张图在不同屏幕上颜色完全不一样。嗯,从那以后我才真正重视起色彩空间这件事。
RGB与sRGB色彩空间
RGB是最基础的色彩模型。红绿蓝三个通道,每个通道0-255,组合出1600多万种颜色。但问题来了——同样的RGB值,在不同设备上显示的颜色不一样。
为什么会这样?因为RGB是个设备相关的色彩空间。你的显示器、我的手机、他的打印机,各自的RGB色域都不一样。
sRGB就是来解决这个问题的。它由微软和惠普在1996年制定,定义了标准的RGB色域、伽马曲线和白点。现在几乎所有的网页、图片、显示器都默认用sRGB。
关键参数:
- 白点:D65(色温6500K)
- 伽马:约2.2
- 色域:覆盖CIE 1931色度图的约35%
我在项目中遇到过一个问题:用sRGB拍的图,放到广色域显示器上看,颜色过饱和。反过来,广色域图在sRGB显示器上看,颜色发灰。这就是色域不匹配的典型表现。
XYZ色彩空间与CIE 1931色度图
RGB不够用,那就需要一个设备无关的色彩空间。CIE 1931 XYZ色彩空间就是为此而生。
它基于人眼对颜色的感知实验,用三个虚拟原色X、Y、Z来描述颜色。其中Y代表亮度,X和Z代表色度信息。
把XYZ投影到二维平面上,就得到了CIE 1931色度图。这张图长这样——马蹄形区域包含了所有人眼可见的颜色。
这张图里,马蹄形边界是单色光(纯光谱色),内部是混合色。sRGB和Adobe RGB的三角形就嵌在里面。你想想看,sRGB只覆盖了马蹄形的一小部分,这就是为什么有些颜色sRGB显示不出来。
实战技巧:做白平衡校正时,我习惯先把RGB转到XYZ空间再处理。因为XYZ的Y通道直接对应亮度,调整白平衡不影响亮度,比在RGB空间里调更干净。
XYZ与RGB的转换
转换公式其实不复杂。以sRGB为例:
// sRGB到XYZ的转换矩阵(D65白点)
double[3][3] sRGB_to_XYZ = {
{0.4124564, 0.3575761, 0.1804375},
{0.2126729, 0.7151522, 0.0721750},
{0.0193339, 0.1191920, 0.9503041}
};
// 转换过程
X = R * 0.4124564 + G * 0.3575761 + B * 0.1804375;
Y = R * 0.2126729 + G * 0.7151522 + B * 0.0721750;
Z = R * 0.0193339 + G * 0.1191920 + B * 0.9503041;
注意,这里的RGB需要先做伽马校正(去伽马),转成线性RGB,才能用这个矩阵。我见过不少新手直接拿sRGB的0-255值去乘矩阵,结果颜色全偏了。
避坑指南:我曾经在嵌入式平台上做色彩校正,发现转换结果总是不对。查了两天才发现——平台用的RGB排列是BGR,矩阵没跟着转置。所以,做转换前一定要确认你的数据排列顺序。
Lab色彩空间与色差计算
XYZ虽然设备无关,但它不是均匀的。什么意思?就是XYZ空间里距离相同的两个点,人眼看不出颜色差异是否相同。
Lab色彩空间就是为了解决这个问题。它把颜色分成三个通道:
- L:亮度(0-100)
- a:红绿轴(负值偏绿,正值偏红)
- b:黄蓝轴(负值偏蓝,正值偏黄)
Lab空间最大的优点是——欧几里得距离直接对应人眼感知的颜色差异。这就是色差公式ΔE的基础。
// CIE76色差公式(最简单的版本)
double deltaE = sqrt(
pow(L1 - L2, 2) +
pow(a1 - a2, 2) +
pow(b1 - b2, 2)
);
// 判断标准
// ΔE < 1.0:人眼几乎看不出差异
// ΔE < 2.0:专业级色彩一致性
// ΔE < 5.0:一般可接受
// ΔE > 10.0:明显色差
我在做摄像头模组标定时,就用ΔE来评估白平衡校正的效果。校正前ΔE可能到15,校正后压到2以内,人眼就基本看不出偏色了。
色差公式演进:
| 版本 | 年份 | 特点 |
|---|---|---|
| CIE76 | 1976 | 最简单,直接欧氏距离 |
| CIE94 | 1994 | 加入权重因子,更准确 |
| CIEDE2000 | 2000 | 考虑色相、饱和度交互,最精确 |
实际项目中,我推荐用CIE94就够了。CIEDE2000虽然更准,但计算量大,在嵌入式平台上跑不动。CIE76又太粗糙,对低饱和度的颜色判断不准。
从RGB到Lab的完整流程
把整个流程串起来,就是这样的:
- 输入:sRGB图像(0-255,带伽马)
- 去伽马:转成线性RGB
- 矩阵变换:线性RGB → XYZ
- 非线性变换:XYZ → Lab(涉及白点归一化和立方根变换)
- 输出:Lab图像(L:0-100, a/b:-128到127)
你想想看,这个流程里每一步都有坑。去伽马时要注意sRGB的伽马曲线不是纯2.2,而是分段函数。XYZ转Lab时白点必须和源图像一致,否则色差计算全错。
我的习惯:做色彩校正时,我通常把图像转到Lab空间,在ab通道上做调整,L通道保持不动。这样调整色相和饱和度不会影响亮度,效果比在RGB空间里调好得多。
好了,色彩空间的基础就这些。记住一句话:RGB是给机器看的,Lab是给人看的,XYZ是中间的桥梁。做白平衡和色彩校正,这三者缺一不可。