ISP核心模块解析(上):Bayer域处理

好,我们正式开始啃ISP最核心的模块。这一节我打算拆成上下两部分来讲,上部分聚焦在Bayer域——也就是Sensor原始数据刚进来还没做任何处理的那个阶段。

很多人觉得Bayer域处理就是“预处理”,没什么技术含量。其实不然。我做过几个项目,前期Bayer域没处理好,后面调再好的算法也救不回来。说白了,Bayer域是画质的地基。

Bayer域是什么?

先简单回顾一下。CMOS Sensor每个像素只能感知亮度,不能直接感知颜色。为了获取彩色信息,Sensor表面覆盖了一层滤色阵列——最常见的就是Bayer Pattern。

Bayer Pattern的典型排列(RGGB):

每个2x2单元包含1个R、2个G、1个B。人眼对绿色最敏感,所以绿色像素占了一半。

Sensor输出的就是这种马赛克状的RAW数据。后续所有处理,都要在这个基础上展开。

黑电平校正(Black Level Correction)

黑电平校正,简称BLC。这是ISP流水线的第一关。

为什么要做?

理想情况下,Sensor在全黑环境下的输出应该是0。但实际不是。由于暗电流、电路噪声等因素,Sensor会有一个固定的偏移量。这个偏移量就是黑电平。

如果不校正,暗部会发灰,动态范围也会被压缩。

怎么做?

常见的做法是:Sensor内部会预留一些光学黑像素(Optical Black, OB),这些像素被遮挡,不感光。ISP读取这些OB像素的平均值,作为当前帧的黑电平基准。

// 伪代码示例:黑电平校正
uint16_t black_level = get_ob_average(sensor_raw);
for (each pixel in frame) {
    pixel = (pixel > black_level) ? (pixel - black_level) : 0;
}

我的经验:黑电平不是一成不变的。温度升高、增益变大,黑电平都会漂移。我建议做动态黑电平校正——每帧都重新计算OB均值,而不是用固定值。曾经有个项目,客户反映暗部偏色,查了两天才发现是黑电平没随增益联动。

Bayer域去噪

去噪是ISP里最考验功力的模块之一。Bayer域去噪,顾名思义,是在数据还是马赛克状态时就做降噪。

为什么要在Bayer域做?

因为去马赛克之后,噪声会被插值算法放大和扩散。先降噪,再插值,效果会好很多。

常用方法:

  • 空域滤波:双边滤波、非局部均值(NLM)。双边滤波保边效果好,但计算量大。
  • 变换域滤波:小波变换、BM3D。效果顶级,但硬件实现成本高。
  • 时域滤波:多帧融合。适合静态场景,运动区域容易产生鬼影。
方法 降噪效果 细节保留 计算量 硬件友好度
双边滤波 中等 好 中 高
NLM 好 好 高 低
BM3D 极好 极好 极高 极低
时域滤波 好 中等 低 高

避坑指南:我曾经在一个低光项目中,为了追求降噪效果,把Bayer域去噪强度拉得很高。结果发现暗部细节全糊了,而且出现了伪色。后来才意识到,Bayer域去噪要克制——它的主要目标是去除传感器读出噪声和光子散粒噪声,而不是把纹理也抹掉。降噪强度要和ISO联动,ISO越高,强度越大,但要有上限。

去马赛克(Demosaic)

去马赛克,也叫颜色插值。它的任务是从Bayer Pattern中恢复出每个像素的R、G、B三个通道值。

为什么难?

因为每个像素只知道自己一个通道的值,另外两个通道要靠邻居猜。猜错了,就会出现伪色、锯齿、摩尔纹。

经典算法演进:

  1. 最近邻插值:最简单,但效果最差。锯齿严重。
  2. 双线性插值:取周围同色像素的平均值。速度快,但边缘模糊。
  3. 边缘导向插值:先判断边缘方向,再沿边缘方向插值。效果明显提升。
  4. 自适应插值:结合色差恒定假设(色差在局部区域变化平缓)。这是目前主流方案的基础。

我个人的习惯是,在项目中优先采用基于色差恒定的边缘导向插值。它在画质和计算量之间取得了很好的平衡。

// 伪代码:基于色差恒定的G通道插值(简化版)
// 假设当前像素是R位置,需要插值G
// 色差:K = G - R(在R位置,G未知,R已知)
// 利用周围G-R色差的平均值来估计当前G值

float k_h = abs(G_left - R_left) + abs(G_right - R_right); // 水平方向色差变化
float k_v = abs(G_up - R_up) + abs(G_down - R_down);       // 垂直方向色差变化

if (k_h < k_v) {
    // 水平边缘,沿水平方向插值
    G_current = R_current + ( (G_left - R_left) + (G_right - R_right) ) / 2;
} else if (k_v < k_h) {
    // 垂直边缘,沿垂直方向插值
    G_current = R_current + ( (G_up - R_up) + (G_down - R_down) ) / 2;
} else {
    // 平坦区域,取平均
    G_current = R_current + ( (G_left - R_left) + (G_right - R_right) + (G_up - R_up) + (G_down - R_down) ) / 4;
}

我的经验:去马赛克算法对边缘方向判断的准确性非常敏感。方向判断错了,伪色就出来了。我建议在判断边缘方向时,不要只看单一通道的梯度,可以结合G通道的梯度信息。G通道采样率最高,信息最可靠。

Bayer域处理流程总览

这三个模块在ISP流水线中是串联的:BLC → Bayer去噪 → Demosaic。顺序不能乱。

下面这张图展示了Bayer域处理的核心流程和关键节点:

Bayer域处理流程 Sensor RAW 黑电平校正 Bayer去噪 去马赛克 关键参数与注意事项: • 黑电平:动态校正,与温度/增益联动 • 去噪强度:与ISO联动,避免过度平滑 • 去马赛克:边缘方向判断是核心,结合G通道梯度 输出结果: • 经过BLC、去噪、Demosaic后,输出完整的RGB图像 • 后续模块(白平衡、Gamma校正等)将在此基础上继续处理

嗯,到这里,Bayer域的三个核心模块就讲完了。你想想看,这三个模块环环相扣,任何一个环节出问题,都会直接影响最终画质。我个人建议,在做ISP调优时,先把Bayer域的参数调稳,再往后走。地基打牢了,上层建筑才稳。