同2°观察者下D65与C照明体的色彩转换方法咨询
首先明确:当观察者角度一致(均为2°)时,不同照明体之间的XYZ色彩是可以转换的,核心是通过**色彩适应变换(Chromatic Adaptation Transform, CAT)**实现,这也是在线色彩转换工具的底层逻辑。
一、数学原理:色彩适应变换
色彩适应的本质是将某一照明体下测得的XYZ值,转换为另一照明体下的感知等效XYZ值。常用的Bradford变换精度较高,步骤如下:
1. 归一化XYZ值
将照明体C下的原始XYZ值($X_C,Y_C,Z_C$)转换为相对色值$R,G,B$,公式为:
$$
\begin{bmatrix} R \ G \ B \end{bmatrix} = M_{Bradford} \times \begin{bmatrix} X_C \ Y_C \ Z_C \end{bmatrix}
$$
其中Bradford变换矩阵为:
$$
M_{Bradford} = \begin{bmatrix}
0.8951 & 0.2664 & -0.1614 \
-0.7502 & 1.7135 & 0.0367 \
0.0389 & -0.0685 & 1.0296
\end{bmatrix}
$$
2. 计算并应用适应系数
先获取2°观察者下两个照明体的标准白点XYZ值:
- 照明体C:$X_{WC}=98.074, Y_{WC}=100.0, Z_{WC}=118.232$
- 照明体D65:$X_{WD65}=95.047, Y_{WD65}=100.0, Z_{WD65}=108.883$
将两个白点分别代入第一步的变换矩阵,得到各自的$R_W,G_W,B_W$,再计算适应系数:
$$
k_R = \frac{R_{WD65}}{R_{WC}}, \quad k_G = \frac{G_{WD65}}{G_{WC}}, \quad k_B = \frac{B_{WD65}}{B_{WC}}
$$
将第一步得到的$R,G,B$分别乘以对应系数,得到适应后的$R',G',B'$:
$$
R' = k_R \times R, \quad G' = k_G \times G, \quad B' = k_B \times B
$$
3. 逆变换得到目标照明体下的XYZ
用Bradford变换的逆矩阵将$R',G',B'$转换为D65照明体下的$X_{D65},Y_{D65},Z_{D65}$:
$$
\begin{bmatrix} X_{D65} \ Y_{D65} \ Z_{D65} \end{bmatrix} = M_{Bradford}^{-1} \times \begin{bmatrix} R' \ G' \ B' \end{bmatrix}
$$
Bradford逆矩阵为:
$$
M_{Bradford}^{-1} = \begin{bmatrix}
0.9869929 & -0.1470543 & 0.1599627 \
0.4323053 & 0.5183603 & 0.0493344 \
-0.0085287 & 0.0400428 & 0.9684867
\end{bmatrix}
$$
二、后续sRGB转换流程
得到D65/2下的XYZ值后,即可用标准流程转换为sRGB:
- 归一化XYZ值(除以D65白点的对应数值):
$$
x = X_{D65}/X_{WD65}, \quad y = Y_{D65}/Y_{WD65}, \quad z = Z_{D65}/Z_{WD65}
$$ - 线性变换得到线性RGB:
$$
\begin{bmatrix} R_{linear} \ G_{linear} \ B_{linear} \end{bmatrix} = \begin{bmatrix}
3.2406 & -1.5372 & -0.4986 \
-0.9689 & 1.8758 & 0.0415 \
0.0557 & -0.2040 & 1.0570
\end{bmatrix} \times \begin{bmatrix} x \ y \ z \end{bmatrix}
$$ - 伽马校正得到最终sRGB:
$$
sRGB = \begin{cases}
1.055 \times (value)^{1/2.4} - 0.055 & \text{if } value > 0.0031308 \
12.92 \times value & \text{if } value \leq 0.0031308
\end{cases}
$$
最后将结果限制在0~255范围内即可。
三、VBA实现注意事项
- 所有计算使用浮点型数据,避免整数运算导致的精度损失
- 严格使用2°观察者对应的标准白点XYZ值,不可混淆10°观察者的参数
- 伽马校正的分支判断要准确,处理线性RGB值为负或超过1的情况
内容的提问来源于stack exchange,提问作者NiikkyN

