3. 传统 ISP Pipeline:从光到图的流水线

各位同学,今天我们来聊聊传统 ISP 的核心流程。说实话,我做了这么多年图像处理,每次回头看这条 Pipeline,都觉得它像一条精密的工业流水线——每个模块各司其职,把 RAW 图一步步变成我们肉眼看着舒服的成品。

我个人习惯把 ISP 比作「数字暗房」。你想想看,传感器捕捉到的 RAW 数据,就像胶片相机里的底片,灰蒙蒙的,偏色严重,还有一堆噪声。传统 ISP 的任务,就是把这卷「底片」冲洗成一张能看的照片。

3.1 ISP 基本流程总览

先看一张整体流程图,我把它画成了经典的串行 Pipeline 结构。嗯,这里要注意,虽然现在很多芯片开始用并行或混合架构,但理解串行是基础。

传统 ISP Pipeline 串行流程 RAW 输入 BLC LSC AWB Demosaic CCM Gamma NR Sharpen YUV 输出 说明:传统 ISP 多为串行流水线,前级输出直接作为后级输入。延迟逐级累加,这是后面做 AI 混合架构时要重点优化的地方。

从 RAW 进来,到 YUV 出去,中间经过 8 个核心模块。我当年刚入行时,师傅跟我说:「你把这 8 个模块吃透,ISP 就算入门了。」现在回头看,这话一点不假。

3.2 各模块功能详解

3.2.1 BLC(黑电平校正)

BLC 是 Pipeline 的第一关。传感器在无光条件下,像素也会有微弱的电信号输出,这叫黑电平。说白了,就是传感器有「底噪」。

校正方法很简单:从每个像素值里减去一个固定的黑电平值。

// BLC 校正伪代码
for each pixel in RAW:
    pixel = pixel - black_level
    if pixel < 0: pixel = 0
我的经验:黑电平值不是一成不变的。温度升高,黑电平会漂移。我曾经在一个安防项目中,白天黑夜温差大,固定黑电平导致暗部偏色。后来改用动态 BLC,根据暗像素行实时估算黑电平,问题才解决。

3.2.2 LSC(镜头阴影校正)

镜头边缘进光量天生比中心少,拍出来的照片四周发暗,这就是 Lens Shading。LSC 就是给边缘像素「补光」。

通常的做法是预存一张增益网格,每个像素乘以对应的增益系数。

// LSC 校正伪代码
for each pixel (x, y) in RAW:
    gain = lens_gain_table[y][x]
    pixel = pixel * gain
注意:增益网格的精度直接影响校正效果。网格太粗,边缘会出现「阶梯状」亮度跳变。我建议至少用 16x16 的网格,配合双线性插值。

3.2.3 AWB(自动白平衡)

人眼有色彩恒常性,但传感器没有。日光下拍的白纸,到了白炽灯下就偏黄。AWB 的任务就是让白色在任何光源下都保持白色。

核心思路:找到场景中的「白色参考点」,然后调整 R/G/B 增益,让参考点变成纯白。

// AWB 灰度世界法伪代码
R_gain = G_avg / R_avg
B_gain = G_avg / B_avg
for each pixel:
    pixel.R = pixel.R * R_gain
    pixel.B = pixel.B * B_gain

常见 AWB 算法对比:

算法原理适用场景缺点
灰度世界法假设场景平均色为灰色色彩丰富的场景大色块场景会失效
完美反射法假设最亮像素为白色有高光区域的场景过曝时误判
色温估计法根据色温曲线查表室内外切换需要标定

3.2.4 Demosaic(去马赛克)

传感器每个像素只能感知一种颜色(R/G/B),通过 Bayer 阵列排列。Demosaic 就是通过插值,把每个像素缺失的两种颜色补全。

最简单的双线性插值,效果一般。现在主流是方向性插值或自适应插值。

// 双线性 Demosaic 伪代码(以 G 通道为例)
for each R pixel at (x, y):
    G(x,y) = (G(x-1,y) + G(x+1,y) + G(x,y-1) + G(x,y+1)) / 4
避坑指南:我曾经在低照度场景下用简单插值,结果彩色噪声被放大,出现大量「假色」。后来改用边缘导向插值,先判断纹理方向再插值,假色明显减少。

3.2.5 CCM(色彩校正矩阵)

传感器的色彩响应和人眼不同,拍出来的红色不够红,蓝色不够蓝。CCM 通过一个 3x3 矩阵,把传感器色彩空间映射到标准色彩空间(如 sRGB)。

// CCM 校正
[R']   [a11 a12 a13]   [R]
[G'] = [a21 a22 a23] * [G]
[B']   [a31 a32 a33]   [B]

矩阵系数通过拍摄标准色卡(如 X-Rite ColorChecker)标定得到。

3.2.6 Gamma(伽马校正)

人眼对暗部细节更敏感,对亮部不敏感。Gamma 校正就是把线性光强映射到非线性空间,让暗部细节更丰富。

标准 Gamma 曲线:V_out = V_in ^ (1/2.2)

注意:Gamma 校正必须在 CCM 之后做,因为 CCM 是线性操作,Gamma 是非线性操作。顺序搞反了,色彩会完全乱掉。

3.2.7 NR(降噪)

噪声是 ISP 的天敌。低照度下,噪声尤其明显。传统降噪分空域和时域两种。

  • 空域降噪:双边滤波、非局部均值滤波。效果好,但计算量大。
  • 时域降噪:多帧叠加、运动补偿。适合视频,但容易产生拖影。

我的建议:实际项目中,空域+时域结合使用。先做时域降噪,再做空域降噪。我曾经在监控项目中,用 3 帧叠加 + 双边滤波,信噪比提升了 6dB。

3.2.8 Sharpen(锐化)

降噪会损失细节,锐化就是把丢失的边缘找回来。经典方法是 Unsharp Mask(USM)。

// USM 锐化伪代码
blur = gaussian_filter(image)
mask = image - blur
output = image + alpha * mask
避坑指南:锐化强度 alpha 不能太大,否则会出现「光晕」效应。我一般控制在 0.3~0.6 之间,具体看场景。

3.3 Pipeline 延迟分析

讲完模块,我们来聊聊延迟。这是做嵌入式 ISP 开发时最头疼的问题之一。

传统 ISP 是串行流水线,每个模块处理一帧图像都需要时间。延迟 = 各模块处理时间之和 + 行缓冲/帧缓冲时间。

模块典型延迟(1080p@30fps)说明
BLC0.1 ms逐像素减法,几乎无延迟
LSC0.3 ms查表+乘法,需行缓冲
AWB0.5 ms需要统计整帧信息,有帧延迟
Demosaic1.0 ms插值算法,需多行缓冲
CCM0.2 ms矩阵乘法,逐像素
Gamma0.1 ms查表,逐像素
NR2.0 ms空域滤波,需大窗口缓冲
Sharpen0.5 msUSM,需高斯滤波缓冲
总计4.7 ms不含帧缓冲和 DMA 开销

延迟瓶颈分析:

  • Demosaic + NR:这两个模块占了一半以上的延迟。因为它们需要大窗口(5x5 甚至 7x7)的像素数据,行缓冲开销大。
  • AWB:需要统计整帧的 R/G/B 均值,意味着至少等待一帧数据全部到达才能开始处理。这是「帧级延迟」的典型代表。
  • 行缓冲:每个模块都需要若干行缓冲,1080p 图像一行约 2KB(RGB),5 行就是 10KB。多个模块累加,片上 SRAM 很容易被吃光。
实战提醒:我在做一款 4K@60fps 的 ISP 时,发现传统串行 Pipeline 的延迟已经超过 8ms,无法满足实时取景的要求。后来不得不把 NR 和 Sharpen 放到后级并行处理,才把延迟压到 4ms 以内。所以,理解延迟的构成,是优化 Pipeline 的第一步。