ICCV 2019【从颜色科学到相机】03_RGB 不等于 sRGB,Gamma、Lab 和“亮度”

颜色与相机成像专题(3):RGB 不等于 sRGB,Gamma、Lab 和"亮度"一次讲清

把 RGB 数组除以 255 就是线性图像吗?灰度图是否代表场景亮度?本文给出可直接用于代码的 sRGB 公式,并解释常见色彩空间各自解决什么问题。

关键词:sRGB、Gamma、CIE Lab、Luminance、Luma

1. "这是 RGB 图像"缺少了哪些信息?

RGB 表示三个分量,但要准确解释颜色,至少还需要知道基色、白点和传递函数。数值范围、通道顺序以及图像是否经过渲染也很重要。

同样的 ( 0.7 , 0.2 , 0.1 ) (0.7,0.2,0.1) (0.7,0.2,0.1),在 camera RGB、sRGB 和 Display P3 中可能代表不同颜色。把 camera RGB 的数组直接交给默认按 sRGB 显示的软件,不构成正确的颜色转换。

名称 数据含义 关键提醒
camera RGB 设备光谱响应对应的通道值 随传感器变化
线性 sRGB sRGB 基色、D65 白点下的线性分量 仍可能已经过相机渲染
编码 sRGB 对线性 sRGB 应用规定的传递函数 常见 8 位图像通常在此域
CIE XYZ 标准观察者下的三刺激值 注意白点和数值尺度
CIE Lab 相对于参考白的近似感知均匀表示 不存在对所有场景通用的默认白点

2. sRGB 规定了什么?

sRGB 使用规定的红、绿、蓝基色和 D65 白点,还规定非线性编码。它使不同设备有机会一致地呈现同一组颜色值,但不要求相机忠实还原场景。

讲义将 sRGB 与 Rec.709 放在一起介绍,容易让人以为二者完全等同。准确地说,它们共享基色色度和 D65 白点,但传递函数及使用约定不同,视频链路还可能涉及不同的量化范围。不能因此混用所有公式。

对以 D65 为参考、 Y Y Y 通常归一化到 1 的 XYZ,转换到线性 sRGB 可写为:

R G B = 3.2404542 − 1.5371385 − 0.4985314 − 0.9692660 1.8760108 0.0415560 0.0556434 − 0.2040259 1.0572252 X Y Z \begin{bmatrix} R \\ G \\ B \end{bmatrix} = \begin{bmatrix} 3.2404542 & -1.5371385 & -0.4985314 \\ -0.9692660 & 1.8760108 & 0.0415560 \\ 0.0556434 & -0.2040259 & 1.0572252 \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} RGB = 3.2404542−0.96926600.0556434−1.53713851.8760108−0.2040259−0.49853140.04155601.0572252 XYZ

如果输入 XYZ 的参考白是 D50,通常需要先进行适当的色适应,再使用 D65 版本矩阵。不能把不同白点的 XYZ 数值不加说明地代入同一矩阵。

3. sRGB 的精确编码和解码

把一个线性分量记为 u u u,编码分量记为 v v v,以下公式限定在非负、归一化的常规范围内:

v = { 12.92 u , u ≤ 0.0031308 1.055 u 1 / 2.4 − 0.055 , u > 0.0031308 v= \begin{cases} 12.92u,&u\le 0.0031308\\ 1.055u^{1/2.4}-0.055,&u>0.0031308 \end{cases} v={12.92u,1.055u1/2.4−0.055,u≤0.0031308u>0.0031308

逆变换为:

u = { v / 12.92 , v ≤ 0.04045 ( ( v + 0.055 ) / 1.055 ) 2.4 , v > 0.04045 u= \begin{cases} v/12.92,&v\le 0.04045\\ ((v+0.055)/1.055)^{2.4},&v>0.04045 \end{cases} u={v/12.92,((v+0.055)/1.055)2.4,v≤0.04045v>0.04045

口语中的"Gamma 约为 2.2"只是近似,不能替代标准的分段公式。 1 / 2.2 1/2.2 1/2.2 也不等于立方根指数 1 / 3 1/3 1/3;讲义对心理物理学的直觉介绍不应作为实现公式。

图 1:比较线性输入与编码值,黑白等权混合的结果。

一个很有用的检查点:编码值 v = 0.5 v=0.5 v=0.5 对应线性值约为 0.214 0.214 0.214,不是 0.5 0.5 0.5。8 位中灰数值 128 经解码约为 0.216 0.216 0.216。

4. 为什么平均、模糊和插值要关心 Gamma?

黑与白在光量意义上等权混合,应先在线性域计算:

u m i x = ( 0 + 1 ) / 2 = 0.5 u_{\mathrm{mix}}=(0+1)/2=0.5 umix=(0+1)/2=0.5

编码后约为 0.735 0.735 0.735,对应 8 位值约 188。如果直接平均两个编码值,得到 v = 0.5 v=0.5 v=0.5,约为 128,显示结果更暗。

这不是所有图像操作都必须线性化的理由。物理光量混合应在相应线性域完成;某些艺术编辑和感知优化则可能有意使用其他空间。应先确定运算目标,再选数据表示。

下面的实现不依赖图像库,输入输出均为浮点数组:

python 复制代码
import numpy as np

def srgb_decode(v):
    v = np.asarray(v, dtype=np.float64)
    if np.any((v < 0) | (v > 1)):
        raise ValueError("Expected encoded sRGB in [0, 1]")
    return np.where(v <= 0.04045, v / 12.92,
                    ((v + 0.055) / 1.055) ** 2.4)

def srgb_encode(u):
    u = np.asarray(u, dtype=np.float64)
    if np.any((u < 0) | (u > 1)):
        raise ValueError("Expected linear sRGB in [0, 1]")
    return np.where(u <= 0.0031308, 12.92 * u,
                    1.055 * u ** (1 / 2.4) - 0.055)

print(srgb_decode(0.5))  # 约 0.214041
print(srgb_encode(0.5))  # 约 0.735357

实际颜色变换可能产生负值或大于 1 的值。这些值应在明确的色域映射、曝光或输出策略下处理,不要在每个中间步骤都盲目裁剪。上面函数为了让教学边界清晰,直接拒绝超范围输入。

5. Luminance 和 Luma,不是同一种"Y"

对线性 sRGB,XYZ 的相对亮度分量可近似写为:

Y = 0.2126 R + 0.7152 G + 0.0722 B Y=0.2126R+0.7152G+0.0722B Y=0.2126R+0.7152G+0.0722B

系数经过四舍五入。若使用较高精度矩阵,会出现 0.7151522 0.7151522 0.7151522 等更精细的值。

而类似下面的公式经常用于非线性编码分量:

Y ′ = 0.299 R ′ + 0.587 G ′ + 0.114 B ′ Y'=0.299R'+0.587G'+0.114B' Y′=0.299R′+0.587G′+0.114B′

这是一种常见的 BT.601 类 luma 加权形式。 Y ′ Y' Y′ 是用于编码或处理的亮度样分量,不等于 CIE 的线性 Y Y Y。灰度转换函数返回的数组不能仅凭名称就解释为物理亮度。

还要再问一步:即使用正确公式计算了线性化照片的 Y Y Y,它通常也只是渲染后图像的相对亮度。没有辐射标定,不能宣称得到场景的 cd/m²。

6. 为什么还需要 Lab、HSV 和 YCbCr?

XYZ 便于定义和转换颜色,却不感知均匀。同样大小的 XYZ 数值差,在不同颜色区域可能产生不同强度的视觉差异。

图 2:讲义 PDF 第 101 页,以 MacAdam 椭圆说明颜色差异的感知尺度并不处处相同。

Lab 将颜色表示为明度 L ∗ L^* L∗ 和两条对立色轴 a ∗ , b ∗ a^*,b^* a∗,b∗,通常用于颜色差异分析。给定参考白 ( X n , Y n , Z n ) (X_n,Y_n,Z_n) (Xn,Yn,Zn),例如:

L ∗ = 116 f ( Y / Y n ) − 16 L^*=116f(Y/Y_n)-16 L∗=116f(Y/Yn)−16

其中 f f f 是低值区线性、高值区立方根的分段函数。 L ∗ L^* L∗ 是 lightness(明度),不是物理 luminance。

Lab 转换必须明确参考白。ICC 工作流常见 D50;部分图像库常用 D65;不能把任一实现的习惯写成 Lab 的普遍默认值。不同库还可能把 L ∗ L^* L∗ 映射到 0~255,并给 a ∗ , b ∗ a^*,b^* a∗,b∗ 添加偏移。

HSV 便于按色相、饱和度等直觉属性操作,但不是感知均匀空间。YCbCr 常用于图像与视频编码,以 luma 和色差信号组织信息;具体矩阵、范围与标准应明确。

CIEDE2000 是基于 Lab 的色差公式。它不是百分制分数,也没有普遍的 0~100 硬上界。"小于 2 就看不出差别"只能作为特定观察条件下的经验说法。

7. 写代码前的五项检查

  1. 输入是 RGB 还是 BGR,整数还是浮点,范围是什么?
  2. 数据属于 camera RGB、sRGB、P3 还是其他空间?
  3. 当前处于线性域还是编码域?
  4. 白点、观察者、ICC 配置是否一致?
  5. 目标是物理运算、显示呈现,还是感知距离?

参考与出处

  • Michael S. Brown, PDF 第 85~105、165、190 页。
  • sRGB 的标准依据为 IEC 61966-2-1;本文给出常用标准矩阵与分段传递函数,未将讲义中的近似式作为精确实现。
  • 本文对 Rec.709、参考白、Lab 与 CIEDE2000 范围作了必要的限定和校正。

上一篇:光谱与 CIE 颜色科学

下一篇:RAW 与传感器前端处理

返回专题目录

相关推荐
李航198313 小时前
AI定制柜建模,需要详细的建模规范和标准流程
人工智能·python·计算机视觉·ai·ai编程
hahaha601613 小时前
色彩恒常性概述
人工智能·嵌入式硬件·数码相机·计算机视觉
hahaha601615 小时前
Shades-of-Gray (SoG) 算法--白平衡算法
人工智能·嵌入式硬件·算法·计算机视觉
Latchh15 小时前
前端导出的JPEG红字发糊,质量要拉到100才清楚
前端·图像处理·人工智能·计算机视觉
YOLO数据集集合18 小时前
红外缺陷检测数据集 | 红外检测 缺陷识别 裂缝检测 渗漏检测 目标检测9145期
人工智能·目标检测·机器学习·计算机视觉·目标跟踪·智慧城市
lank_M18 小时前
抠图换深色背景有白边?先分清直通和预乘alpha
图像处理·人工智能·计算机视觉·状态模式
一木 之林18 小时前
DDPM扩散模型代码实战:前向加噪造数据、U-Net噪声预测与反向生成手写数字
人工智能·算法·计算机视觉
这张生成的图像能检测吗20 小时前
(论文速读)DefectDiffu:基于一致性建模的少样本工业缺陷图像生成
人工智能·深度学习·计算机视觉·异常检测·少样本学习·扩散生成
shoufeipin90hou1 天前
4K 线扫相机的行频匹配:带速一变,图像为什么会变形
数码相机·计算机视觉