Pipeline核心模块解析:RAW域、RGB域与YUV域处理
各位同学,今天我们来啃Pipeline里最硬核的部分——三个色彩空间域的处理。说实话,我刚入行时也被这些域搞晕过。RAW、RGB、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) | 高(降噪和锐化要实时) |
说白了,调度就是在算力预算内,把资源花在最能提升画质的地方。我见过有些团队把算力平均分配,结果夜景噪点一堆,白天锐度不够。好的调度是动态的——根据场景、帧率、功耗实时调整。