RGB与YUV转换原理:ITU-R BT.601与BT.709标准

好,咱们今天来聊聊RGB和YUV之间的转换。说实话,我刚入行那会儿,觉得这玩意儿不就是套公式嘛,有啥好学的?直到有一次,我在一个视频采集卡的项目里,发现采集出来的画面颜色怎么调都不对——人脸发绿,天空发紫。折腾了两天,最后发现是色彩空间标准搞混了。嗯,从那以后,我再也不敢小看这两个标准了。

为什么需要YUV?

先问个问题:为什么我们不直接用RGB,非要转成YUV?

原因其实很简单——人眼对亮度的敏感度远高于对颜色的敏感度。你想想看,黑白电视时代,一个亮度信号就能搞定一切。彩色电视要兼容黑白电视,就得把亮度信息单独拎出来。

YUV的核心思想就是:

  • Y — 亮度分量(Luma),说白了就是黑白图像
  • U / Cb — 蓝色色差分量
  • V / Cr — 红色色差分量

这样做的好处很明显:我们可以对Y保留全分辨率,对U和V进行下采样。人眼看不出来,但带宽省了一大半。我在做嵌入式摄像头调试时,就靠这个技巧把1080p的传输带宽砍掉了将近一半。

两个主流标准:BT.601 与 BT.709

说到转换公式,就绕不开两个标准。它们定义了RGB到YUV的转换矩阵。

特性 BT.601(标清) BT.709(高清)
应用场景 SDTV(720×576 / 720×480) HDTV(1280×720 / 1920×1080)
亮度权重 Y = 0.299R + 0.587G + 0.114B Y = 0.2126R + 0.7152G + 0.0722B
绿色权重 0.587(偏重) 0.7152(更重)
蓝色权重 0.114 0.0722(更轻)

关键点:BT.709给绿色分配了更高的权重。为什么?因为高清显示设备的绿色荧光粉效率更高,人眼对绿色也更敏感。这个差异直接导致同一个RGB值,用两个标准转出来的YUV完全不同。

矩阵变换公式详解

好,咱们上公式。别怕,我尽量讲得直白些。

BT.601 标准(标清)

RGB范围:0~255(8位),Y范围:16~235,Cb/Cr范围:16~240。

Y  =  0.299 * R + 0.587 * G + 0.114 * B
Cb = -0.169 * R - 0.331 * G + 0.500 * B + 128
Cr =  0.500 * R - 0.419 * G - 0.081 * B + 128

注意那个+128。Cb和Cr是有符号数,范围是-112~+112,加上128后映射到16~240。我刚开始做的时候,忘了加这个偏移量,结果画面全是紫绿色的——嗯,血的教训。

BT.709 标准(高清)

Y  =  0.2126 * R + 0.7152 * G + 0.0722 * B
Cb = -0.1146 * R - 0.3854 * G + 0.5000 * B + 128
Cr =  0.5000 * R - 0.4542 * G - 0.0458 * B + 128

对比一下两个标准的Y公式:

  • BT.601:绿色占0.587,红色占0.299
  • BT.709:绿色占0.7152,红色占0.2126

说白了,高清标准更依赖绿色通道。你在做高清视频处理时,如果发现绿色通道的噪声特别明显,别奇怪——它承载了最多的亮度信息。

逆变换:从YUV回到RGB

光会转不行,还得能转回来。逆变换矩阵就是正变换矩阵的逆矩阵。

BT.601 逆变换:

R = Y + 1.402 * (Cr - 128)
G = Y - 0.344 * (Cb - 128) - 0.714 * (Cr - 128)
B = Y + 1.772 * (Cb - 128)

BT.709 逆变换:

R = Y + 1.5748 * (Cr - 128)
G = Y - 0.1873 * (Cb - 128) - 0.4681 * (Cr - 128)
B = Y + 1.8556 * (Cb - 128)

注意:逆变换后的RGB值可能会超出0~255范围。一定要做钳位(clamp)处理。我曾经在一个FPGA项目里忘了加钳位,结果画面高光部分全是诡异的条纹——查了两天才找到原因。

知识结构图:RGB ↔ YUV 转换流程

下面这张图帮你理清整个转换链路:

RGB ↔ YUV 转换流程(BT.601 / BT.709) RGB 输入 R / G / B (0~255) 标准选择 BT.601 / BT.709 正变换矩阵 Y = 系数 × RGB YUV 输出 Y / Cb / Cr 逆变换矩阵 RGB = 系数 × (YUV-128) 钳位处理 Clamp(0, 255) RGB 输出 R / G / B (0~255) 提示:正变换和逆变换的系数必须匹配同一标准,混用会导致颜色失真

实际项目中的避坑指南

讲完理论,咱们聊聊实战中容易踩的坑。

经验1:我曾经在一个视频处理芯片的验证项目里,发现YUV转RGB后的图像总是偏绿。查了半天,发现是逆变换矩阵的系数精度不够——用了整数运算,舍入误差累积导致的。解决方案:用定点数Q16格式,保留足够的小数位。

经验2:BT.601和BT.709的Y范围都是16~235,不是0~255。如果你直接把0~255的RGB往里套,暗部细节全丢。我建议先做范围映射:RGB 0~255 → Y 16~235。

经验3:千万别混用标准!我见过有人用BT.601的正变换,然后用BT.709的逆变换——结果画面颜色完全不对。两个标准必须成对使用。

总结一下

RGB和YUV的转换,说白了就是一套线性变换。核心就三点:

  1. 选对标准 — 标清用BT.601,高清用BT.709
  2. 系数要准 — 正变换和逆变换的系数必须匹配
  3. 范围要钳 — 别忘了做钳位和范围映射

嗯,掌握了这些,你就能在视频处理项目里少走很多弯路。下次咱们聊聊YUV的采样格式——4:4:4、4:2:2、4:2:0到底有什么区别,以及怎么选。