2、RAW图数据存储结构:Bayer阵列、CFA原理与线性特性

好,咱们今天聊聊RAW图最底层的那些事。很多工程师调了几年图像,却对传感器出来的原始数据一知半解。我个人觉得,不理解Bayer阵列和CFA原理,后面做去马赛克、白平衡校正,基本就是在碰运气。

2.1 彩色滤波阵列(CFA)原理

说白了,CMOS传感器本身是“色盲”的。每个像素只能感知光的强度,也就是亮度,它分不清红绿蓝。那彩色照片怎么来的?

答案就是在每个像素上盖一层微小的滤色片——这就是CFA(Color Filter Array)。每个像素只允许特定波长的光通过,其他波长的光被吸收或反射。这样一来,传感器就只记录“某一种颜色”的亮度值。

核心概念:CFA的本质是“以空间换色彩”。每个像素只采集一种颜色分量,丢失的另外两种颜色信息,靠后续的插值算法(去马赛克)从相邻像素推算出来。

我刚开始做ISP时,总觉得这设计太浪费了——明明每个像素都能感光,却只让1/3的光进来。但没办法,这是目前成本、工艺和画质之间最平衡的方案。

2.2 Bayer阵列模式

最常见的CFA模式就是Bayer阵列。它用2x2的重复单元排列滤色片。为什么是2x2?因为人眼对绿色最敏感,所以绿色像素占一半,红色和蓝色各占1/4。

常见的Bayer模式有四种:

模式名称 2x2单元排列 常见传感器
RGGB 第一行:R G
第二行:G B
Sony IMX系列、OmniVision多数型号
GRBG 第一行:G R
第二行:B G
部分三星、安森美传感器
GBRG 第一行:G B
第二行:R G
某些老款CCD传感器
BGGR 第一行:B G
第二行:G R
部分Kodak、Foveon X3(非Bayer)

避坑指南:我曾经在项目中接过一个第三方模组,默认是RGGB,结果传感器输出的是GRBG。去马赛克算法没改,整张图全是紫色条纹。排查了两天才发现是Bayer模式配错了。所以拿到新传感器,第一件事就是确认Bayer排列顺序。

你可能会问:怎么确认Bayer模式?我一般用两种方法:

  • 查datasheet:传感器手册里会明确写Bayer pattern。
  • 拍纯色画面:对着均匀白墙拍一张RAW,然后看每个2x2块的像素值分布。哪个通道值最高,对应的就是该颜色的滤色片位置。

2.3 RAW数据的线性特性

这是很多新手容易忽略的点。RAW数据是线性的,什么意思?

传感器输出的数字值(DN值)与入射光强度成正比。也就是说,如果入射光强度翻倍,RAW值也翻倍。这跟人眼的感知完全不同——人眼对亮度的响应是对数的。

举个例子:

  • 入射光强度 = 100 lux → RAW值 = 500
  • 入射光强度 = 200 lux → RAW值 = 1000
  • 入射光强度 = 400 lux → RAW值 = 2000

这个线性关系非常重要。因为后面所有的处理——白平衡增益、颜色校正矩阵、伽马校正——都建立在“数据是线性的”这个前提上。

注意:线性特性只在传感器未饱和时成立。一旦某个像素的电荷超过满阱容量(Full Well Capacity),RAW值就会饱和(通常为4095或16383),线性关系立刻失效。饱和区域的细节永远丢失,后期拉不回来。

我记得有一次调试夜景模式,发现高光区域全是死白。查了半天,发现是曝光时间设得太长,导致部分像素饱和了。所以做HDR或多帧合成时,一定要监控饱和像素的比例。

2.4 黑电平(Black Level)

理想情况下,没有光照射时,传感器应该输出0。但实际不是这样——由于暗电流、电路噪声等因素,即使完全遮光,传感器也会输出一个非零值。这个值就是黑电平。

黑电平的校正公式很简单:

// 黑电平校正
corrected_value = raw_value - black_level

// 如果校正后为负值,通常截断到0
if (corrected_value < 0) corrected_value = 0;

不同传感器的黑电平值不同。常见的有:

  • 8-bit RAW:黑电平通常在16~64之间
  • 10-bit RAW:黑电平通常在64~256之间
  • 12-bit RAW:黑电平通常在256~1024之间
  • 14-bit RAW:黑电平通常在1024~4096之间

我的习惯:黑电平不是固定不变的。温度升高,黑电平会漂移。我一般在每帧图像中保留一些“光学黑像素”(Optically Black Pixels),实时计算当前帧的黑电平,而不是用固定值。这样能有效抑制温度引起的暗电流噪声。

2.5 白平衡(White Balance)

白平衡的本质,是在RAW域对R、G、B三个通道施加不同的增益,使得中性灰物体在三个通道上的响应一致。

为什么要在RAW域做?因为RAW数据是线性的,增益直接乘上去就行。如果在非线性域(比如sRGB)做白平衡,结果会非常奇怪。

白平衡的数学表达:

// 假设参考白点的R/G/B值分别为 R_w, G_w, B_w
// 目标是将R和B通道调整到与G通道一致

R_gain = G_w / R_w
B_gain = G_w / B_w

// 应用增益
R_out = R_in * R_gain
G_out = G_in * 1.0  // G通道通常不做增益
B_out = B_in * B_gain

这里有个关键点:白平衡增益不能无限大。增益太大会放大噪声,尤其是蓝色通道——因为蓝色像素的量子效率通常最低,信噪比本来就差。

我曾经踩过的坑:在低色温光源下(比如白炽灯,约2800K),蓝色通道的增益可能达到3~4倍。结果蓝色通道的噪声被放大到肉眼可见的程度,整张图全是蓝色噪点。后来我加了增益上限(最大2.5倍),超出部分用色温混合的方式处理,才解决了这个问题。

2.6 知识结构总览

下面这张图把本章的核心逻辑串起来了。从传感器采集到RAW数据输出,每一步都环环相扣。

RAW图数据存储结构知识体系 CMOS/CCD 传感器 彩色滤波阵列 (CFA) Bayer 阵列模式 (RGGB/GRBG/GBRG/BGGR) 线性 RAW 数据 (DN ∝ 光强) 黑电平校正 (Black Level) 白平衡增益 (White Balance) 关键:RAW域处理必须在线性空间完成,黑电平校正优先于白平衡增益

从这张图可以看得很清楚:传感器采集 → CFA滤色 → Bayer排列 → 线性RAW数据 → 黑电平校正 → 白平衡增益。每一步都有它的物理意义和数学基础。

我个人建议,拿到一个RAW文件后,先做三件事:确认Bayer模式、测量黑电平、估算白平衡增益。这三步做扎实了,后面的调优才有根基。