4、去噪 (Denoise):空间域去噪 (Bilateral/BM3D)、时间域去噪 (3DNR)、RK 自研降噪算法特点
去噪这块,说实话是ISP Pipeline里最考验功力的环节之一。你想想看,传感器出来的原始数据,信噪比就那么点,后面还要做各种增益、Gamma、锐化,噪声一旦没压住,后面全给你放大了。我这些年调过不少平台的降噪模块,RK的方案给我印象最深的是——它不跟你玩花活,但每个模块都切中要害。
4.1 空间域去噪:Bilateral Filter 与 BM3D
空间域去噪,说白了就是在单帧图像里做文章。它的核心矛盾是:既要抹掉噪声,又不能把边缘细节给糊了。这个平衡点,找起来挺费劲的。
4.1.1 Bilateral Filter(双边滤波)
Bilateral Filter 是我个人非常喜欢的一个基础算子。它不像高斯滤波那样一视同仁地模糊所有像素,而是引入了「像素值差异」这个权重。
公式其实不复杂:
I_filtered(x) = (1/W_p) * Σ I(x_i) * G_s(||x - x_i||) * G_r(|I(x) - I(x_i)|)
这里有两个关键参数:
- 空间域sigma(σ_s):控制空间邻近度权重,越大则模糊范围越广
- 值域sigma(σ_r):控制像素值差异权重,越大则边缘保留能力越弱
我在项目中遇到过一个问题:σ_r设得太小,平坦区域噪声纹丝不动;设得太大,边缘又糊了。后来我总结出一个经验——σ_r应该跟当前区域的噪声标准差挂钩。噪声大的地方,σ_r适当放大;噪声小的地方,收紧它。RK的Bilateral实现里,其实就内置了这种自适应机制,它会根据局部亮度统计动态调整权重。
4.1.2 BM3D(三维块匹配滤波)
BM3D 是空间域去噪的天花板,但也是计算量的天花板。它的思路很有意思:先在图像里找相似的块,把它们叠成一个三维数组,然后在变换域(DCT或小波)里做阈值收缩。
流程大致分两步:
- 基础估计:硬阈值滤波,得到初步去噪结果
- 最终估计:用维纳滤波做二次增强
嗯,这里要注意——BM3D在RK平台上通常不会全分辨率跑。我见过一个方案是:在Y通道上做BM3D,UV通道用Bilateral。这样既保住了亮度细节,又控制了带宽。毕竟BM3D的复杂度是O(N log N)级别的,4K分辨率下实时处理,对DDR带宽是个不小的考验。
| 算法 | PSNR提升(典型值) | 计算开销 | 适用场景 |
|---|---|---|---|
| Bilateral | 2-4 dB | 低 | 实时预览、轻度噪声 |
| BM3D | 5-8 dB | 高 | 高画质拍照、低照度 |
4.2 时间域去噪:3DNR(三维降噪)
空间域去噪有个天然瓶颈——它只能利用单帧信息。但视频场景下,相邻帧之间有大量冗余信息。3DNR就是吃这碗饭的。
3DNR的核心思想是:运动区域用空间域,静止区域用时间域。怎么判断运动?这就涉及到运动补偿(Motion Compensation, MC)了。
RK的3DNR架构里,我印象最深的是它的运动检测模块。它不是简单做帧差,而是结合了块匹配和局部梯度信息:
// 伪代码示意
motion_level = f(block_sad, local_gradient, texture_complexity)
if motion_level < TH_LOW:
// 静止区域,强时间滤波
blend_ratio = 0.8
elif motion_level > TH_HIGH:
// 运动区域,退化为空间滤波
blend_ratio = 0.0
else:
// 过渡区域,自适应混合
blend_ratio = linear_interp(motion_level)
我个人习惯把时间滤波的强度跟场景亮度挂钩。暗光下噪声大,时间滤波可以开猛一点;白天光线好,稍微意思一下就行。否则容易拖出鬼影——嗯,鬼影是3DNR最头疼的问题。
4.3 RK 自研降噪算法特点
RK的自研降噪,不是简单把Bilateral和3DNR拼在一起。它有几个让我觉得挺有意思的设计:
- 多尺度分解:RK把图像分解成低频、中频、高频三个层次。低频做轻度平滑,中频做边缘保护降噪,高频做细节保留。每个频段的降噪参数独立可配。
- 亮度自适应阈值:暗区的噪声是泊松分布的,亮区是高斯分布的。RK的降噪模块会根据像素亮度动态切换噪声模型,这个细节很多平台没做到。
- 纹理保护机制:RK在降噪前会先做一次纹理检测。如果当前区域是草地、布料这类高频纹理,它会降低降噪强度,防止纹理被抹成一片。
我记得有一次调一个室内监控场景,天花板上的纹理细节总是被磨平。后来发现是纹理检测的阈值设得太保守了。把纹理检测的灵敏度从0.3调到0.5之后,效果立竿见影。
isp_denoise_config 结构体里的 dnr_level 和 texture_protect 两个参数,调好了能省不少事。
最后说一句——降噪这件事,没有银弹。Bilateral快但糊,BM3D好但慢,3DNR强但有鬼影。RK的做法是把这些工具组合起来,让它们在各自擅长的场景里发挥作用。你想想看,这其实跟做菜一个道理——没有万能调料,关键看你怎么搭配。
dnr_level 入手,把它从0调到100,观察噪声和细节的变化曲线。找到拐点之后,再微调 texture_protect。我一般会把 texture_protect 设在0.4-0.6之间,太低纹理容易丢,太高噪声压不住。