第4章:RAW域数据格式——从RAW8到RAW16,以及Bayer的那些事儿

好,咱们进入第四章。前面聊了MIPI的物理层和协议层,现在该聊聊RAW域里最核心的东西——数据格式了。

说白了,传感器输出的原始数据长什么样?你怎么把它从一堆比特流里还原成有意义的像素值?这就是本章要解决的问题。

我个人习惯把RAW数据格式比作“传感器的母语”。你调试ISP,不懂这个,后面全是瞎蒙。

4.1 RAW位深:RAW8、RAW10、RAW12、RAW14、RAW16

先看位深。位深决定了每个像素用多少个比特来表示。

格式 位深 典型应用场景 动态范围(理论)
RAW8 8 bit 低端摄像头、USB摄像头 48 dB
RAW10 10 bit 手机主摄、安防IPC 60 dB
RAW12 12 bit 车载摄像头、工业相机 72 dB
RAW14 14 bit 高端工业、医疗影像 84 dB
RAW16 16 bit 科学级相机、天文摄影 96 dB

你可能会问:位深越高越好吗?理论上是的。但实际项目中,你得考虑带宽、存储、处理速度。

关键认知:RAW10是消费电子领域的“黄金位深”。它比RAW8多了一档动态范围,又不像RAW12那样对带宽压力太大。我经手的项目中,80%的调试工作都集中在RAW10上。

举个例子。一个200万像素的传感器,30fps输出:

  • RAW8:带宽约 480 Mbps
  • RAW10:带宽约 600 Mbps
  • RAW12:带宽约 720 Mbps

你看,从RAW10到RAW12,带宽涨了20%。对于MIPI D-PHY来说,这20%可能就意味着要从1-lane切换到2-lane,或者从低速模式切到高速模式。

我的经验:选位深时,先算带宽预算。别一上来就上RAW12,结果发现MIPI跑不动,最后还得降帧率。我曾经在一个车载项目里就吃过这个亏——选了RAW14,结果D-PHY的时钟频率死活上不去,最后只能降回RAW12。

4.2 Bayer模式:RGGB/GRBG/BGGR/GBRG

好,位深聊完了。接下来是Bayer模式。

大部分彩色传感器用的都是Bayer滤色阵列。每个像素只感测一种颜色——红、绿或蓝。然后通过插值算法恢复全彩。

Bayer模式有四种排列方式:

  • RGGB:第一行 R G R G...,第二行 G B G B...
  • GRBG:第一行 G R G R...,第二行 B G B G...
  • BGGR:第一行 B G B G...,第二行 G R G R...
  • GBRG:第一行 G B G B...,第二行 R G R G...

你可能会觉得:这不就是四种排列嘛,随便选一个不就行了?

嗯,这里有个坑。ISP的demosaic模块是跟Bayer模式绑定的。你传感器输出的是RGGB,ISP却配成了GRBG,那出来的图像颜色就全乱了。

避坑指南:我曾经在调试一款OV sensor时,发现图像偏绿严重。查了半天,最后发现是Bayer模式配错了。传感器手册上写的是“BGGR”,我默认配成了“RGGB”。就这一个字节的差异,折腾了我两天。

怎么确认Bayer模式?我建议你这么做:

  1. 看传感器数据手册,找到Bayer pattern的说明
  2. 拍一张纯白画面,看RAW数据的排列
  3. 用工具(比如RAW分析器)验证

另外,Bayer模式跟传感器的物理方向也有关系。传感器旋转90度或180度,Bayer模式也会变。所以做模组时,一定要确认镜头的安装方向。

4.3 数据打包与解包

接下来是实操环节——数据打包与解包。

MIPI CSI-2协议里,RAW数据不是直接裸传的。它需要打包成特定的格式。常见的打包方式有:

  • RAW8:每个像素1字节,直接传,最简单
  • RAW10:4个像素打包成5字节(4×10=40 bit = 5 byte)
  • RAW12:2个像素打包成3字节(2×12=24 bit = 3 byte)
  • RAW14:4个像素打包成7字节(4×14=56 bit = 7 byte)
  • RAW16:每个像素2字节,直接传

我重点说说RAW10的打包,因为这是最常用的。

RAW10打包规则

假设你有4个像素:P0, P1, P2, P3,每个10 bit。打包成5字节:

Byte 0: P0[9:2]   // P0的高8位
Byte 1: P1[9:2]   // P1的高8位
Byte 2: P2[9:2]   // P2的高8位
Byte 3: P3[9:2]   // P3的高8位
Byte 4: P3[1:0] P2[1:0] P1[1:0] P0[1:0]  // 4个像素的低2位拼在一起

你看,第4字节里,P0的低2位在最低位,P3的低2位在最高位。这个顺序不能搞反。

解包时要注意:很多初学者解包时,会把低2位的顺序搞反。比如把P0的低2位放到最高位去了。结果就是图像出现周期性的条纹噪声。我见过不止一个工程师在这个问题上栽跟头。

RAW12打包规则

RAW12的打包更简单:2个像素打包成3字节。

Byte 0: P0[11:4]   // P0的高8位
Byte 1: P1[11:4]   // P1的高8位
Byte 2: P1[3:0] P0[3:0]  // P0和P1的低4位拼在一起

嗯,这里也是,P0的低4位在低位,P1的低4位在高位。

解包代码示例(C语言风格)

我写个简单的RAW10解包函数,你感受一下:

// 输入:packed_data - 5字节的打包数据
// 输出:pixels - 4个10-bit像素值
void unpack_raw10(uint8_t *packed_data, uint16_t *pixels) {
    pixels[0] = (packed_data[0] << 2) | ((packed_data[4] >> 0) & 0x03);
    pixels[1] = (packed_data[1] << 2) | ((packed_data[4] >> 2) & 0x03);
    pixels[2] = (packed_data[2] << 2) | ((packed_data[4] >> 4) & 0x03);
    pixels[3] = (packed_data[3] << 2) | ((packed_data[4] >> 6) & 0x03);
}

注意看,第4字节的移位操作。我习惯用宏定义把这种操作封装起来,避免手写出错。

调试技巧:如果你不确定解包是否正确,可以拍一张均匀光照的灰卡。解包后,检查相邻像素的值是否连续变化。如果出现周期性的跳变,那多半是解包顺序错了。

4.4 知识结构图

下面这张图总结了本章的核心知识体系:

RAW域数据格式知识结构图 RAW域数据格式知识结构 RAW数据格式 位深(RAW8~RAW16) RAW8 RAW10 RAW12 RAW14/16 Bayer模式 RGGB GRBG BGGR GBRG 数据打包与解包 RAW10打包 RAW12打包 解包算法 验证方法 核心:位深决定动态范围,Bayer模式决定颜色排列,打包解包决定数据正确性

4.5 本章小结

好,总结一下本章的核心要点:

  • 位深:RAW10是主流,选型时先算带宽
  • Bayer模式:四种排列,配错就偏色,务必确认
  • 打包解包:注意低2位/低4位的顺序,用灰卡验证

这些看起来都是基础,但我在实际项目中见过太多人在这上面翻车。你想想看,一个ISP pipeline调了几个月,最后发现是RAW数据解包错了——那得多冤?

所以,我的建议是:在开始调试ISP之前,先把RAW数据的抓取和解包验证做扎实。这一步稳了,后面的工作才有意义。