Pipeline核心模块解析:RAW域、RGB域与YUV域处理

各位同学,今天我们来啃Pipeline里最硬核的部分——三个色彩空间域的处理。说实话,我刚入行时也被这些域搞晕过。RAW、RGB、YUV,每个域干的事完全不同,但又环环相扣。你想想看,一张照片从传感器出来到最终显示,中间要经历多少次“变形”?

我个人习惯把整个流程想象成一条流水线:RAW域是“原材料粗加工”,RGB域是“色彩精调”,YUV域是“细节美颜”。下面我们逐个拆解。

手机影像Pipeline三大色彩域处理流程 RAW域处理 黑电平校正 去噪(原始域) 去马赛克 → 输出RGB RGB域处理 白平衡校正 颜色校正矩阵 Gamma校正 → 输出YUV YUV域处理 锐化 降噪 色彩增强 → 输出YUV 关键原则:RAW域保细节 → RGB域保色彩 → YUV域保观感,顺序不可颠倒

一、RAW域处理:从传感器原始数据说起

RAW域是整个Pipeline的起点。传感器输出的就是RAW数据——每个像素只记录一种颜色(R/G/B),通过Bayer阵列排列。说白了,这时候的图像还是“半成品”,缺颜色、有噪声、暗电平也不准。

1.1 黑电平校正(Black Level Correction)

传感器在完全无光时,输出并不是0。因为有暗电流和电路偏置,会有一个基底值,通常叫黑电平。我见过有些工程师直接减一个固定值完事,结果暗部细节全丢了。

核心公式:

校正后像素 = 原始像素 - 黑电平值
// 黑电平值通常从传感器OTP或校准表中读取
// 常见值:64(10bit)、256(12bit)、1024(14bit)

我在项目中遇到过一个问题:某款传感器在不同增益下黑电平会漂移。固定值校正导致暗部偏色。后来我改用动态黑电平跟踪——根据增益和温度查表插值,问题才解决。

避坑指南:黑电平校正后一定要做饱和钳位。我曾经忘了这步,结果高光区域出现负值,后续去马赛克直接炸了,画面出现彩色条纹。

1.2 去噪(Denoise in RAW域)

RAW域去噪和YUV域去噪完全不同。RAW域的噪声模型更简单——主要是光子散粒噪声和读出噪声。我习惯用BM3D或者小波变换,但移动端算力有限,实际常用的是双边滤波或非局部均值的简化版。

噪声类型 来源 特性 常用去噪方法
光子散粒噪声 光子到达的随机性 与信号强度平方根成正比 维纳滤波、BM3D
读出噪声 模拟电路 与信号无关,固定方差 均值滤波、中值滤波
固定模式噪声 像素不一致性 空间固定,时间不变 帧差法、校准表

嗯,这里要注意:RAW域去噪不能太狠。去噪太强,细节就没了,后续去马赛克也救不回来。我一般控制在保留90%以上的边缘能量。

1.3 去马赛克(Demosaic)

去马赛克就是把Bayer格式插值成完整RGB。说白了,每个像素只有一种颜色,我们要猜出另外两种。最简单的双线性插值,速度快但边缘有锯齿。高端方案用方向自适应插值或基于深度学习的超分。

性能与画质的博弈:去马赛克是Pipeline中计算量最大的模块之一。以4K@30fps为例,每秒要处理约830万像素×3通道的插值。我见过某平台用双线性插值,功耗降了30%,但边缘伪彩严重。最终方案是:平坦区域用双线性,边缘区域用方向自适应,算力分配要动态调整。

我个人习惯在去马赛克前先做坏点校正。传感器总有坏点,如果不修,去马赛克会把坏点扩散成一片彩色斑点。我曾经吃过这个亏,调试了三天才发现是坏点没处理。

二、RGB域处理:让颜色“对”起来

从RAW域出来的RGB图像,颜色还是偏的。为什么?因为传感器的光谱响应和人眼不一样,而且不同光源下颜色会偏。RGB域就是干这个的——把颜色校准到人眼看起来“自然”。

2.1 白平衡校正(AWB)

白平衡的目标很简单:让白色物体在任何光源下都显示为白色。但实现起来很复杂。我常用的方法是灰度世界法和完美反射法的融合。

// 灰度世界法:假设场景平均色为灰色
R_gain = G_avg / R_avg
B_gain = G_avg / B_avg

// 完美反射法:假设最亮像素为白色
R_gain = max(G) / max(R)
B_gain = max(G) / max(B)

// 实际融合:加权平均
R_gain_final = α * R_gain_gray + (1-α) * R_gain_reflect

实战经验:白平衡不能只靠算法,还要结合色温传感器。我在某旗舰机上遇到过:室内暖光灯下,算法把白墙调成了蓝色,因为墙上有蓝色装饰物干扰了统计。后来加了色温传感器做先验约束,问题解决。

2.2 颜色校正矩阵(CCM)

CCM是一个3×3矩阵,把传感器RGB映射到标准色彩空间(如sRGB)。说白了,就是纠正传感器“看颜色不准”的问题。

矩阵元素 作用 典型值范围
Rr, Gg, Bb 主对角线:各通道增益 0.8 ~ 1.2
Rg, Rb, Gr, Gb, Br, Bg 非对角线:通道间串扰补偿 -0.3 ~ 0.3

CCM的标定是个细活。我一般用24色卡拍摄,然后用最小二乘法拟合矩阵。但要注意:CCM会放大噪声。绿色通道增益高了,暗部绿色噪声就明显。所以CCM设计要兼顾色彩准确度和信噪比。

2.3 Gamma校正

Gamma校正解决的是“显示非线性”问题。人眼对暗部变化敏感,对亮部变化不敏感。CRT显示器也有类似的非线性。所以我们要对图像做Gamma映射:V_out = V_in ^ (1/γ),通常γ=2.2。

小技巧:Gamma校正可以在RGB域做,也可以在YUV域做。我建议在RGB域做,因为Gamma是非线性操作,如果在YUV域做,会影响色度分量的线性度,导致色彩偏移。

三、YUV域处理:让画面“好看”起来

RGB转YUV后,亮度和色度分离了。Y通道负责细节,UV通道负责颜色。这样处理起来更灵活——你可以只处理亮度,不影响颜色;或者只增强颜色,不影响细节。

3.1 锐化(Sharpening)

锐化的本质是增强边缘对比度。常用方法有非锐化掩模(USM)和拉普拉斯算子。但锐化有个副作用——会放大噪声和振铃效应。

// 非锐化掩模流程
1. 对Y通道做高斯模糊 → Y_blur
2. 提取边缘:edge = Y - Y_blur
3. 增强:Y_sharp = Y + α * edge
// α是锐化强度,通常0.5~1.5

我踩过一个坑:锐化强度设太高,人物皮肤上的毛孔都变成了噪点。后来我加了边缘检测门限——只在强边缘处锐化,平坦区域不做。效果好了很多。

3.2 降噪(Denoise in YUV域)

YUV域的降噪和RAW域不同。Y通道的噪声主要是亮度噪声,UV通道的噪声主要是色度噪声。我习惯分开处理:

  • Y通道:用边缘保留滤波(如双边滤波),保留细节的同时去噪
  • UV通道:用强一些的低通滤波,因为人眼对色度噪声不敏感

注意:UV通道降噪太强会导致颜色“糊”在一起。我见过某方案把UV通道直接做均值滤波,结果红色区域边缘出现了绿色晕影。原因是色度信息被过度平滑,导致颜色边界模糊。

3.3 色彩增强(Color Enhancement)

色彩增强是Pipeline的最后一步,也是“主观性”最强的一步。说白了,就是让颜色更鲜艳、更讨喜。常用方法:

  • 饱和度调整:对UV通道做增益,但要注意肤色保护
  • 色调映射:把特定颜色(如天空蓝、草地绿)往更饱和的方向拉
  • 记忆色增强:让肤色更红润、天空更蓝——人脑“记得”的颜色往往比实际更鲜艳

我的经验:色彩增强要“克制”。我见过一些手机拍出来的照片,颜色浓得溢出,红色变成了一团色块。好的色彩增强是“润物细无声”的——你感觉画面好看,但说不出来哪里调了。我一般把饱和度增益控制在1.1~1.3倍,超过1.5倍就容易失真。

四、三大域的调度策略

最后聊一下调度。这三个域的处理不是独立的,它们共享算力和带宽。我常用的调度原则:

场景 RAW域优先级 RGB域优先级 YUV域优先级
夜景/低光 高(去噪优先) 中(白平衡稳定即可) 低(锐化减弱,防噪点放大)
白天/高光 中(去马赛克精度优先) 高(CCM精度优先) 高(锐化和色彩增强拉满)
视频/实时 低(用快速插值) 中(固定CCM,不调AWB) 高(降噪和锐化要实时)

说白了,调度就是在算力预算内,把资源花在最能提升画质的地方。我见过有些团队把算力平均分配,结果夜景噪点一堆,白天锐度不够。好的调度是动态的——根据场景、帧率、功耗实时调整。