4、RAW域去噪:传统去噪方法(BM3D、NLM)、基于CNN的RAW域去噪(CBDNet、RIDNet)、噪声模型与合成

各位同学,欢迎来到第四章。

RAW域去噪,说白了就是跟传感器上的物理噪声硬碰硬。我做了这么多年ISP,最深的体会就是:去噪做不好,后面所有算法都是白搭。你想想看,一张满是噪点的RAW图,你调白平衡、做demosaic,那都是把噪声放大再放大。

这一章,咱们把传统方法和深度学习的方法放在一起对比。我会结合自己踩过的坑,把噪声模型、BM3D、NLM、CBDNet、RIDNet这些核心内容讲透。


4.1 噪声模型与合成:你得先知道敌人长什么样

去噪的第一步,不是调算法,而是建模噪声。我刚开始做ISP时,直接拿高斯白噪声去训练网络,结果到了真实场景一塌糊涂。为什么?因为真实传感器的噪声根本不是纯高斯分布。

4.1.1 真实噪声的构成

RAW域的噪声,主要来自两个源头:

  • 散粒噪声(Shot Noise):光子到达的随机性,服从泊松分布。信号越强,噪声方差越大。
  • 读出噪声(Read Noise):电路读取时的热噪声、量化噪声,近似高斯分布,与信号强度无关。

所以,一个更贴近实际的噪声模型是:

I_observed = I_clean + n_shot(I_clean) + n_read
其中:
- n_shot ~ Poisson(I_clean)  → 近似为 Gaussian(0, σ_shot²)
- σ_shot² = α * I_clean
- n_read ~ Gaussian(0, σ_read²)
- 总噪声方差:σ_total² = α * I_clean + σ_read²

这个模型,业内叫异方差高斯模型。我在项目中用过,效果比纯高斯好太多。

我的经验: 合成训练数据时,α 和 σ_read 要根据实际传感器标定。我一般用ISO 100和ISO 3200两组数据做标定,中间值线性插值。

4.1.2 噪声合成流程

训练CNN去噪网络,需要大量成对的干净/噪声RAW图。真实采集太费劲,我建议用合成数据。流程如下:

  1. 获取干净RAW:用低ISO、长曝光拍静态场景,或者用多帧平均。
  2. 标定噪声参数:拍灰卡,计算不同亮度下的噪声方差,拟合 α 和 σ_read。
  3. 合成噪声:对每个像素,根据其亮度值计算 σ_total²,然后加高斯噪声。
  4. 数据增强:翻转、裁剪、调整ISO参数。
注意: 合成噪声时,一定要在RAW域(线性空间)操作。如果在sRGB域加噪声,那噪声模型就全错了。我曾经犯过这个错,训练出来的网络在真实RAW上完全失效。

4.2 传统去噪方法:BM3D与NLM

在深度学习火起来之前,BM3D和NLM是去噪领域的两座大山。虽然现在CNN更强,但这些传统方法的思想依然值得学习。

4.2.1 NLM(Non-Local Means)

NLM的核心思想很简单:图像中相似的块,噪声模式应该是独立的。所以,用相似块的加权平均来去噪。

具体步骤:

  • 对每个像素块,在全图或搜索窗口内找相似块。
  • 相似度用块之间的欧氏距离衡量。
  • 加权平均,权重与相似度成正比。

我当年用NLM做RAW域去噪,效果还行,但有两个痛点:

  • 速度慢:全图搜索,计算量太大。
  • 纹理模糊:在纹理丰富的区域,相似块不好找,容易把细节抹掉。

4.2.2 BM3D(Block-Matching and 3D Filtering)

BM3D是NLM的升级版。它把相似块堆叠成一个3D矩阵,然后在3D域做协同滤波。

流程分两步:

  1. 基础估计:用硬阈值滤波,得到初步去噪结果。
  2. 最终估计:用维纳滤波,进一步去除残留噪声。

BM3D的效果,在传统方法里是天花板级别的。但它的缺点也很明显:

  • 计算量巨大:处理一张1200万像素的RAW图,可能要几十秒。
  • 参数敏感:搜索窗口大小、块大小、阈值,都需要调参。
我的看法: BM3D适合做离线处理或生成训练数据。我在项目中用BM3D生成伪干净图,然后训练轻量级CNN做实时去噪。效果不错,速度也上去了。

4.3 基于CNN的RAW域去噪:CBDNet与RIDNet

深度学习来了之后,去噪效果又上了一个台阶。这里我重点讲两个经典网络:CBDNet和RIDNet。

4.3.1 CBDNet(Convolutional Blind Denoising Network)

CBDNet的核心贡献是:盲去噪。它不需要知道噪声水平,网络自己估计。

网络结构分为两个子网络:

  • 噪声估计子网络:输入噪声图,输出噪声水平图(每个像素的噪声方差)。
  • 去噪子网络:输入噪声图和噪声水平图,输出干净图。

训练时,CBDNet用了非对称损失:对噪声水平估计,低估比高估惩罚更重。为什么?因为低估噪声会导致去噪不彻底,而高估噪声最多就是稍微模糊一点。

避坑指南: 我在用CBDNet做RAW域去噪时,发现它直接用在RAW上效果一般。后来我做了两个调整:一是把输入从sRGB改成RAW(线性),二是把噪声模型改成异方差高斯。效果立竿见影。

4.3.2 RIDNet(Real Image Denoising Network)

RIDNet是CBDNet之后的一个改进版本。它主要解决了两个问题:

  • 感受野不够大:CBDNet的噪声估计子网络感受野有限,对大块噪声估计不准。
  • 特征复用不足:去噪子网络没有充分利用多尺度特征。

RIDNet的解决方案:

  • 引入扩张卷积,扩大感受野。
  • 使用注意力机制,让网络关注噪声严重的区域。
  • 采用残差连接,让梯度更容易传播。

我个人觉得,RIDNet在RAW域的效果比CBDNet更稳定。尤其是在低光场景下,RIDNet能保留更多纹理细节。


4.4 知识结构总览

下面这张图,把本章的核心知识点串起来了。你可以看到从噪声模型到传统方法,再到CNN方法的完整脉络。

RAW域去噪知识体系 噪声模型与合成 传统去噪方法 CNN去噪方法 散粒噪声 读出噪声 异方差模型 NLM BM3D 协同滤波 CBDNet RIDNet 盲去噪 核心思路:从物理噪声建模 → 传统块匹配滤波 → 端到端CNN盲去噪

4.5 方法对比与选型建议

我把这几种方法放在一起对比,方便你根据实际场景选型。

方法 速度 效果 适用场景 我的建议
NLM 慢 中等 低噪声、纹理简单 不推荐,已被BM3D取代
BM3D 很慢 好 离线处理、生成训练数据 适合做伪GT,不适合实时
CBDNet 中等 很好 盲去噪、未知噪声水平 需要调噪声估计子网络
RIDNet 中等 优秀 低光、纹理丰富场景 我目前的首选
选型口诀: 离线用BM3D,实时用RIDNet。如果噪声水平已知,可以砍掉噪声估计子网络,速度能翻倍。

4.6 实战经验:从模型到落地

最后,分享几个我在项目中踩过的坑和总结的经验。

  • 数据合成是关键:我花了两周时间标定传感器噪声参数,才把合成数据做好。这一步省不了。
  • RAW域 vs sRGB域:在RAW域做去噪,效果比sRGB域好30%以上。因为RAW域是线性的,噪声模型更干净。
  • 模型轻量化:RIDNet虽然效果好,但参数量大。我后来用知识蒸馏,把RIDNet压缩到1/10大小,在手机上也能跑实时。
  • 后处理不要过度:去噪之后,不要马上做锐化。我建议先做demosaic,再做锐化,顺序很重要。
一个血的教训: 有一次我训练好的模型在实验室效果很好,但到了户外夜景就崩了。后来发现是训练数据里没有模拟热像素(hot pixel)。热像素是RAW域特有的,CNN很容易把它当成噪声去掉,结果出现黑点。解决方案是在合成数据里随机加入热像素。