色彩空间基础:从RGB到人眼感知的桥梁

做AWB调优这些年,我最大的体会就是——不懂色彩空间,你连白平衡的“白”是什么都说不清楚。说白了,色彩空间就是给颜色一个“身份证”,让不同设备之间能准确传递颜色信息。

今天咱们就聊聊几个最核心的色彩空间。嗯,这些概念我几乎每天都在用。

RGB与sRGB:最熟悉的陌生人

RGB大家都懂,红绿蓝三通道嘛。但你知道吗?RGB其实不是一个标准化的色彩空间。它只是一个“加法混色”的模型。真正要定义颜色,还得指定三原色的具体波长、白点位置、Gamma曲线等等。

举个例子。你显示器上的RGB和相机传感器上的RGB,根本就不是一回事。我在项目中遇到过这种情况:同一张RAW图,在不同软件里打开颜色完全不一样。原因就是它们用了不同的RGB定义。

sRGB就是来解决这个问题的。它由微软和惠普在1996年联合推出,定义了标准的RGB色彩空间。现在几乎所有互联网图片、显示器、打印机都默认用sRGB。

sRGB的几个关键参数:

  • 白点:D65(色温6500K)
  • Gamma:近似2.2
  • 三原色色度坐标:R(0.6400, 0.3300)、G(0.3000, 0.6000)、B(0.1500, 0.0600)

我个人习惯,在做AWB算法时,先把所有颜色统一转到sRGB空间再处理。这样至少保证“起点”是一致的。

CIE 1931 XYZ:色彩世界的“绝对坐标系”

RGB有个硬伤——它依赖于设备。那有没有一种“绝对”的色彩空间?有,就是CIE 1931 XYZ。

1931年,国际照明委员会(CIE)搞了一次大规模的人眼颜色匹配实验。他们让受试者调整红绿蓝三原色的强度,去匹配单色光。结果发现,有些颜色用正值的RGB是配不出来的,必须引入“负值”的红色。

这太反人类了。于是他们做了个数学变换,把RGB转换成了XYZ三个虚拟的“基色”。XYZ的好处是:所有可见光的颜色都能用正值的XYZ表示

我的经验:在ISP pipeline里,我经常把sRGB转成XYZ再做白平衡增益计算。因为XYZ的Y分量直接对应亮度,处理起来更干净。我曾经踩过一个坑——直接在RGB空间做白平衡,结果高饱和区域出现了色偏。后来转到XYZ空间处理,问题就解决了。

RGB到XYZ的转换矩阵(D65白点,sRGB):

| X |   | 0.4124564  0.3575761  0.1804375 | | R |
| Y | = | 0.2126729  0.7151522  0.0721750 | | G |
| Z |   | 0.0193339  0.1191920  0.9503041 | | B |

CIE Lab与Luv:让“距离”代表“差异”

XYZ虽然绝对,但它有个问题——人眼对颜色的感知不是线性的。你想想看,在XYZ空间里,两个点之间的欧氏距离,并不代表人眼感觉到的颜色差异大小。

这就尴尬了。做AWB调优时,我们需要量化“这个颜色偏了多少”。如果度量标准不准,调优就是瞎调。

于是CIE Lab和Luv诞生了。它们都是“感知均匀”的色彩空间。

  • CIE Lab:L代表亮度,a代表红绿轴,b代表黄蓝轴。Lab空间里,两个颜色之间的欧氏距离,大致等于人眼感知的色差。
  • CIE Luv:同样感知均匀,但更适用于加色混合(比如显示器)。Luv的u、v轴与色度图更接近。

注意:Lab和Luv都是从XYZ转换来的,不是直接从RGB转的。所以流程是:RGB → XYZ → Lab/Luv。我曾经见过有人直接把RGB转Lab,结果颜色完全乱套了。

Lab转XYZ的公式(部分):

// 假设 L* 在 [0, 100], a*, b* 在 [-128, 127]
// 先计算 f(Y/Yn)
fy = (L* + 16) / 116
fx = a* / 500 + fy
fz = fy - b* / 200

// 然后反推 X, Y, Z
Y = Yn * (fy^3)  // 如果 fy > 0.008856
X = Xn * (fx^3)
Z = Zn * (fz^3)

色度图与普朗克轨迹:AWB的“地图”

好了,现在有了各种色彩空间,我们怎么用它们做AWB?

色度图(Chromaticity Diagram)就是把XYZ的亮度信息去掉,只看色度。常用的有CIE xy色度图。x和y由XYZ计算得来:

x = X / (X + Y + Z)
y = Y / (X + Y + Z)
z = 1 - x - y

在xy色度图上,所有可见光颜色都落在“马蹄形”区域内。这个马蹄形的边界就是单色光(光谱色)。

普朗克轨迹(Planckian Locus)是色度图上的一条曲线。它代表了不同色温下黑体辐射的颜色。从低色温的橙红色(2000K),到中性白(5500K),再到高色温的蓝色(10000K)。

AWB的核心思想:找到图像中“应该是白色”的区域,计算它的色度坐标,然后沿着普朗克轨迹找到对应的色温,最后做增益补偿。

我在项目中常用的做法是:

  1. 把图像转到XYZ空间
  2. 计算每个像素的xy色度
  3. 在色度图上找到离普朗克轨迹最近的点
  4. 根据偏移量计算R、B增益

嗯,这里要注意:实际场景中的光源不一定正好落在普朗克轨迹上。比如荧光灯、LED灯,它们的色度点往往偏离轨迹。这时候就需要更复杂的算法了。

知识体系总览

下面这张图是我自己整理的色彩空间关系图,帮你理清思路:

色彩空间知识体系 传感器 RAW 数据 RGB / sRGB 色彩空间 CIE 1931 XYZ 色彩空间 CIE Lab 色彩空间 CIE Luv 色彩空间 色度图 (xy) + 普朗克轨迹 从传感器数据到人眼感知的完整色彩链路

从这张图你可以看到,整个色彩链路是从传感器RAW数据开始的。先转到RGB/sRGB做标准化,再转到XYZ做绝对度量,最后根据需求转到Lab或Luv做感知分析。而色度图和普朗克轨迹,则是我们做AWB时的“导航工具”。

避坑指南:我曾经在调一款手机摄像头时,发现AWB在室内荧光灯下总是偏绿。查了两天才发现,问题出在色度图上的荧光灯位置偏离普朗克轨迹太远,而我的算法只考虑了轨迹上的点。后来我加了一个“偏离补偿”模块,问题就解决了。

好了,色彩空间的基础就聊到这儿。记住一句话:没有正确的色彩空间,就没有正确的白平衡。下一节我们会深入AWB的具体算法实现,到时候这些色彩空间知识都会用上。


公众号:蓝海资料掘金营,微信deep3321