图像去噪全攻略:从空间域滤波到深度学习的算法与实现
简介面向图像处理初学者与研究者的图像去噪算法演示集合融合 Python 与 PyQt5既涵盖高斯滤波、中值滤波、快速傅里叶变换去噪、双边滤波、非局部均值去噪也加入了 DnCNN 等深度学习模型思路可应用于课程实验、算法对比和桌面小工具开发。压缩包共 6 个文件其中 5 个 py 脚本分别对应不同滤波算法及程序入口另有 1 个 ui 文件定义可视化界面整体仅 6KB轻量精简便于直接阅读、修改和运行。资源已有 6212 人学习用户可在图形界面中切换去噪方式、调节滤波器大小与平滑强度实时观察处理效果并保存图像从而直观理解空间域与频率域去噪的区别。对于希望系统掌握图像去噪原理并快速上手 PyQt5 应用开发的读者这套代码提供了可复用的参考实现能够帮助将算法理论快速落地为实际工具也为后续扩展更多算法留出了清晰接口。1. 图像去噪不是把图变干净先认清噪声类型再谈算法拿一张昏暗楼道里的监控画面说传感器一升温暗部全是彩色颗粒这就是我们要处理的噪声。图像去噪的目标很直接——把噪声抹掉但别把墙砖缝隙、车牌边缘、人物轮廓一起抹掉。很多初学者第一次跑均值滤波就发现“干净是干净了但糊成一团”这种翻车通常不是代码问题而是没分清噪声类型和滤波器的适用范围。这篇文章把空间域滤波、小波阈值去噪、深度学习去噪三条路线写到能直接复现的程度附上参数怎么调、指标怎么算、工程里最容易踩的坑。适合正在做图像处理作业、OpenCV 图像处理项目或者想往 ISP 图像处理方向走的人。想直接抄代码的可以跳到第2章但我建议耐住性子看完第5章那几条坑我交过学费。2. 空间域滤波均值和高斯为什么抹边缘中值和双边怎么救回来空间域滤波是去噪的入门路线也是 OpenCV 图像处理里最常用的工具箱。它直接对像素邻域做运算速度快、解释性强适合用来快速验证噪声水平也适合做复杂算法的预处理步骤。需要注意这类算法通常只对高斯噪声和椒盐噪声这两类常见噪声有稳定效果遇到复杂真实噪声比如暗光下的彩色噪点只能打个底。2.1 线性的均值与高斯滤波为什么边缘也被抹平先看一段基于 OpenCV 的最小实现import cv2 img cv2.imread(noisy_demo.jpg, cv2.IMREAD_GRAYSCALE) # 均值滤波窗口内像素求平均 mean_img cv2.blur(img, (5, 5)) # 高斯滤波窗口内像素按高斯权重加权求和 gauss_img cv2.GaussianBlur(img, (5, 5), sigmaX1.5)这段代码里 cv2.blur 的第二个参数是核尺寸也叫卷积窗口必须是正奇数。窗口越大平滑越强但边缘宽度也会被拉大。cv2.GaussianBlur 多了一个 sigmaX 参数它控制高斯核的权重分布sigmaX 建议取 1.01.6如果窗口是 5x5、sigma 又给得很大核权重会退化接近均值滤波边缘丢失更严重。很多教程会额外展示一个手动实现均值滤波的写法用 np.ones((3,3), np.float32)/9 丢给 cv2.filter2D。这在原理上与 cv2.blur 完全等价区别只是 filter2D 允许你自己设计核。理解这一步很重要均值核每个位置权重相等高斯核则是中心权重最大、四周按二维高斯函数递减。卷积核里没有考虑像素的局部关系只是把邻域信息垒在一起所以线性滤波几乎不可能“区分噪声和边缘”。再补充一个容易忽略的点高斯核的 sigma 与核尺寸需要匹配。OpenCV 里如果 sigmaX 传 0会按公式 sigma 0.3 * ((ksize - 1) * 0.5 - 1) 0.8 自动推导这个经验公式在 3x3 到 11x11 之间都适用。手动设置时核尺寸不要超过 6 * sigma 1否则核外层的权重已经接近零空转浪费算力。为什么工程上宁可用高斯也不用均值因为均值核在频域对应一个矩形窗的 sinc 函数阻带旁瓣很大平滑时容易在强边缘附近留下类似振铃的光晕高斯核没有这种旁瓣平滑更温和。所以均值滤波现在基本只用来做超快预处理或算法教学。如果观察到“图片干净但文字、栏杆发虚”说明窗口太大或者 sigma 太大。这时要优先把窗口降回 3x3而不是去加后续锐化锐化只会把噪声再放大。均值和高斯在数学上都是线性操作对边缘和噪声一视同仁地“平均”所以在去噪和保细节之间天然没有平衡点这是性质决定的不是代码能补的。实际项目中我一般只把线性滤波用在两个地方一是去掉平坦区域中较轻的读出噪声二是作为后续边缘检测或分割的预处理。真正的去噪主力还得看下面这两个非线性方案。2.2 中值和双边滤波让边缘活下来的非线性方案中值滤波的思路很朴素把窗口内所有像素排序取中间那个值作为中心像素输出。它对椒盐噪声也就是突兀的黑白点几乎是“一键清除”因为它直接丢弃了离群点不需要对离群值做加权。OpenCV 里一行即可median_img cv2.medianBlur(img, 5) # 第二个参数为窗口直径必须为大于1的奇数自己实现一个 3x3 中值也不难本质是把窗口内 9 个像素排序后取第 5 个值但注意这种写法在图像边缘会丢掉行列实际使用要补边界值用 BORDER_REPLICATE 效果不错。OpenCV 内部用的是历史直方图优化的快速中值CPU 上已经很快不必自己重写。中值滤波的代价是窗口里的细小纹理都被当成“噪声”处理了头发丝、栅栏这类高频结构窗口稍大就消失所以中值窗口一般不超过 5x5超过后画质下滑明显。双边滤波则换了个思路。它对像素做加权平均权重同时考虑两个距离空间距离离中心越近权重越大灰度距离灰度差越大权重越小。这个灰度权重把边缘两边的像素“隔离”开来因此能在去噪的同时保住边缘。实现如下# d 是窗口直径sigmaColor 控制灰度相似度sigmaSpace 控制空间相似度 bilat_img cv2.bilateralFilter(img, d9, sigmaColor75, sigmaSpace75)这三个参数第一次上手时很容易懵尤其是 sigmaColor 和 sigmaSpace 怎么配合。我的习惯是sigmaColor 取噪声幅度的 2 到 3 倍sigmaSpace 取 4080d 先给 9。如果结果有破碎感说明 sigmaColor 太大或 d 太小如果边缘在抖说明 sigmaSpace 太大。调参顺序固定为先定 d再调 sigmaSpace 到边缘稳定最后慢慢缩小 sigmaColor 直到噪声刚好消失。这个过程没有公式可以直接给答案非常依赖观察这也是很多人说双边滤波参数是玄学的原因。双边滤波还有一个视觉缺陷叫梯度反转在强边缘附近灰度距离权重可能把很小的噪声簇保留下来形成类似拼接的块状感。遇到这种情况常规做法不是继续调大 sigmaColor而是降低输出图像分辨率后再滤波或者把彩色图先转 Lab 空间只对 L 通道做双边减少色度方向的噪声干扰。实时视频里窗口和 sigma 都偏大时双边滤波很容易成为性能瓶颈尤其 CPU 上跑 1080p。常见做法是降采样到 720p 滤波后再放大或者用 Bilateral Grid 这类快速近似把计算量降几个量级。在智能车图像处理这类对毫秒级延迟敏感的场景里通常还会限制 sigmaSpace 不超过 40并保证滤波前后帧间噪声方差变化不超过 0.5。空间域滤波的整体选型可以按下表来算法适用噪声边缘保留耗时适用场景均值滤波均匀高斯噪声差极低预处理、亮度平稳区域高斯滤波高斯噪声差极低预处理、减少细节后做阈值分割中值滤波椒盐/脉冲中等低监控夜间闪烁点、打印扫描去点双边滤波低强度高斯好中等人脸美化、轻度去噪耗时这列只在 CPU 小图上对比。真要跑在 FPGA 或 ISP 流水线里中值和双边都能被改造成行缓冲结构的定点实现但参数必须固定死不能在运行期动态改窗口。这一章适合做第一版对实时性要求高的场景中值加自动阈值往往比后两章的算法更早能上板。3. 小波阈值去噪在高频系数里抖掉噪声3.1 为什么小波能区分噪声和边缘系数稀疏性与硬软阈值在空间域里噪声和边缘都是“变化剧烈的像素”很难分开。小波变换把图像分解成不同尺度的子带低频近似保留整体亮度高频细节携带水平边缘、垂直边缘和对角纹理。真实边缘的能量集中在少数几个大系数上而噪声能量均匀分布在所有高频小系数上。用一个阈值把“小”系数压掉再把系数重建回图像就完成了去噪。这就是小波阈值去噪的基本逻辑。阈值选多少是全部工程细节所在。最通用的固定阈值取λ σ × sqrt(2 × ln(N))N 是像素总数。σ 不是主观指定而是用第一层高频对角子带的中值绝对偏差来估计σ̂ median(|cD|) / 0.67450.6745 是标准正态分布下 MAD 与标准差的比例常数。这里容易犯的错是直接对整幅图像算 std得到的是一个被边缘污染的估计值。用对角子带是因为它在水平和垂直方向都不敏感更接近纯噪声背景。阈值函数有硬阈值和软阈值两种。硬阈值把小于阈值的系数置零、大于阈值的保留原值结果干净但会产生振铃伪影软阈值让所有系数向零收缩一个阈值看起来更柔和但会把边缘能量也削掉一部分。实践中绝大多数项目用软阈值只有当图像本身是二值图或边缘极锐利时才用硬阈值。与傅里叶变换对比更能看出小波的位置傅里叶变换把噪声和细纹理混在同一个频带里简单低通会连纹理一起去掉小波在多个尺度上做局部化分析至少能在尺度这一维上把二者分开但同一尺度内部仍然依赖阈值。这套方法对噪声标准差在 1560 范围的图像效果最明显噪声太弱时阈值会把细节全砍掉噪声太强时系数已经完全淹没阈值法也无能为力只能交给深层模型。3.2 基于 PyWavelets 的完整实现与 MATLAB 参数对照下面这段代码可以直接跑通一张灰度图的去噪流程import numpy as np import pywt def wavelet_denoise(img, sigmaNone, level4, wavdb4, modesoft): # 分解低频 多尺度高频 coeffs pywt.wavedec2(img, wav, levellevel, modeperiodization) # 用小波估计噪声标准差取最后一层对角高频 if sigma is None: cD coeffs[-1][2] sigma np.median(np.abs(cD)) / 0.6745 # 固定阈值公式 thr sigma * np.sqrt(2 * np.log(img.size)) # 第一个元素是低频后续才是高频分量 new_coeffs [coeffs[0]] for detail in coeffs[1:]: cH, cV, cD detail # 阈值处理默认软阈值 cH pywt.threshold(cH, thr, modemode) cV pywt.threshold(cV, thr, modemode) cD pywt.threshold(cD, thr, modemode) new_coeffs.append((cH, cV, cD)) # 重构与分解 mode 需一致 return pywt.waverec2(new_coeffs, wav, modeperiodization)调用例子denoised wavelet_denoise(gray_img, level4, wavsym8, modesoft)参数说明level分解层数4 层对 512x512 图是常用起点层数太多低频近似被反复抽稀会丢失大尺度纹理结构。判断 level 是否过大有个土办法把最后一层低频近似图放大回原尺寸如果它还能看到明显的闪烁点说明噪声没有完全被分到高频需要增加一层分解反过来如果低频图出现成块的“油墨感”说明分解过度细节已经被抽进高频并被阈值杀掉了。wav小波基工程里最先试 db4 或 sym8。db4 短小局部分辨率好sym8 更平滑振铃更少。bior 系列也可以但需要成对指定。mode阈值处理方式soft 默认若图像是文档扫描件换成 hard 能保留更锐利的笔画边缘。分解时的延拓模式上面代码用了 periodization。MATLAB 的 wdencmp 默认用对称延拓直接统一成 periodization 反而能避免两边结果不一致。如果用 MATLAB 做对照wdencmp(gbl, X, db4, 4, thr, s, 1) 里的 thr 就是上面算出来的标量阈值s 对应软阈值h 对应硬阈值。注意 MATLAB 与 PyWavelets 对边界延拓的约定不同同参数下系数会有一圈像素的差异算 PSNR 之前记得先裁掉 20 个像素。阈值倍率也是一个值得单独调的参数刚开始不要直接改阈值函数而是给固定阈值乘一个 0.81.2 的系数观察边缘完整度。倍率在 0.8 以下去噪几乎无效在 1.2 以上边缘损失速度明显加快。小波去噪最典型的问题有两个一是振铃在强边缘周围看到波纹对应阈值过高或小波基太长二是纹理丢失对应 level 过高或软阈值收缩过猛。第一次上手时先固定 level4、wavsym8单独调阈值倍率比一次性把四个参数全动有效得多。4. 深度学习去噪用 PyTorch 复现一个最小 DnCNN深度学习去噪不是“把网络换大一点”就能无限变强的事。它的前提非常具体训练数据里的噪声分布要接近真实场景。理解了这个前提再去看模型结构、损失函数和训练细节每一步都有明确目的。这节用一个轻量残差网络走通从合成噪声训练到推理的完整流程整段代码在 CPU 上也能跑出可见效果。4.1 理解残差学习模型预测噪声而不是干净图DnCNN 的思路是让卷积网络直接输出“噪声图”而不是干净图。输入是含噪图 x标签是纯噪声 n y - x网络学的是 f(x) ≈ n最终干净图 x - f(x)。这里的关键是残差目标更接近白噪声响应分布简单、尺度稳定网络在同样参数下收敛更快对深度设置的敏感度也更低。即使不用 BatchNorm一个 8 层左右的纯卷积残差网络已经能在合成高斯噪声上去掉一大半噪声。下面这个实现刻意去掉了 BatchNorm避免在推理时踩到 batch 统计量不一致的坑。import torch.nn as nn class TinyDnCNN(nn.Module): def __init__(self, depth8, n_feats64): super().__init__() self.in_conv nn.Conv2d(3, n_feats, 3, padding1) self.mid nn.ModuleList([ nn.Conv2d(n_feats, n_feats, 3, padding1) for _ in range(depth - 2) ]) self.out_conv nn.Conv2d(n_feats, 3, 3, padding1) self.relu nn.ReLU(inplaceTrue) def forward(self, x): x self.relu(self.in_conv(x)) for layer in self.mid: x self.relu(layer(x)) return self.out_conv(x)输入输出刻意保持 3 通道因为真实现实场景里彩色噪声的通道间相关性是客观存在的逐通道独立去噪会留下色斑。模型并不神秘它就是一组 3x3 卷积加 ReLU预测的是噪声那张图。选择 MSE 作为主损失是因为它与 PSNR 对齐度高、训练稳定如果想让人眼看起来更锐利可以在训练后期加入 SSIM 项做微调。4.2 合成噪声训练从照片切 patch 加噪声真实带噪声的高质量成对数据集很难拿到常见做法是找一批干净自然图像在线切 patch 并加上高斯噪声用有监督方式训练。这个合成数据和真实数据的 gap就是深度学习去噪产品的第一个翻车点。import torch import numpy as np import cv2 from torch.utils.data import Dataset class NoisyPatchDataset(Dataset): def __init__(self, image_paths, patch_size64, sigma25): self.paths image_paths self.patch_size patch_size self.sigma sigma def __getitem__(self, idx): img cv2.imread(self.paths[idx]) # 随机裁剪 h, w, _ img.shape ph, pw self.patch_size, self.patch_size y np.random.randint(0, h - ph) x np.random.randint(0, w - pw) patch img[y:yph, x:xpw].astype(np.float32) / 255.0 # 加高斯噪声sigma 单位与像素一致 noise np.random.randn(*patch.shape) * (self.sigma / 255.0) noisy np.clip(patch noise, 0, 1) return torch.from_numpy(noisy.transpose(2, 0, 1)), \ torch.from_numpy(patch.transpose(2, 0, 1))这里 sigma 的单位是 0255 的灰度值。sigma25 是中等噪声肉眼能明显看到颗粒但图像内容仍然清晰sigma50 以上接近重度噪声需要加深网络或加大 patch。patch 切到 64x64 是因为它能在内容丰富度和批量大小之间取平衡切太小会学不到长纹理结构切太大会拖慢训练。训练循环本身不复杂前向、算 MSE、反向model TinyDnCNN(depth8, n_feats64) optimizer torch.optim.Adam(model.parameters(), lr1e-3) loss_fn torch.nn.MSELoss() for epoch in range(20): for noisy, clean in dataloader: optimizer.zero_grad() pred_noise model(noisy) # 训练目标噪声图 干净图 - 含噪图 loss loss_fn(pred_noise, clean - noisy) loss.backward() optimizer.step()初始学习率用 1e-3每 10 个 epoch 乘以 0.5。如果显存足够把 batch size 提到 64 比提高学习率更有利于训练稳定性没有 GPU 的机器上patch 可以降到 48x48保证 20 分钟内能出一个能看的结果。推理时用输入减去预测噪声即可def denoise_with_model(model, noisy_bgr): tensor torch.from_numpy(noisy_bgr.transpose(2, 0, 1)).unsqueeze(0).float() / 255.0 with torch.no_grad(): pred_noise model(tensor) clean tensor - pred_noise clean clean.squeeze(0).permute(1, 2, 0).cpu().numpy() return np.clip(clean * 255, 0, 255).astype(np.uint8)这段代码跑出来的模型对 sigma25 的合成高斯噪声在常见测试图集上 PSNR 大约能到 3133 dB比双边滤波的 2829 dB 有明显提升。但注意它解决不了真实暗光噪声里的彩色偏因为训练数据只有高斯白噪声。要处理真实噪声做法是把训练噪声换成 raw 域泊松噪声模板或者用带真实噪声的配对数据做微调。这是深度学习去噪从 demo 走向产品的最关键一步也是 ISP 图像处理链路里最不值得省时间的一步。5. 去噪项目最容易踩的 5 个坑现象、原因与解决这一章集中记录我在实际项目里遇到过的典型问题。每一条都按现象、原因、解决的顺序写方便你对照自己的图快速定位。5.1 指标与边界PSNR 高不代表肉眼舒服换库后结果对不上第一个坑是指标崇拜。现象降噪后 PSNR 提升了 1.5 dB但把两张图放大到 100% 看纹理像面团边缘出现白边。原因PSNR 只是逐像素误差的平均程度它对“平滑感”几乎没有惩罚。一张把所有高频都抹平的图PSNR 常常很高因为它在平坦区减少了大量噪声误差但人眼恰恰在意边缘周围有没有振铃、纹理区有没有被过度平滑。解决用 PSNR 加 SSIM 双指标并在每个测试集里独立出一类“强纹理图”。SSIM 如果掉到 0.9 以下基本不能放行。肉眼在 100% 缩放下重点看三处边缘 5 像素范围内的明暗过渡、大面积平滑区的颗粒感、横幅文字的锯齿。这三处没问题再谈指标。第二个坑是跨库边界不一致。现象同一个算法、同一个阈值OpenCV 和 MATLAB 的去噪结果 PSNR 对不上差异集中在图像四周。原因两边边界延拓方式完全不同MATLAB 的 imfilter 默认用零填充OpenCV 的多数滤波函数默认用 BORDER_REFLECT_101小波分解对边缘的扩展方式也不一致。解决评估时统一把图像四周裁掉 20 个像素只对内部有效区域算指标。如果是对比不同库最省事的做法是先用 cv2.copyMakeBorder 把边界统一填充成复制模式处理完再裁回。凡是跨语言、跨库对比实验结果这一步不能省。5.2 彩色与结构RGB 通道滤波和形态学为什么越干越脏第三个坑是在 RGB 三个通道上无脑滤波。现象对一张夜景 RGB 图三个通道分别做高斯滤波输出图像的边缘出现彩色光晕去噪后色相偏移。原因RGB 三个通道的噪声方差受传感器 Bayer 排列和增益影响通道间相关很强。逐通道滤波没有利用这个相关性还把高亮度通道的强噪声扩散到了其他通道。解决先转 YCrCb 色彩空间对亮度通道 Y 做强去噪对 Cr/Cb 只做轻微去噪比如 3x3 高斯去噪完再转回 RGB。如果噪声是明显的彩色颗粒要优先确认 Bayer 排列方式并使用 ISP 馈送的 demosaic 后数据而不是直接在 RGB 上堆滤波器。第四个坑是形态学操作被当成去噪万金油。现象用 cv2.morphologyEx 的 MORPH_OPEN 处理后的图像黑点少了但文字变细、细小结构消失高斯噪声反而被放大。原因开运算本质是删除小于结构元的前景区域适合处理孤立点和断续线这类形态噪声对随机幅度分布的高斯噪声没有建模能力膨胀又会让暗部噪声聚集成块。解决形态学只用在二值图或掩膜上处理空洞和断线不要拿来应对灰度噪声。如果目标只是去掉椒盐噪声中值滤波不仅效果更好还不需要设计结构元。这条在工业检测里很常见很多人图省事直接拿开运算当去噪最后都会回来补中值。5.3 传感器噪声raw 域暗部那套高斯参数为什么失效第五个坑是真实传感器噪声不服从高斯分布。现象同一套高斯去噪参数在白天的图上效果很好换到夜间暗部就出现大量青蓝色噪点去不掉或越去越脏。原因真实传感器噪声由光子散粒噪声和读出噪声组成暗部光子数极低噪声几乎服从泊松分布又在高增益下被放大高斯模型这时严重失真。解决先用均匀亮度灰阶图做噪声标定统计每个亮度区间的标准差得到噪声水平随亮度的曲线再决定去噪强度。工程上常见的让步做法是对暗部不做强去噪而是用亮度自适应阈值在 YCrCb 空间里把暗部像素的降噪强度衰减到亮部的一半同时配合多帧时域平均。这也是大多数 ISP 图像处理链路里暗部降噪的标准做法。提示如果手里有 raw 原图先把黑电平扣除并完成白平衡校正再进亮度域去噪跳过这一步直接处理 RGB参数再好也救不回彩色噪点。若拿到的是 raw 和对应 RGB 图还可以用 Anscombe 变换把泊松噪声转成近似高斯再做高斯去噪最后逆变换效果比直接在 RGB 上做更稳。这套流程看着多但每步都是必要的。越早把“我的噪声是什么分布”这个问题搞清楚后面调参越省力。6. 上生产前先估噪声MAD 估计器与残差验证6.1 用 MAD 估计器给噪声“量个血压”再决定去哪条路线前面提到阈值法和深度模型对噪声强度都很敏感。问题是很多项目拿到图片就开始调滤波器参数调参用的图一旦换场景就失效。正确的顺序是先估计当前画面的噪声水平再根据水平选算法和参数。这个估计用最简单的 MAD 就能做import numpy as np import pywt def estimate_noise_std(gray_img): # 做一层小波分解取对角高频子带 cD _, (cH, cV, cD) pywt.dwt2(gray_img, db4) return np.median(np.abs(cD)) / 0.6745这个函数在任意一张灰度图上都能毫秒级返回一个标准差数值。按估计值选型我一般这样分档sigma 5肉眼几乎不可见不需要去噪最多做一次 3x3 高斯5 sigma 20双边滤波或小波软阈值足够优先双边参数直观且计算快sigma 20小波阈值开始不划算直接上轻量深度模型如果场景是监控或工业相机且帧率要求很高再考虑 FPGA 上的中值或小波硬件实现但前提是 sigma 已经用上面的方式标定过不要再拿默认参数去猜。这个分档不能覆盖所有真实噪声但给了一个可复现的起点。估计出的 sigma 只能指导算法选择不能直接当作滤波参数双边滤波的 sigmaColor 通常是它的 23 倍小波阈值则是 sigma × sqrt(2 lnN) 再乘一个 0.81.2 的比例系数。6.2 一张残差图撕开“去噪”和“磨皮”的区别去噪效果除了用指标判断我习惯在调试时多生成一张残差图残差 原图 - 去噪图。正确的结果里残差应该是一张没有明显结构的随机颗粒图如果残差里还能看到楼房的轮廓、窗帘的花纹说明这些本不该被去掉的结构被滤波器吃了。反过来残差灰度范围几乎为零说明当前参数根本没碰到噪声纯粹在空转。residual np.abs(orig.astype(np.float32) - denoised.astype(np.float32)) cv2.imwrite(residual.png, np.clip(residual * 8, 0, 255).astype(np.uint8))乘以 8 是为了把微弱残留放大到肉眼可见的程度。把残差图和原图叠在一起来回翻能发现很多指标发现不了的问题比如边缘过冲、色偏残留、局部块状伪影。我这几年的习惯是任何去噪算法改动先出残差图再谈质量好坏。这样反而省掉大量来回沟通改参数的时间。从估噪到选型从指标到残差这套流程是去噪项目能快速落地并且后期不靠玄学维护的关键。希望这些经验能帮到你下次拿到一张“看着脏”的图不用再从一个 3x3 高斯开始试起。本文还有配套的精品资源点击获取