1167 字
6 分钟
RGB 为什么要转换成 YCbCr?从矩阵、码值范围到往返误差

相机 ISP 最终常得到 RGB,视频编码器却更喜欢 YCbCr。原因并不是 YCbCr“颜色更准确”,而是它把信号重新组织成一条亮度样信号 YY' 和两条色差信号 CbCbCrCr:视觉更敏感的结构集中在 YY',色度便可以使用不同的采样和压缩策略。

本文统一讨论经过传递函数编码的非线性 RGBR'G'B',并以归一化浮点和 8-bit 码值为例。若输入是场景线性 RGB,公式的物理含义并不相同。

从 RGB 到亮度与色差#

KrK_rKbK_b 是标准给出的系数,Kg=1KrKbK_g=1-K_r-K_b

Y=KrR+KgG+KbBY'=K_rR'+K_gG'+K_bB'Cb=BY2(1Kb),Cr=RY2(1Kr)Cb=\frac{B'-Y'}{2(1-K_b)},\qquad Cr=\frac{R'-Y'}{2(1-K_r)}

归一化定义中 YY' 通常位于 [0,1][0,1],色差以 0 为中性、理想范围约为 [0.5,0.5][-0.5,0.5]。数字编码再把色差中性点搬到中间码值。

矩阵转换实验室

改变 RGB 与标准,观察亮度 Y 和两条色差信号如何重新分配信息。

矩阵系数
Y′ 码值115
Cb 码值82
Cr 码值200

转换不是简单的固定矩阵。SDTV 常见 BT.601,HDTV 常见 BT.709,UHD/HDR 管线可能采用 BT.2020 非恒定亮度 YCbCr;它们的基色定义不同,因此系数也不同。分辨率只能提示可能采用哪个标准,不能替代明确的元数据。

实拍图像的 Y′、Cb、Cr 分量

同一张照片在矩阵变换后被拆成结构清晰的 Y′ 与两张以中性灰为零点的色差信号。

Y 可视化
显示分量
矩阵

Cb、Cr 为了显示而加上 0.5:中性区域呈灰色,亮暗分别代表正、负色差,并不是照片本身的亮度。

样片尺寸860 × 648
预览计算560 px 宽
许可CC0 1.0

样片:Baap8969 / Wikimedia Commons,CC0 1.0;本站缩放并转为 WebP。

Y′ 不是物理亮度 Y#

Y′ 不是 RGB 的平均值

不同标准由基色与白点推导出不同的亮度权重;绿色通常承担最多细节。

R′0.2126G′0.7152B′0.0722
标准

这里的撇号表示对非线性编码的 R′G′B′ 求 luma。它不是场景线性亮度,也不等同于光度学 luminance。

红权重 Kr0.2126
绿权重 Kg0.7152
蓝权重 Kb0.0722

撇号非常重要。YY' 是对 Gamma/OETF 编码后的 RGBR'G'B' 做加权得到的 luma,方便视频处理;色度学中的 YY 则是对线性光量的加权。二者数值和可加性都不同。

工程中常把 luma 口语化称为“亮度”,但做曝光合成、光照计算或物理颜色变换时,必须先确认数据是否线性。

逆变换为什么可行#

只要使用相同系数、保留浮点精度且不裁剪,矩阵是可逆的:

R=Y+2(1Kr)CrR'=Y'+2(1-K_r)CrB=Y+2(1Kb)CbB'=Y'+2(1-K_b)CbG=YKrRKbBKgG'=\frac{Y'-K_rR'-K_bB'}{K_g}

“RGB 转 YCbCr 会损失颜色”并不准确。损失来自后续量化、色度抽样、越界裁剪,或者编码与解码使用了不一致的标准。

Full Range 与 Limited Range#

Full Range 与 Limited Range

同一个归一化亮度会落到不同码值区间;范围元数据错配会抬黑或压白。

016235255
8-bit 范围

BT.601/709 的 studio swing 常用 Y′=16…235、Cb/Cr=16…240;脚位以外保留 headroom/footroom,不应随意当作非法值删除。

Y′126
中性 Cb128
中性 Cr128

8-bit full range 常把 YY' 映射到 0…255,把中性色差映射到 128。视频 limited range 常把标称 YY' 映射到 16…235、色差映射到 16…240:

Ycode=16+219YY_{code}=16+219Y'Ccode=128+224CC_{code}=128+224C

这些数值是编码约定,不是说 limited range 的画面必然更灰。正确解码会恢复相同归一化信号;误把 limited 当 full 会让黑位抬高、白位变暗,反向误读则会压黑和截白。

10-bit limited range 常相应扩展为亮度 64…940、色度 64…960。不能把 8-bit 常数机械用于其他位深。

量化怎样留下误差#

往返转换与量化误差

浮点矩阵可逆;真正留下误差的通常是量化、裁剪、范围误读与色度抽样。

原始 RGB
往返结果
矩阵

此处三通道采用同一位深并在 full range 量化;没有模拟 4:2:0、传输误码或定点矩阵舍入。

RMSE0.00148
Y′CbCr 码值99 · 154 · 215
量化级数256

定点实现还要决定矩阵系数精度、中间位宽、舍入方式和饱和策略。低位深下,相邻 RGB 可能量化到同一个 YCbCr 码字;逆变换只能得到该格点的代表值。

以下代码展示 full-range、BT.709 的浮点核心,输出色差仍以 0 为中心:

def rgb_to_ycbcr709(r, g, b):
kr, kb = 0.2126, 0.0722
kg = 1.0 - kr - kb
y = kr * r + kg * g + kb * b
cb = (b - y) / (2.0 * (1.0 - kb))
cr = (r - y) / (2.0 * (1.0 - kr))
return y, cb, cr

与色度抽样的关系#

YCbCr 的价值在于分离信息,不代表色度必然降采样。4:4:4 会为每个像素保留 Y′、Cb、Cr;4:2:2 和 4:2:0 才减少色度采样。RGB 也可以直接压缩,YCbCr 也可以无损保存。

典型输出链路是:

线性 RGB → OETF / Gamma → R′G′B′ → Y′CbCr 矩阵
→ 色度低通与抽样 → 量化 / 编码

解码按相反方向恢复,但色度下采样丢掉的空间频率不会凭空回来。

最容易踩的坑#

  1. 把 Y′ 当作线性光亮度参与曝光或合成;
  2. 只写“YCbCr”,没有记录 BT.601/709/2020 和范围;
  3. 编码用 BT.709、解码却按 BT.601,造成系统性色偏;
  4. 把 limited range 的 16 和 235 当作需要裁掉的脏数据;
  5. 混淆 YCbCr 数字分量与模拟视频中的 YPbPr;
  6. 在矩阵前后不受控地 clip,破坏可逆性;
  7. 把所有转换误差都归因于矩阵,忽略色度抽样和定点舍入。

验证清单#

  • 黑、白、中性灰是否保持 Cb=Cr=0Cb=Cr=0(编码后为中间码值);
  • RGB/CMY 基色和肤色是否使用同一矩阵往返;
  • full/limited、位深与容器元数据是否一致;
  • 浮点参考与定点实现的最大误差、平均误差;
  • 超范围信号与 headroom/footroom 的处理策略;
  • 色度抽样前是否有合适低通滤波。

YCbCr 不是更神秘的颜色模型,而是一种服务于视频处理和压缩的坐标变换。只要把矩阵标准、非线性状态、码值范围与位深写清楚,RGB 和 YCbCr 之间的转换就是可验证的工程步骤。

RGB 为什么要转换成 YCbCr?从矩阵、码值范围到往返误差
https://cloudsir.top/posts/how-rgb-ycbcr-conversion-works/
作者
CloudSir
发布于
2026-08-25
许可协议
CC BY-NC-SA 4.0
JPEG 怎样压缩一张图片?从 8×8 DCT 到量化与 Zigzag
AF 自动对焦系统总览:从选主体到驱动镜组