RGB 颜色空间

RGB 颜色空间几乎是生活中最常见的颜色空间,它是一个加色系统,通过三个基色的混合来描述其中的颜色。最常见的 RGB 颜色空间是 sRGB(standard Red Green Blue),由惠普和微软在 1996 年共同推出,并逐渐获得各行业和软件的广泛支持。

以 sRGB 为代表的 RGB 颜色空间主要包含三部分定义:色度学上的 RGB 定义、非线性传递函数和观看环境。sRGB 定义红绿蓝的 xy 色度坐标为:(0.64, 0.33)、(0.30, 0.60)、(0.15, 0.06),根据三色的比例不同,能混合出不同的白点,还定义白点坐标为(0.3127, 0.3290),以何种比例能混合出定义的白点需要计算得到,也是转换的关键。

转换的顺序是 RGB -> 线性 RGB -> XYZ。线性 RGB 到 XYZ 的转换通过一个矩阵实现。

构建转换矩阵

色度坐标的混合

如何确定三个色度坐标混合后的新色度坐标?

首先,将 xy 色坐标变换到 XYZ 三刺激值,Z 在后续的混合中不重要,此处省略其变换。

$$ \begin{align*} &X+Y+Z=\frac{Y}{y} \\ &X=x(X+Y+Z)=\frac{xY}{y} \\ \end{align*} $$

两个或多个三刺激值求和后再回到 xyY 色坐标。

$$ \begin{align*} & Y=Y_{1}+Y_{2}+Y_{3} \\ & X=\frac{x_{1}Y_{1}}{y_{1}}+\frac{x_{2}Y_{2}}{y_{2}}+\frac{x_{3}Y_{3}}{y_{3}} \\ & X+Y+Z=\frac{Y_{1}}{y_{1}}+\frac{Y_{2}}{y_{2}}+\frac{Y_{3}}{y_{3}} \\ \end{align*} $$

令 $X+Y+Z=S$,混合后的色度坐标为:

$$ \begin{align*} \\ & y=\frac{Y}{S} \\ & x=\frac{X}{S} \end{align*} $$

即:

$$ \begin{align*} &S=\frac{Y}{y} \\ &X=xS=\frac{xY}{y} \end{align*} $$

当三原色的色度坐标和白点色度坐标已知时,可构建如下的方程组。

$$ \left\{ \begin{align*} & Y_{1}+Y_{2}+Y_{3}=Y \\ & \frac{1}{y_{1}}Y_{1}+\frac{1}{y_{2}}Y_{2}+\frac{1}{y_{3}}Y_{3}=\frac{Y}{y} \\ & \frac{x_{1}}{y_{1}}Y_{1}+\frac{x_{2}}{y_{2}}Y_{2}+\frac{x_{3}}{y_{3}}Y_{3}=\frac{xY}{y} \end{align*} \right. $$

用矩阵表示为:

$$ \begin{bmatrix} 1 & 1 & 1 \\ \frac{1}{y_1} & \frac{1}{y_2} & \frac{1}{y_3} \\ \frac{x_1}{y_1} & \frac{x_2}{y_2} & \frac{x_3}{y_3} \end{bmatrix} \begin{bmatrix} Y_1 \\ Y_2 \\ Y_3 \end{bmatrix} = \begin{bmatrix} Y \\ \frac{Y}{y} \\ \frac{xY}{y} \end{bmatrix} $$

通常将 Y 设为 1,可求解得到三原色按什么比例(每个基色的亮度 Y)混合能获得指定的白点。

转换矩阵

求得三个基色的 xyY 后,将其转换为 XYZ,不难注意到此时已经计算出 RGB 空间中基向量对应的 XYZ 三刺激值。

因此,RGB 到 XYZ 的转换矩阵如下,如需从 XYZ 到 RGB,只需求逆矩阵。

$$ \begin{bmatrix} X_{r} & X_{g} & X_{b} \\ Y_{r} & Y_{g} & Y_{b} \\ Z_{r} & Z_{g} & Z_{b} \\ \end{bmatrix} \begin{bmatrix} R \\ G \\ B \end{bmatrix} = \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} $$

还有高手

Claude 3.7 Sonnet Thinking 的方法更为简洁直观:

  1. 首先将三原色及白点的 Y 值预设为 1,基于此条件计算出它们对应的 XYZ 值。

  2. 求解三原色的 XYZ 乘以一个怎样的系数矩阵能得到白点的 XYZ。(XYZ 可以线性相加)

  3. 转置三原色 XYZ 与系数矩阵的乘积。

非线性传递函数

为了更好的适应人眼的感知特性,RGB 空间中的值通常会经过非线性传递函数,将线性 RGB 转换为非线性 RGB。例如,sRGB 选用了一个接近伽马 2.2 的非线性传递函数,但修正了逆变换时在零附近可能存在的问题。

从线性 sRGB 到非线性 sRGB 的转换函数为,虽然指数上是 2.4,但实际上它更接近于 $x^{2.2}$。

$$ \begin{align*} & R' = \begin{cases} 12.92R & R \leq 0.0031308 \\ 1.055R^{1/2.4}-0.055 & R > 0.0031308 \end{cases} \end{align*} $$

思考

如何判断一个给定的三刺激值是否在某个 RGB 空间内?

How to determine if given XYZ tristimulus values fall within a color gamut.
The gamut is defined by four CIE xy coordinates representing red, green, blue, and white.
Please provide the Python code.

这个提问,只有 Deepseek R1 能够在不联网的情况下给出正确的答案(大概要输出一万 tokens,多数平台部署的 R1 没有这么长的输出)。

Grok 3 Deep Research 则找到了一个 StackOverflow 的答案,Gemini 2.0 Pro 提及了可能需要在三维色域中计算,其它模型则都不能做出正确回答。

Update: Claude 3.7 Sonnet 0219 无需推理就能给出部分正确的答案(省略了如何从四个 xy 到三个 XYZ)。推理之后可以得到正确答案。