3. sRGB色彩空间:定义、标准、转换矩阵与Gamma曲线

3.1 sRGB色彩空间概述

sRGB(standard Red Green Blue)是由惠普与微软于1996年共同制定的标准色彩空间,旨在统一CRT显示器、打印机与互联网图像的色彩表现。它基于ITU-R BT.709原色,采用与CRT显示器光电转换特性近似的Gamma曲线,成为Web、消费电子与嵌入式显示系统的事实标准。

核心定位:sRGB是面向8位/通道、低动态范围(LDR)显示设备的色彩空间,覆盖CIE 1931色度图中约35%的色域,是嵌入式显示子系统最基础的色彩处理目标空间。

3.2 色度参数与标准原色

sRGB色彩空间在CIE 1931 xy色度图中的原色坐标与白点坐标如下表所示:

色度坐标 R (红) G (绿) B (蓝) 白点 D65
x 0.6400 0.3000 0.1500 0.3127
y 0.3300 0.6000 0.0600 0.3290
Y (亮度系数) 0.2126 0.7152 0.0722 —

亮度系数(Luminance Coefficients)用于RGB到亮度的线性转换:Y = 0.2126·R_lin + 0.7152·G_lin + 0.0722·B_lin,这是色彩空间转换与图像灰度化的重要依据。

sRGB色域在CIE 1931色度图中的三角形表示 R (0.640, 0.330) G (0.300, 0.600) B (0.150, 0.060) D65 (0.3127, 0.3290) sRGB色域覆盖约35%的CIE 1931可见色域,三角形顶点对应BT.709原色

3.3 Gamma曲线:光电转换与电光转换

sRGB的Gamma曲线分为两段:线性段与幂律段,用于模拟CRT显示器的非线性响应,同时避免低亮度量化噪声。曲线定义如下:

// sRGB 非线性编码函数(OETF:光电转换,线性→非线性)
// 输入:线性值 C_linear ∈ [0, 1]
// 输出:非线性值 C_srgb ∈ [0, 1]
float srgb_oetf(float C_linear) {
    if (C_linear <= 0.0031308f) {
        return 12.92f * C_linear;
    } else {
        return 1.055f * powf(C_linear, 1.0f / 2.4f) - 0.055f;
    }
}

// sRGB 非线性解码函数(EOTF:电光转换,非线性→线性)
// 输入:非线性值 C_srgb ∈ [0, 1]
// 输出:线性值 C_linear ∈ [0, 1]
float srgb_eotf(float C_srgb) {
    if (C_srgb <= 0.04045f) {
        return C_srgb / 12.92f;
    } else {
        return powf((C_srgb + 0.055f) / 1.055f, 2.4f);
    }
}
调试要点:在嵌入式显示链路中,sRGB Gamma解码(EOTF)是色彩空间转换的第一步。如果输入图像已标记为sRGB,必须先做EOTF得到线性RGB,才能进行后续的色域矩阵乘法与HDR合成。
sRGB Gamma曲线:线性输入 vs 非线性输出 线性输入 (C_linear) 非线性输出 (C_srgb) 0 0.5 1.0 0 0.5 1.0 线性 (γ=1.0) 拐点 (0.00313, 0.04045) 低亮度区采用12.92倍线性缩放,高亮度区采用幂指数1/2.4的幂律映射

3.4 RGB到XYZ的转换矩阵

sRGB色彩空间与CIE 1931 XYZ色彩空间之间的线性转换矩阵,基于D65白点与BT.709原色推导。转换公式如下:

// sRGB (线性) → CIE XYZ (D65)
// 输入:R_lin, G_lin, B_lin ∈ [0, 1]
// 输出:X, Y, Z
// 矩阵系数精确到6位小数
| X |   | 0.412456  0.357576  0.180437 | | R_lin |
| Y | = | 0.212673  0.715152  0.072175 | | G_lin |
| Z |   | 0.019334  0.119192  0.950304 | | B_lin |

// CIE XYZ (D65) → sRGB (线性)
// 逆矩阵
| R_lin |   |  3.240454  -1.537138  -0.498531 | | X |
| G_lin | = | -0.969266   1.876011   0.041556 | | Y |
| B_lin |   |  0.055643  -0.204026   1.057225 | | Z |
常见错误:直接对8位sRGB非线性值做矩阵乘法,会导致色相偏移与亮度失真。正确的链路是:
sRGB(8bit) → 归一化 → EOTF解码 → 线性RGB → 矩阵乘法 → XYZ
在嵌入式调试中,务必在矩阵乘法前插入Gamma解码验证点。

3.5 色彩空间转换完整链路

在显示子系统中,sRGB色彩空间转换的完整处理链路如下:

  1. 输入归一化:将8位整数[0, 255]映射到浮点[0, 1]。
  2. Gamma解码(EOTF):应用sRGB EOTF将非线性值转换为线性光强。
  3. 色域矩阵乘法:将线性sRGB转换为目标色彩空间(如XYZ、DCI-P3、BT.2020)。
  4. 亮度映射与色调映射:根据目标显示设备的峰值亮度与色域边界做裁剪或压缩。
  5. Gamma编码(OETF):将线性值重新编码为目标色彩空间的非线性值,输出到显示接口。
sRGB色彩空间转换处理链路 sRGB 输入 8bit [0,255] 归一化 ÷255 → [0,1] Gamma解码 EOTF (γ=2.4) 色域矩阵 sRGB→XYZ → 调试验证点 ① 归一化后检查数据范围 ② EOTF后检查线性度 ③ 矩阵乘法后检查白点坐标 XYZ (D65) DCI-P3 BT.2020 目标色彩空间(根据显示设备能力选择)

3.6 嵌入式调试中的常见问题

问题现象 可能原因 调试方法
图像整体偏暗 Gamma解码(EOTF)未执行,直接对非线性值做矩阵乘法 在矩阵乘法前插入线性度验证点,检查R_lin = G_lin = B_lin = 0.5时的输出
白色偏蓝或偏黄 白点坐标错误或矩阵系数精度不足 输入R=G=B=1.0,验证XYZ输出是否接近(0.9505, 1.0000, 1.0890)
色阶断层(Banding) 8位精度在Gamma解码后低亮度区量化不足 使用10位或12位内部精度,或在Gamma解码前做抖动(Dithering)
颜色过饱和 色域矩阵未做裁剪,导致目标色域外颜色被截断 在矩阵乘法后添加色域边界检测与色调映射(Gamut Mapping)

3.7 总结与最佳实践

  • 始终先解码后转换:sRGB Gamma解码(EOTF)是色彩空间转换的前提,不可跳过。
  • 使用高精度中间格式:线性RGB阶段建议使用16位定点或32位浮点,避免累积误差。
  • 验证白点与中性灰:输入中性灰(128,128,128),检查转换后是否保持中性。
  • 注意矩阵系数的精度:使用至少6位小数,避免色偏累积。
  • 嵌入式实现时查表优化:Gamma EOTF可使用256或1024点查找表(LUT)加速,减少浮点运算。
调试检查清单:
□ 确认输入图像色彩空间标记为sRGB
□ 验证归一化后数据范围在[0, 1]内
□ 检查EOTF拐点处(0.00313)的连续性
□ 验证矩阵乘法后白点坐标误差 < 0.001
□ 确认输出编码(OETF)与显示设备Gamma匹配