LV025-从Bayer到YUV420的流程
一、 链路总览
相机从“看到光”到“存成一个文件”,中间要经过传感器采样、ISP 处理、色彩空间转换、色度下采样,最后才落盘。以 1920x1080、10bit Bayer 为例,整条链路是这样的:

| 阶段 | 数据形态 | 位宽 | 每像素占用 | 1920x1080 一帧 |
|---|---|---|---|---|
| 传感器输出 | Bayer RAW,每像素 1 个分量 | 10bit(RAW10 打包) | 1.25 字节 | 2.47 MB |
| ISP 内部 | 仍是 Bayer,每像素 1 个分量 | 10 ~ 12bit | 2 字节(解包后按 16bit 放) | 3.96 MB |
| 去马赛克之后 | 每像素 R、G、B | 8bit x 3 | 3 字节 | 5.93 MB |
| RGB → YUV | YUV444 | 8bit x 3 | 3 字节 | 5.93 MB |
| 色度下采样 4:2:0 | YUV420 | 8bit(Y) + 8bit(U/V)/4 | 1.5 字节 | 2.97 MB |
| 存储到文件 | I420 / NV12 裸数据 | 8bit | 1.5 字节 | 2.97 MB |
(表里的 MB 按 1024 进制换算,下同。)
这里有个反直觉的结论,先放出来:处理完的 YUV420(2.97MB)比传感器原始输出的 Bayer RAW(2.47MB)还大。为什么越大越处理、越处理越大,看完下面几步就明白了。
二、 从 sensor 到 YUV420 的处理流程
1. 采集:怎么从 sensor 拿到 Bayer 数据
前面那张表是从“传感器输出”开始算的。但数据不会凭空出现在 SoC 里——从配置 sensor 到 ISP 拿到 Bayer,中间还有一段采集通路:
sensor:光电转换 → 模拟增益 → ADC → 数字 RAW(Bayer)
↓ DVP 并口 或 MIPI CSI-2(差分,经 D-PHY)
SoC 侧:D-PHY → CSI2RX 控制器(或 VICAP)
↓
ISP 流水线(或先落到 DDR)1.1 先把 sensor 配起来
sensor 上电不会自己出图,主控要先通过 I2C 配置它的寄存器:分辨率、像素格式(RAW8/RAW10/RAW12)、帧率、曝光、增益,并读 OTP 里的模组标定数据。在 MIPI 体系里这条控制总线叫 CCI(Camera Control Interface),本质仍是 I2C,见《LV010-CCI》。
除总线外还得给足:外部时钟(MCLK,常见 24MHz,sensor 内部 PLL 再倍频出像素时钟)、电源时序(AVDD/DOVDD/DVDD)、reset/powerdown 控制。
1.2 sensor 内部怎么“产生” Bayer
光打进感光区转成电荷,经模拟增益、逐行 ADC 变成数字值。每个像素前盖着 R/Gr/Gb/B 之一,所以读出来每像素只有 1 个分量;ADC 的位深决定 RAW 位宽(10bit 最常用)。输出的行、帧节奏由同步信号控制。
1.3 数据怎么传出来:DVP 还是 MIPI
- MIPI CSI-2 + D-PHY(主流):数据走差分对,一般是 1 组时钟 + 1/2/4 组数据 lane。CSI-2 是协议层(打包、帧/行起始、虚拟通道、多路复用),D-PHY 是物理层(差分电气)。RAW10 之类的打包就发生在这一层,接口细节见《LV005-MIPI简介》和《LV005-MIPI-Sensor接口原理图》。
- DVP 并口(老式、低分辨率):PCLK + HSYNC + VSYNC + 8/10/12 位并行数据线,协议为 ITU-R BT.601/656、BT.1120。
1.4 SoC 侧怎么接住(以 RK3568 为例)
进入 SoC 后通常分两级:D-PHY 先把差分信号还原成字节流(PPI),再由 CSI2RX 控制器解析 CSI-2 包、还原成像素交给 ISP;CSI2RX 还支持 HDR 多帧、PDAF,并内置 FPN(固定模式噪声)去除。
到这里数据有两条去向:
- 处理通路:进 ISP 流水线(ISP 自带 CSI2RX,可直接对接 PHY 器件)。
- 直存通路:进 VICAP(Video Capture),由它把 DVP / MIPI(CSI2) 数据经 DMA、AXI 直接写进 DDR,不经过 ISP 处理。
ISP 的输入能力:DVP 支持 BT.601/656(RAW8/10/12、YUV422)与 BT.1120;MIPI 支持 1/2/4 lane、RAW8/10/12、YUV422;最大输入 4096x2304。
—— 《Rockchip_RK3568_TRM_Part2_V1.1-20210301.pdf》12.1 Overview(P.981)、12.3.1 CSI2RX(P.982–983)、Chapter 11 VICAP(P.948)
2. 传感器吐出来的 Bayer RAW(10bit)
2.1 Bayer 阵列:每个像素只有一个分量

传感器上每个感光点前面都盖着一片滤色片,只让红、绿、蓝中的一种光通过,所以一个像素只有一个分量。最常见的排布是 RGGB(第一行 R、Gr,第二行 Gb、B),此外还有 BGGR、GRBG、GBRG 三种,统称 Bayer 阵列(CFA)。
图中绿色写成了 Gr、Gb,而不是笼统的一个 G,这里说明一下:与 R 同一行的绿叫 Gr,与 B 同一行的绿叫 Gb。分开标是有原因的:
- 一是相位:只有区分开才能准确描述四种排布,RGGB 是
R Gr / Gb B,BGGR 是B Gb / Gr R,GRBG 是Gr R / B Gb,GBRG 是Gb B / R Gr;否则单说一个“绿”,根本讲不清它挨着的是 R 还是 B。 - 二是 Gr、Gb 在 ISP 里就是两条通道:相邻滤色片的串扰、微透镜的角度响应,会让两者对同一束光的响应略有差异,所以白平衡常常按 R/Gr/Gb/B 四通道各给一个增益,去马赛克时两者的插值路径也不同。
只写一个 G 不算错(不少资料为了简洁就是这么画的),但会丢掉这两层信息。
绿色占了一半的感光点,是因为人眼对绿色最敏感,而绿色也携带了最多的亮度信息。
Bayer 长什么样、插值算法怎么写,在《LV010-bayer格式》里已经讲过,这里不重复,只关注数据怎么流动。
2.2 10bit 是怎么装进字节里的
10bit 不是整数个字节,所以要么按 16bit(2 字节)对齐存放,要么打包。相机和 SoC 之间走 MIPI CSI-2(见《LV005-MIPI简介》),用的就是打包格式:
RAW10:4 个像素 -> 5 个字节
Byte0 ~ Byte3 = P0 ~ P3 的高 8 位
Byte4 = P0、P1、P2、P3 各自剩下的低 2 位(4 x 2 = 8 位,刚好凑一个字节)也就是图上画的那样:4 x 10bit = 40bit = 5Byte,平均 10bit/像素 = 1.25 字节/像素。
| RAW 格式 | 每像素位宽 | 打包方式 | 每像素占用 | 1920x1080 一帧 |
|---|---|---|---|---|
| RAW8 | 8bit | 1 像素 1 字节 | 1 字节 | 1.98 MB |
| RAW10 | 10bit | 4 像素 5 字节 | 1.25 字节 | 2.47 MB |
| RAW12 | 12bit | 2 像素 3 字节 | 1.5 字节 | 2.97 MB |
| RAW14 | 14bit | 4 像素 7 字节 | 1.75 字节 | 3.46 MB |
| RAW16 | 16bit | 1 像素 2 字节 | 2 字节 | 3.96 MB |
RAW10,1920x1080:
2073600 x 10 / 8 = 2592000 Byte = 2531.25 KB ≈ 2.47 MB注意“打包”只存在于传输和存储环节:ISP 拿到数据后一般会先解包成 16bit 对齐再来算,所以同一个 sensor,RAW10 传出来 2.47MB,到了 ISP 内部就变成 3.96MB 了。
3. ISP 把 Bayer 变成 RGB
3.1 处理链上每一步在做什么
数据从 sensor 出来之后,进的是 ISP(Image Signal Processor)。不同厂商的流程不完全一样,但大体都包含这些步骤:
| 步骤 | 干什么 | 位宽变化 |
|---|---|---|
| 黑电平校正 BLC | 减掉暗电流造成的底噪 | 10 ~ 12bit |
| 镜头阴影校正 LSC | 把镜头边缘偏暗的部分提亮 | 10 ~ 12bit |
| 坏点校正 DPC | 干掉个别坏掉的感光点 | 10 ~ 12bit |
| 去噪 NR | 抑制暗光下的噪声 | 10 ~ 12bit |
| 白平衡 AWB | R、G、B 各乘一个增益,让黑白灰不偏色 | 10 ~ 12bit |
| 去马赛克 Demosaic | 插值补齐每个像素缺失的两个分量 | 每像素变成 3 个分量 |
| 色彩校正 CCM | 3x3 矩阵,把 sensor 的 RGB 拉到目标色域(如 sRGB) | 8 ~ 12bit |
| Gamma / 色调曲线 | 把线性响应映射成符合人眼感知的曲线 | 8 ~ 12bit |
| 色彩空间转换 CSC | RGB → YUV | 8bit x 3 |
| 色度下采样 | YUV444 → YUV420 | 8bit x 1.5 |
至于为什么 ISP 内部要用比 sensor 更高的位深(比如 sensor 出 10bit、ISP 内部算 12bit),是为了在乘增益、做矩阵这些运算里少丢精度,最后再压到 8bit 输出。
这些步骤具体落在哪个硬件模块上,统一放在第三节讲。
3.2 去马赛克:1 个分量插成 3 个

前面说 Bayer 每个像素只有 1 个分量,但屏幕上的一个像素需要 R、G、B 三个分量。去马赛克就是根据周围像素的颜色值,把每 2x2 里缺失的分量插值补出来。
这是整条链路上唯一让数据量变大的一步:每像素从 1 个分量变成 3 个分量,字节数直接翻 3 倍。而且要清楚一点——插值出来的像素里,只有 1/3 是真实采到的值,剩下的都是算出来的,真实信息量始终只有原始 RAW 那么多。
4. RGB → YUV
4.1 为什么要转
因为接下来要“对色度下采样”,而前提是把亮度(Y)和色度(U/V)拆开。人眼对亮度敏感、对色度不敏感,只有拆开之后,才能单独把色度砍掉一半甚至四分之三而肉眼看不出区别。关于人眼特性和采样模式,见《LV020-YUV的格式》。
4.2 转换公式
以 8bit 全范围(JPEG / PC 常用)为例,BT.601:
Y = 0.299R + 0.587G + 0.114B
Cb = -0.169R - 0.331G + 0.500B + 128
Cr = 0.500R - 0.419G - 0.081B + 128BT.709(HD 常用):
Y = 0.2126R + 0.7152G + 0.0722B
Cb = -0.1146R - 0.3854G + 0.5000B + 128
Cr = 0.5000R - 0.4542G - 0.0458B + 128系数不同、还有 16~235 的“电视范围”和 0~255 的“全范围”之分,细节见《LV015-YUV与RGB转换》。
4.3 此时还是 YUV444
转完还是每个像素一个 Y + 一个 U + 一个 V,也就是 YUV444,每像素 3 字节,和 RGB 一样大。到这一步只是换了坐标系,一点空间都没省。
5. 色度下采样成 4:2:0

4:2:0 的含义、以及为什么是“2x2 的 4 个像素共用一组 UV”,在《LV020-YUV的格式》里详细讲过,这里一句话带过:U、V 在水平和垂直方向上都按 2:1 采样,亮度保持全采样。
单个像素占用 = 1Byte(Y) + 1Byte(U)/4 + 1Byte(V)/4 = 1.5Byte
1920x1080 一帧:
2073600 x 1.5 = 3110400 Byte = 3037.5 KB ≈ 2.97 MB到这一步,“3 字节/像素”变成了“1.5 字节/像素”,相比 RGB888 正好省一半,这也是 YUV420 成为相机、视频、播放器默认格式的原因。
6. 写进文件是什么样
6.1 YUV 文件里没有头信息
和 BMP、JPEG 不一样,YUV 文件没有任何头和元数据:没有宽高、没有采样格式、没有位深,只有一大坨裸像素。所以拿到一个 .yuv 文件,必须外部约定好“1920x1080 + I420”这样的信息才能正确显示(比如用 7yuv 打开时要手选格式)。
芯片之间传递时不是这样:buffer 一般自带描述信息(宽、高、stride、格式),落成“纯裸数据文件”之后这些就丢了。
6.2 I420 / NV12 / NV21 的排布

以 8x8 的图为例(Y 平面 8x8,U、V 平面各 4x4):
| 格式 | 排布 | 8x8 图的字节数 | 1920x1080 的字节数 |
|---|---|---|---|
| I420(YUV420P) | Y → U → V 三段分开 | 64 + 16 + 16 = 96 | 3110400 |
| YV12 | Y → V → U 三段分开 | 64 + 16 + 16 = 96 | 3110400 |
| NV12(YUV420SP) | Y 一段,UV 交织一段(UVUV…) | 64 + 32 = 96 | 3110400 |
| NV21 | Y 一段,VU 交织一段(VUVU…) | 64 + 32 = 96 | 3110400 |
1920x1080 的拆解:
Y 平面:1920 x 1080 = 2073600 Byte
U 平面:960 x 540 = 518400 Byte
V 平面:960 x 540 = 518400 Byte
合计 :3110400 Byte = 3037.5 KB ≈ 2.97 MB补充一点:硬件里为了内存对齐,Y 的行宽(stride)常会补齐到 16 / 32 / 64 的整数倍,此时 buffer(以及按 buffer 直接 dump 出来的文件)会比上面的理论值大一些。
6.3 一帧到底多大

| 格式 | 每像素占用 | 1920x1080 一帧 |
|---|---|---|
| Bayer RAW10(打包) | 1.25 字节 | 2.47 MB |
| Bayer RAW(解包后按 16bit) | 2 字节 | 3.96 MB |
| YUV420(8bit) | 1.5 字节 | 2.97 MB |
| YUV422(8bit) | 2 字节 | 3.96 MB |
| RGB888 / YUV444(8bit) | 3 字节 | 5.93 MB |
| YUV420(10bit,P010) | 2 字节 | 5.93 MB |
(P010 是把 10bit 的数放进 16bit 容器里存,所以又把体积拉回去了)
两个结论:
(1)YUV420(8bit)比 10bit 打包的 Bayer RAW 还大。色度下采样省下的是相对 RGB / YUV444 的体积,不是相对 RAW 的体积——RAW 才是这条链路上最“瘦”的形态,因为每个像素只有一个分量。
(2)到这一步为止都还是“一帧 2.97MB”的量级,真正把体积压下去的是后面的视频编码(H.264 / H.265 等),那属于视频编解码章节的内容。
三、 各步骤对应的 ISP 硬件模块
前面几节讲的是“做了什么”,这一节补上“由谁来做”。以 RK3568 的 ISP 为例,按 TRM 的划分,ISP 内部依次分四段:RAW Processing → RGB Processing → YUV Processing → Memory Interface(MI)(《Rockchip_RK3568_TRM_Part2_V1.1-20210301.pdf》P.982)。
1. 链路步骤 → ISP 模块对照
| 通用步骤 | RK3568 模块 | 说明 |
|---|---|---|
| 黑电平校正 BLC | BLS(Black-level-subtraction) | 从像素里减掉一个 DC 偏置;自动模式读传感器遮蔽像素求均值 |
| 镜头阴影校正 LSC | LSC | 每个像素乘各自的校正系数,系数在 sector 角点之间做双线性插值 |
| 坏点校正 DPC | DPCC | 静态 + 动态坏点/坏点簇校正,最大 3x3,静态表可存 2048 个位置 |
| 绿平衡 | GIC | Green Imbalance Correction,修正绿通道不平衡 |
| 去噪 NR | RAW 域 BAYNR(空域)/ BAY3D(时域);YUV 域 2DNR(YNR + CNR) | RAW 域分空域、时域两套,YUV 域再分亮度、色度 |
| 白平衡 AWB | RAWAWB(统计)+ AWB_GAIN(增益) | 统计在 RAW 域产生,增益按 R/Gr/Gb/B 四通道乘回 |
| 去马赛克 Demosaic | DEBAYER | 插值 + 滤波输出 RGB;黑白模式下三通道输出同值 |
| 色彩校正 CCM | CCM | 3x3 颜色校正矩阵 |
| Gamma | RAW 域 GAMMA_IN、RGB 域 GAMMA_OUT | 输入侧贴合 sensor 特性,输出侧贴合人眼感知 |
| 色彩空间转换 RGB→YUV | CSM | Color Space Matrix |
| 色度下采样到 4:2:0 | CONV422 + SELF_RESIZE / SCL | 先做 444→422,再由 Resize 完成 422→420 |
表内模块的功能见《Rockchip_RK3568_TRM_Part2_V1.1-20210301.pdf》P.986–989,模块基地址见同文档 P.991 的 Table 12-2。
2. ISP 内部按域分组
【RAW Processing(RAW / Bayer 域)】
FPN:固定模式噪声去除,实现在CSI2RX(MIPI)里BLS、DPCC、GAMMA_IN、LSC、GICHDRMGE(多帧合成)、HDRTMO(DRC 宽动态压缩)BAYNR(空域降噪)、BAY3D(时域降噪)AWB_GAIN,以及 3A 统计模块RAWAWB、RAWAE_BIG/RAWAE_LITE、RAWAF、RAWHIST_BIG/RAWHIST_LITE、PDAF
【RGB Processing】
DEBAYER、CCM、GAMMA_OUT、DEHAZE_ENHANCE、3DLUT、LDCH
【YUV Processing】
2DNR(YNR+CNR)、SHARP、CSM、CONV422、SCL/SELF_RESIZE
【Memory Interface(MI)】
- 负责主路图像、MIPI、DBR、LUT 各通道与 DDR 之间的读写
—— 《Rockchip_RK3568_TRM_Part2_V1.1-20210301.pdf》P.982–991
3. 三个容易忽略的点
(1)3A 的统计在 RAW 域完成:RAWAWB、RAWAE_*、RAWHIST_* 吃的都是 raw 数据,硬件只负责“测量”,软件拿到统计量后算出增益、曝光、白平衡参数,再回填给 AWB_GAIN 等模块去“应用”。
(2)Gamma 有两个:RAW 域一个 GAMMA_IN,RGB 域一个 GAMMA_OUT,位置不同、用途不同;平时说的“Gamma 校正”通常指输出侧的 GAMMA_OUT。
(3)4:2:0 是最后一步才做的:CSM 先把 RGB 变成 YUV444,CONV422 再降到 YUV422;要输出 4:2:0 还得靠 SELF_RESIZE / SCL(TRM 明确写了 Resize 支持 4:2:2 ↔ 4:2:0 的相互转换)。所以 ISP 默认输出多是 YUV422,YUV420 由 Resize 或后级模块决定。
四、 总结
把整条链路串起来:
sensor:I2C/CCI 配置 + MCLK 时钟,逐行读出(光电转换 → 模拟增益 → ADC → Bayer RAW,每像素 1 个分量,10bit)
↓ DVP 并口,或 MIPI CSI-2(差分,经 D-PHY)
SoC:D-PHY → CSI2RX 还原成像素,交给 ISP(或经 VICAP 直存 DDR)
↓ 解包 + 校正(黑电平、镜头阴影、坏点、去噪、白平衡)
仍是 Bayer,1 个分量(按 16bit 存放,2 字节/像素)
↓ 去马赛克(插值补齐)
RGB,3 个分量(8bit x 3,3 字节/像素) ← 数据量变大的一步
↓ 色彩空间转换
YUV444,3 个分量(3 字节/像素)
↓ 色度下采样(U、V 各 2:1)
YUV420,1.5 字节/像素 ← 数据量变小的一步
↓ 按 I420 / NV12 排布
裸数据文件(无头信息,1920x1080 一帧 2.97MB)最后留三个容易搞混的点:
- 数据量变大发生在去马赛克(1 个分量 → 3 个分量),变小发生在色度下采样(3 字节 → 1.5 字节)。
- YUV420 之所以看着不糊,是因为色度下采样只降低了“颜色”的精度,亮度 Y 一点没降,而人眼对亮度最敏感。
- 相机不一定都给 RAW:带 ISP 的 sensor(很多手机 sensor、USB 摄像头)直接输出 YUV422 / YUV420,此时拿到手的可能就已经是 NV12 / NV21 了,本文前半段那条“RAW → ISP → RGB”的路径在 sensor 内部已经走完了。
本文档由 markdowncli 技能辅助生成