Bayer RAW数据格式:从像素排列到物理意义
各位同学,今天我们来啃一块硬骨头——Bayer RAW数据格式。说实话,我刚入行那会儿,觉得RAW不就是传感器吐出来的原始数据嘛,有啥好讲的?直到第一次调通一个4K@60fps的ISP pipeline,发现图像全是彩色摩尔纹,才意识到Bayer Pattern的理解深度直接决定了你的调试水平。
这一节,我会从三个层面展开:Bayer Pattern的四种排列方式、RAW数据的位深选择、以及黑电平与白平衡到底在物理上意味着什么。嗯,咱们直接开始。
一、Bayer Pattern:四种排列,一个核心思想
为什么传感器要用Bayer Pattern?说白了,单个像素只能感知光的强度,分不清颜色。Bayer在1976年想了个办法:在每个像素上覆盖一个滤光片,只让红、绿、蓝其中一种光通过。人眼对绿色最敏感,所以绿色像素占一半,红蓝各占四分之一。
四种常见的排列方式如下:
| Pattern名称 | 第一行 | 第二行 | 常见传感器厂商 |
|---|---|---|---|
| RGGB | R G R G ... | G B G B ... | Sony、OmniVision(多数) |
| GRBG | G R G R ... | B G B G ... | 部分三星、安森美 |
| BGGR | B G B G ... | G R G R ... | 部分CMOS传感器 |
| GBRG | G B G B ... | R G R G ... | 某些特殊应用传感器 |
关键点:ISP的Demosaic模块必须知道当前传感器的Pattern,否则插值出来的颜色完全错乱。我在项目中遇到过,某次换了传感器型号,忘记改驱动里的Pattern配置,结果图像偏紫得一塌糊涂,排查了整整两天。
你可能会问:四种排列有啥本质区别?其实没有。它们只是传感器厂商在物理布局上的选择。但作为ISP工程师,你必须记住:Pattern决定了后续所有颜色处理的方向。比如RGGB的R通道在(0,0)位置,而BGGR的R通道在(1,1)位置,Demosaic的插值窗口必须跟着转。
我的习惯:在代码里用一个枚举定义Pattern类型,然后在初始化阶段从传感器ID读取配置。千万别写死,否则换传感器就是灾难。
二、RAW位深:RAW10、RAW12、RAW16怎么选?
位深决定了每个像素能表达多少灰度等级。RAW10就是10bit,1024级;RAW12是4096级;RAW16是65536级。你想想看,位深越高,动态范围越大,暗部细节越丰富。
但代价也很明显:
- 带宽翻倍:RAW12比RAW10数据量多20%,RAW16直接翻倍。对于4K@60fps,MIPI接口的压力非常大。
- 处理延迟增加:高位深数据在ISP内部需要更多位宽的计算单元,流水线级数可能增加。
- 存储成本:RAW16占两个字节,RAW10可以打包成5字节存4个像素,节省空间。
| 位深 | 灰度等级 | 每像素字节数 | 典型应用场景 |
|---|---|---|---|
| RAW10 | 1024 | 1.25(打包) | 手机摄像头、消费级相机 |
| RAW12 | 4096 | 1.5(打包) | 安防监控、工业相机 |
| RAW16 | 65536 | 2 | 医疗成像、科学级相机 |
避坑指南:我曾经在一个项目中,为了追求画质选了RAW16,结果MIPI的D-PHY跑不到目标频率,最后被迫降回RAW12。所以,位深选择一定要结合硬件接口能力,别只看理论值。
另外,RAW数据在存储时通常采用打包格式。比如RAW10,4个像素共40bit,用5个字节存储。读取时需要用位操作拆包。嗯,这里要注意:不同厂商的打包顺序可能不同,有的先存高8位,有的先存低2位,一定要看datasheet。
// RAW10 打包示例:4个像素(p0~p3)存入5字节
// 字节0: p0[9:2] 高8位
// 字节1: p1[9:2] 高8位
// 字节2: p2[9:2] 高8位
// 字节3: p3[9:2] 高8位
// 字节4: p3[1:0] | (p2[1:0] << 2) | (p1[1:0] << 4) | (p0[1:0] << 6)
// 解包时,p0 = (byte0 << 2) | ((byte4 >> 6) & 0x03)
三、黑电平与白平衡:物理意义与校正逻辑
这部分是很多初学者容易混淆的地方。我尽量用大白话讲清楚。
3.1 黑电平(Black Level)
理想情况下,传感器完全遮光时,输出应该是0。但实际因为暗电流、读出噪声等原因,输出会有一个偏移量,这个偏移就是黑电平。通常RAW10的黑电平在64左右(即10bit的1/16处)。
为什么要校正黑电平?因为如果不减掉这个偏移,暗部的噪声会被放大,而且会影响后续的白平衡计算——白平衡是基于颜色的比例,偏移量会破坏这个比例。
物理意义:黑电平校正是把传感器的“零点”拉到数字0。我习惯在ISP的最前端做这件事,因为后面的所有处理都依赖这个零点。
校正公式很简单:
// 黑电平校正
pixel_corrected = pixel_raw - black_level;
// 如果结果小于0,则钳位到0
if (pixel_corrected < 0) pixel_corrected = 0;
但要注意:黑电平值不是固定的。它会随温度、增益、曝光时间变化。我见过一个项目,低温下黑电平漂了20个LSB,导致图像偏绿。后来加了温度补偿表才解决。
3.2 白平衡(White Balance)
白平衡的物理意义更直观:不同光源的色温不同,传感器对RGB三个通道的响应也不一样。比如在钨丝灯下,红色成分多,蓝色成分少,如果不做校正,拍出来的白色物体偏黄。
白平衡的本质就是给每个通道乘一个增益系数,让中性灰区域在RGB三个通道上相等。公式如下:
// 白平衡增益
R_gain = G_avg / R_avg;
B_gain = G_avg / B_avg;
// 应用增益
R_out = R_in * R_gain;
B_out = B_in * B_gain;
G_out = G_in; // 通常以G通道为参考
我的经验:白平衡增益不要超过4倍,否则噪声会被放大得不可接受。如果场景需要极高增益,说明光源色温太极端,建议用双色温补光灯。
这里有个容易踩的坑:白平衡增益是在黑电平校正之后、Demosaic之前做的,还是在Demosaic之后做?答案是在Bayer域做。因为Demosaic会引入颜色插值误差,如果在RGB域做白平衡,误差会被放大。我习惯在Bayer域直接对R和B通道乘增益,G通道不动。
四、知识体系总览
为了让你更直观地理解这一章的知识结构,我画了一张图:
这张图把本章的三个核心模块串起来了。你注意看,Bayer Pattern决定了像素的排列方式,位深决定了数据的精度,而黑电平和白平衡是进入ISP流水线之前必须完成的两步预处理。三者缺一不可。
总结一句话:Bayer RAW是ISP的起点,理解它的格式、位深和物理校正,是后面所有图像处理的基础。我见过太多工程师在Demosaic阶段花大量时间调参,结果问题出在黑电平没校好——方向错了,再努力也没用。