如何将指定观察者/光源的CIE 1931 XYZ颜色适配至另一参数组?
要完成从D65光源+2°观察者到D50光源+10°观察者的XYZ颜色适配,需要分两步操作:先统一观察者视角(2°→10°),再进行光源白点适配(D65→D50),以下是具体原理、公式和实现:
1. 核心原理
CIE 1931(2°观察者)和CIE 1964(10°观察者)是两套独立的XYZ颜色系统,需先通过转换矩阵将原颜色和原白点映射到同一观察者空间;之后使用Bradford适配变换(行业通用的白点适配方法)完成跨光源的颜色转换。
2. 关键转换公式与矩阵
2.1 2°→10°观察者的XYZ转换矩阵
[
\begin{bmatrix}
X_{10} \
Y_{10} \
Z_{10}
\end{bmatrix}
\begin{bmatrix}
0.987939 & -0.006944 & 0.015221 \
0.009246 & 0.981007 & 0.008575 \
-0.000371 & -0.008285 & 1.018480
\end{bmatrix}
\begin{bmatrix}
X_2 \
Y_2 \
Z_2
\end{bmatrix}
]
2.2 Bradford白点适配流程
Bradford变换通过将XYZ映射到锥形感知空间,再基于白点比例缩放,最后映射回XYZ,具体步骤:
转换到Bradford空间:
[
\begin{bmatrix}
R \
G \
B
\end{bmatrix}
=
\begin{bmatrix}
0.8951 & 0.2664 & -0.1614 \
-0.7502 & 1.7135 & 0.0367 \
0.0389 & -0.0685 & 1.0296
\end{bmatrix}
\begin{bmatrix}
X \
Y \
Z
\end{bmatrix}
]计算缩放因子:
设源白点(10°下的D65)为 ( W_{src}=(X_{w,s},Y_{w,s},Z_{w,s}) ),目标白点(10°下的D50)为 ( W_{dst}=(X_{w,d},Y_{w,d},Z_{w,d}) ),分别转换到Bradford空间后得到 ( (R_{w,s},G_{w,s},B_{w,s}) ) 和 ( (R_{w,d},G_{w,d},B_{w,d}) ),则缩放因子:
[
r = \frac{R_{w,d}}{R_{w,s}}, \quad g = \frac{G_{w,d}}{G_{w,s}}, \quad b = \frac{B_{w,d}}{B_{w,s}}
]缩放并转换回XYZ:
用缩放因子调整颜色的Bradford分量后,通过Bradford逆矩阵转回XYZ:
[
\begin{bmatrix}
X' \
Y' \
Z'
\end{bmatrix}
=
\begin{bmatrix}
0.9869929 & -0.1470543 & 0.1599627 \
0.4323053 & 0.5183603 & 0.0493344 \
-0.0085287 & 0.0400428 & 0.9684867
\end{bmatrix}
\begin{bmatrix}
rR \
gG \
b*B
\end{bmatrix}
]
3. 针对给定参数的计算示例
输入参数:
- 源颜色:( (X_2:44.6609, Y_2:76.106, Z_2:12.3365) )(D65+2°)
- D65+2°白点:( (95.047, 100, 108.883) )
- D50+10°白点:( (96.720, 100, 81.427) )
步骤1:转换到10°观察者空间
- 源颜色转换后:( (X_{10}:43.78, Y_{10}:75.18, Z_{10}:11.92) )
- D65白点转换后:( (X_{w,10}:94.86, Y_{w,10}:99.91, Z_{w,10}:110.04) )
步骤2:Bradford适配
- 源白点Bradford分量:( (93.79, 104.22, 110.13) )
- 目标白点Bradford分量:( (100.07, 101.78, 80.75) )
- 缩放因子:( r≈1.067, g≈0.9766, b≈0.7332 )
- 适配后颜色:( (X':47.43, Y':75.52, Z':9.52) )
4. 算法实现(Python)
import numpy as np # 2°观察者XYZ -> 10°观察者XYZ转换矩阵 CIE2_TO_CIE10 = np.array([ [0.987939, -0.006944, 0.015221], [0.009246, 0.981007, 0.008575], [-0.000371, -0.008285, 1.018480] ]) # Bradford适配矩阵及其逆矩阵 BRADFORD_M = np.array([ [0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296] ]) BRADFORD_M_INV = np.array([ [0.9869929, -0.1470543, 0.1599627], [0.4323053, 0.5183603, 0.0493344], [-0.0085287, 0.0400428, 0.9684867] ]) def xyz_cross_adapt(src_xyz, src_white_2deg, dst_white_10deg): # 1. 将源颜色和源白点转换到10°观察者空间 src_xyz_10 = CIE2_TO_CIE10 @ src_xyz src_white_10 = CIE2_TO_CIE10 @ src_white_2deg # 2. 计算白点的Bradford空间分量 src_white_brad = BRADFORD_M @ src_white_10 dst_white_brad = BRADFORD_M @ dst_white_10deg # 3. 计算适配缩放因子 scale_factors = dst_white_brad / src_white_brad # 4. 转换源颜色到Bradford空间并缩放 src_xyz_brad = BRADFORD_M @ src_xyz_10 dst_xyz_brad = src_xyz_brad * scale_factors # 5. 转换回XYZ空间 dst_xyz = BRADFORD_M_INV @ dst_xyz_brad return dst_xyz # 输入参数 source_xyz = np.array([44.6609, 76.106, 12.3365]) source_white_d65_2deg = np.array([95.047, 100, 108.883]) target_white_d50_10deg = np.array([96.720, 100, 81.427]) # 执行适配 adapted_xyz = xyz_cross_adapt(source_xyz, source_white_d65_2deg, target_white_d50_10deg) print(f"适配后的D50+10°颜色:X={adapted_xyz[0]:.2f}, Y={adapted_xyz[1]:.2f}, Z={adapted_xyz[2]:.2f}")
运行后输出:适配后的D50+10°颜色:X=47.43, Y=75.52, Z=9.52
内容的提问来源于stack exchange,提问作者orangeBall

