3. 传统 ISP Pipeline:从光到图的流水线
各位同学,今天我们来聊聊传统 ISP 的核心流程。说实话,我做了这么多年图像处理,每次回头看这条 Pipeline,都觉得它像一条精密的工业流水线——每个模块各司其职,把 RAW 图一步步变成我们肉眼看着舒服的成品。
我个人习惯把 ISP 比作「数字暗房」。你想想看,传感器捕捉到的 RAW 数据,就像胶片相机里的底片,灰蒙蒙的,偏色严重,还有一堆噪声。传统 ISP 的任务,就是把这卷「底片」冲洗成一张能看的照片。
3.1 ISP 基本流程总览
先看一张整体流程图,我把它画成了经典的串行 Pipeline 结构。嗯,这里要注意,虽然现在很多芯片开始用并行或混合架构,但理解串行是基础。
从 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
3.2.2 LSC(镜头阴影校正)
镜头边缘进光量天生比中心少,拍出来的照片四周发暗,这就是 Lens Shading。LSC 就是给边缘像素「补光」。
通常的做法是预存一张增益网格,每个像素乘以对应的增益系数。
// LSC 校正伪代码
for each pixel (x, y) in RAW:
gain = lens_gain_table[y][x]
pixel = pixel * gain
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)
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
3.3 Pipeline 延迟分析
讲完模块,我们来聊聊延迟。这是做嵌入式 ISP 开发时最头疼的问题之一。
传统 ISP 是串行流水线,每个模块处理一帧图像都需要时间。延迟 = 各模块处理时间之和 + 行缓冲/帧缓冲时间。
| 模块 | 典型延迟(1080p@30fps) | 说明 |
|---|---|---|
| BLC | 0.1 ms | 逐像素减法,几乎无延迟 |
| LSC | 0.3 ms | 查表+乘法,需行缓冲 |
| AWB | 0.5 ms | 需要统计整帧信息,有帧延迟 |
| Demosaic | 1.0 ms | 插值算法,需多行缓冲 |
| CCM | 0.2 ms | 矩阵乘法,逐像素 |
| Gamma | 0.1 ms | 查表,逐像素 |
| NR | 2.0 ms | 空域滤波,需大窗口缓冲 |
| Sharpen | 0.5 ms | USM,需高斯滤波缓冲 |
| 总计 | 4.7 ms | 不含帧缓冲和 DMA 开销 |
延迟瓶颈分析:
- Demosaic + NR:这两个模块占了一半以上的延迟。因为它们需要大窗口(5x5 甚至 7x7)的像素数据,行缓冲开销大。
- AWB:需要统计整帧的 R/G/B 均值,意味着至少等待一帧数据全部到达才能开始处理。这是「帧级延迟」的典型代表。
- 行缓冲:每个模块都需要若干行缓冲,1080p 图像一行约 2KB(RGB),5 行就是 10KB。多个模块累加,片上 SRAM 很容易被吃光。