4、噪声估计方法:基于块的噪声估计、基于变换域的噪声估计、基于深度学习的噪声估计

噪声估计,说白了就是搞清楚「这张图里到底有多少噪声」。

我刚开始做夜景算法时,总觉得降噪就是使劲模糊。结果呢?细节全没了,照片像油画。后来才明白——不知道噪声长什么样,就别想把它去掉。

这一章,我们聊聊三种主流的噪声估计思路。它们各有各的脾气,也各有各的用武之地。

4.1 基于块的噪声估计

这是最经典的方法。我习惯叫它「找平地的思路」。

你想啊,一张图里总有纹理平坦的区域——比如天空、墙壁、桌面。这些地方本来应该是均匀的,像素值的波动基本就是噪声本身。

4.1.1 基本原理

把图像切成小块,比如 8×8 或 16×16。对每个块计算方差。方差小的块,说明纹理少,噪声占主导。把这些「干净块」的方差收集起来,就能估计出全局噪声水平。

核心假设:图像中存在足够多的平坦区域,且噪声在空间上平稳。

4.1.2 实现步骤

  1. 图像分块:将图像划分为不重叠的 N×N 小块。
  2. 计算局部方差:对每个块计算像素值的方差 σ²_local。
  3. 筛选平坦块:保留方差最小的前 10%~20% 的块。
  4. 统计估计:对这些块的方差取中位数或均值,得到噪声方差 σ²_n。
// 伪代码:基于块的噪声估计
function estimateNoiseBlockBased(image, blockSize=8, percentile=0.2):
    blocks = splitIntoBlocks(image, blockSize)
    variances = []
    for block in blocks:
        variance = computeVariance(block)
        variances.append(variance)
    // 取方差最小的 percentile 比例的块
    sortedVars = sort(variances)
    thresholdIdx = int(len(sortedVars) * percentile)
    selectedVars = sortedVars[:thresholdIdx]
    noiseVariance = median(selectedVars)
    return sqrt(noiseVariance)  // 噪声标准差

我的经验:块大小选 8×8 比较稳妥。太大容易混入纹理,太小统计不稳定。我在项目中遇到过一块全是渐变天空的情况——方差其实不小,但那是光照变化,不是噪声。后来我加了梯度检测,把梯度大的块也排除掉,效果好了很多。

4.1.3 优缺点

优点 缺点
实现简单,计算快 对纹理丰富的图像估计不准
不需要先验知识 假设噪声空间平稳,实际不总是成立
适合实时处理 低噪声场景下容易低估

4.2 基于变换域的噪声估计

这个方法更巧妙。它把图像变换到另一个「域」里,让噪声和信号更容易分开。

为什么会这样?你想想看,自然图像在频域或小波域里,能量通常集中在低频或少数大系数上。而噪声呢?它均匀分布在所有频率上。这就给了我们可乘之机。

4.2.1 小波域估计

我个人最喜欢用小波变换。把图像分解成不同尺度和方向的子带。高频子带里,信号能量弱,噪声占主导。直接用高频子带的系数就能估计噪声。

// 伪代码:小波域噪声估计
function estimateNoiseWavelet(image):
    // 做一层小波分解
    [LL, LH, HL, HH] = dwt2(image, 'db4')
    // HH 子带是高频对角线方向,噪声最集中
    noiseSigma = median(abs(HH(:))) / 0.6745
    return noiseSigma

关键公式:σ_n = median(|HH|) / 0.6745

0.6745 是高斯分布的中位数与标准差的换算系数。这个公式来自 Donoho 的经典,我用了好多年,非常稳。

4.2.2 DCT 域估计

另一种思路是用 DCT(离散余弦变换)。把图像块变换到 DCT 域,DC 系数代表均值,AC 系数代表纹理和噪声。对于平坦块,AC 系数基本就是噪声。

我记得有一次做手机夜景算法,传感器在暗光下噪声模型很复杂——不是简单的高斯。基于块的估计完全失效。换成 DCT 域方法后,把每个块的 AC 系数直方图拟合一下,居然把非高斯噪声也估计出来了。

4.2.3 优缺点对比

方法 优势 局限
小波域 对非平稳噪声鲁棒,多尺度分析 计算量稍大,小波基选择有影响
DCT 域 与 JPEG/HEVC 兼容,硬件友好 块效应可能干扰估计
FFT 域 全局分析,适合周期性噪声 对空间变化噪声不敏感

4.3 基于深度学习的噪声估计

这是近五年的主流方向。说白了,就是让神经网络自己学会「看」噪声。

你想想看,传统方法需要手工设计特征和假设。深度学习不一样——给它海量的「干净图 + 噪声图」对,它自己就能总结出噪声的规律。

4.3.1 网络架构思路

  • 端到端估计:输入单张噪声图,直接输出噪声标准差图(每个像素一个值)。
  • 噪声分离网络:类似 U-Net 结构,编码器提取特征,解码器输出噪声分量。
  • 自监督方法:不需要干净图,利用噪声在空间上的独立性来估计。比如 Noise2Noise、Noise2Void 的思路。

我踩过的坑:曾经用合成噪声训练了一个网络,效果惊艳。一上真实手机数据,直接翻车。为什么?合成噪声太「干净」了——真实传感器噪声有行噪声、固定模式噪声、量化噪声,合成数据根本模拟不全。后来我改用真实数据 + 少量合成数据混合训练,才算稳住。

4.3.2 典型网络结构

输入: 噪声图像 (H, W, 3)
  ↓
Conv3×3 + ReLU → 64通道
  ↓
Conv3×3 + ReLU → 128通道
  ↓
Conv3×3 + ReLU → 256通道
  ↓
Conv3×3 + ReLU → 128通道
  ↓
Conv3×3 + ReLU → 64通道
  ↓
Conv3×3 → 1通道 (噪声标准差图)
  ↓
输出: 每个像素的噪声标准差 σ(x, y)

实用建议:输出层不要用 ReLU,用 Softplus 或 ELU+1,保证噪声标准差始终为正。我一开始用 ReLU,结果某些像素输出 0,导致后续降噪除零崩溃……

4.3.3 训练数据生成

方法 做法 适用场景
合成数据 干净图 + 高斯/泊松噪声模型 快速验证,预训练
真实数据 多帧平均得到近似干净图 实际产品,精度高
混合训练 合成 + 真实按比例混合 兼顾泛化与精度

4.4 三种方法对比总结

嗯,到这里三种方法都聊完了。我画了一张图,帮你把它们的定位看清楚。

噪声估计方法对比框架 基于块的估计 基于变换域的估计 基于深度学习的估计 局部方差法 梯度筛选法 小波域中位数法 DCT 域分析法 端到端回归 自监督法 适用场景 块方法:平坦场景、实时系统 | 变换域:非平稳噪声、多尺度分析 | 深度学习:复杂噪声、高精度需求 性能对比 指标 块方法 变换域 深度学习 计算速度 ★★★★★ ★★★★☆ ★★☆☆☆ 估计精度 ★★★☆☆ ★★★★☆ ★★★★★ 泛化能力 ★★☆☆☆ ★★★☆☆ ★★★★★

重要提醒:没有万能的方法。我在项目中见过有人非要用深度学习估计一个平稳高斯噪声——杀鸡用牛刀,还增加了功耗。反过来,也有人用块方法去估计传感器行噪声——根本估计不出来。选方法之前,先搞清楚你的噪声长什么样。

4.5 实际工程中的选择建议

最后,我根据自己的经验,给几个实际建议:

  • 手机实时预览:用基于块的估计。计算量小,够用就行。
  • 专业相机后处理:用变换域方法。精度更高,能处理复杂噪声。
  • 计算摄影旗舰机:上深度学习。但一定要用真实数据微调,别信合成数据的泛化能力。
  • 混合方案:我现在的做法是——用块方法做快速粗估计,用轻量 CNN 做精细估计。两者互补,速度和精度都能兼顾。