ISP Pipeline概览:移动端ISP架构、RAW域处理、RGB域处理、YUV域处理
各位同学,咱们直接进入正题。移动端ISP(图像信号处理器)的Pipeline,说白了就是一张RAW照片从传感器出来,到最终变成你屏幕上那张能发朋友圈的图,中间经历的一系列“加工工序”。
我刚开始接触这行的时候,觉得ISP就是个黑盒子——RAW进去,好看的图出来。后来自己动手调过几个项目才发现,这里面的门道深着呢。尤其是低光照场景,Pipeline里任何一个环节没处理好,最终效果都会崩。
今天咱们就把这个Pipeline拆开,看看每个域都在干什么。
一、移动端ISP整体架构
先看一张整体流程图,帮你建立全局认知。
核心观点:移动端ISP的Pipeline通常分为三大处理域——RAW域、RGB域、YUV域。每个域解决不同的问题,顺序不能乱。
这张图你应该记在脑子里。每次调低光照算法的时候,都要清楚当前在哪个域、下一步要去哪。
二、RAW域处理
RAW域是Pipeline的第一站。传感器输出的原始数据就是RAW格式——每个像素只记录一种颜色(R、G、B之一),按Bayer阵列排列。
为什么要在RAW域做处理?因为这时候数据还没被“污染”,信噪比最高。说白了,越早做降噪和校正,效果越好。等到了RGB域再做,噪声已经被插值放大了,处理起来事倍功半。
2.1 黑电平校正
传感器在完全无光的情况下,输出并不是0,而是有一个固定的偏移量,这叫黑电平。校正很简单:减去这个偏移值。
// 黑电平校正伪代码
for each pixel in RAW_image:
pixel = max(pixel - black_level, 0)
我的经验:不同增益下的黑电平可能不一样。低光照场景下增益很高,黑电平会漂移。我建议你在暗电流标定时,至少取3个不同增益点做线性拟合,别只用一个固定值。
2.2 坏点校正
传感器上总有几个“坏点”——要么一直亮(热像素),要么一直暗(死像素)。低光照下这些坏点特别显眼。
我常用的方法是动态坏点检测:
- 计算当前像素与周围8邻域的差值
- 如果差值超过阈值,判定为坏点
- 用中值或均值替换
注意:阈值要随ISO增益动态调整。我曾经在某个项目里用固定阈值,结果高ISO下把正常像素误判为坏点,画面出现大量“斑块”。后来改成ISO自适应阈值才解决。
2.3 去马赛克
这是RAW域最关键的一步。把Bayer格式的每个像素“插值”成完整的R、G、B三个通道。
常见的算法有:
| 算法 | 质量 | 计算量 | 低光照表现 |
|---|---|---|---|
| 双线性插值 | 低 | 极低 | 差(伪彩严重) |
| 边缘导向插值 | 中 | 低 | 一般 |
| 自适应插值 | 高 | 中 | 较好 |
| 深度学习插值 | 极高 | 高 | 优秀(但移动端吃力) |
我个人习惯在低光照场景下用边缘导向插值,计算量可控,伪彩也比双线性少很多。
三、RGB域处理
RAW域处理完,数据变成了完整的RGB图像。这时候我们开始处理颜色相关的问题。
3.1 白平衡
低光照下,光源色温往往偏暖(白炽灯)或偏冷(荧光灯/月光)。白平衡就是让白色物体在图像里看起来是白的。
我常用的方法是灰度世界法 + 色温估计:
- 统计全图的R、G、B均值
- 计算R/G和B/G比值
- 根据比值查表得到色温
- 应用对应的增益系数
避坑指南:低光照下,大面积的暗区会导致白平衡误判。我曾经遇到一个场景——夜晚的草地,绿色通道占比过高,算法误判为“偏绿”,强行拉高红色,结果草地变成了紫色。后来我加入了“置信度权重”,只统计亮度较高的区域做白平衡,问题就解决了。
3.2 Gamma校正
人眼对暗部细节的敏感度远高于亮部。Gamma校正就是做这件事——把暗部拉开,亮部压缩。
标准Gamma曲线:
// Gamma校正
output = pow(input, 1.0 / gamma)
// gamma通常取2.2
低光照场景下,我建议适当降低Gamma值(比如2.0),让暗部更亮一些。但别降太多,否则亮部会过曝。
四、YUV域处理
RGB转YUV之后,亮度和颜色分开了。Y通道负责亮度,UV通道负责色度。这时候处理起来更灵活。
4.1 亮度降噪
低光照下Y通道的噪声最明显。我通常用空域+时域联合降噪:
- 空域:双边滤波或NLM(非局部均值),保留边缘的同时去噪
- 时域:多帧对齐后做时域滤波,对静态区域效果极好
我的经验:时域降噪的强度要跟运动检测联动。运动区域强度降低,否则会出现“鬼影”。我曾经在调试夜景模式时,因为时域强度太高,人走路拖出了半透明的尾巴……
4.2 锐化
降噪之后图像会变“软”,需要锐化找回细节。但低光照下锐化很容易放大噪声。
我推荐使用非锐化掩模(Unsharp Mask)加阈值控制:
// 非锐化掩模
blur = gaussian_filter(Y)
detail = Y - blur
// 只对细节幅度大于阈值的区域做增强
if abs(detail) > threshold:
Y_enhanced = Y + strength * detail
else:
Y_enhanced = Y
阈值设得好,既能锐化边缘,又不会把噪声凸显出来。
4.3 色彩增强
低光照下颜色饱和度会下降。在UV通道上适当提升饱和度,能让画面更“生动”。
但注意——别过头。我见过不少算法把夜景调得跟动画片一样,颜色浓得发假。适度增强,保持自然感才是王道。
五、各域处理对比总结
| 处理域 | 输入 | 核心任务 | 低光照关键点 |
|---|---|---|---|
| RAW域 | Bayer RAW | 黑电平、坏点、去噪、去马赛克 | 信噪比最高,降噪效果最好 |
| RGB域 | 完整RGB | 白平衡、颜色校正、Gamma | 注意暗区白平衡误判 |
| YUV域 | YUV 4:2:0/4:4:4 | 降噪、锐化、色彩增强 | 亮度和颜色分开处理,灵活性高 |