资讯动态

MATLAB图像去噪实战:传统算法与CNN对比解析

发布时间:2026/9/8 23:08:25 来源:尧图企业网站定制
简介面向图像去噪研究与复现这套MATLAB代码包完整实现了DnCNN卷积神经网络去噪模型同时提供均值滤波、中值滤波、非局部均值滤波NLM和三维块匹配滤波BM3D四种传统算法作为对照适合深度学习、数字图像处理方向的课程设计或算法对比实验。代码支持强度为1070的高斯白噪声处理并采用PSNR与SSIM指标自动评估结果方便量化不同算法的去噪效果。压缩包共177个文件以m脚本、mat数据、png示例图像为主另含mexw32/mexw64等多平台编译的MEX加速文件整体约80.31MB。附带Set12标准测试集可直接运行Demo脚本比较五种算法的表现也可自行扩展数据集获取更充分的验证结论。压缩包内目录组织清晰模型实现、测试数据与运行脚本相对独立便于快速定位和二次开发。目前已有3756人学习下载适合希望系统掌握传统去噪与深度去噪差异的中高级学习者。 图像去噪这个东西听起来像是教科书里才会讲的基础内容但真正做图像处理落地的人都知道它是绕不开的坎。不管是工业视觉检测、医学影像分析还是手机拍照算法的后处理链路第一道关永远是“把噪声压下去同时别把细节抹掉”。噪声本身并不可怕可怕的是你为了去噪把边缘搞糊了或者把纹理细节当成噪声给干掉了那后面所有的高层任务——分割、识别、配准——都会跟着遭殃。我做 ImageDenoise 这个项目初衷很简单把手边常用的去噪算法全部整理到 MATLAB 里用同一套数据、同一个评价标准跑一遍既是为了给组里新来的同事一份能直接抄作业的代码也是想认真对比一下传统去噪算法和卷积神经网络CNN之间的真实差距。项目不但覆盖了均值滤波、中值滤波、非局部均值滤波NLM等经典传统方法还在 MATLAB 深度学习工具箱里搭了一个轻量级的 CNN 去噪网络。最后产出的是一套模块化的 MATLAB 工程输入一张带噪图就能一键输出所有算法的去噪结果和 PSNR/SSIM 对比表。这篇就把我实现这套东西的全过程、踩过的坑、调参的经验以及实测结论都整理出来供做图像处理的朋友参考。1. 项目背景为什么要在 MATLAB 里做一套完整的去噪对比工程1.1 图像去噪为什么值得单独做一套代码很多刚入门的朋友会觉得去噪就是“模糊一下完事”实际远不是这么简单。真实场景里的噪声来源很杂传感器热噪声、暗电流、低光照下的光子散粒噪声、传输过程中的量化噪声叠加在一起往往是混合噪声。不同类型的噪声需要用不同的策略去处理。比如椒盐噪声用中值滤波就特别灵而高斯噪声更适合非局部均值或深度学习的方法。如果没有一套规范的对比环境靠感觉选算法很容易翻车。这是我坚持用 MATLAB 做这套工程的原因之一。MATLAB 的图像处理工具箱把 imfilter、medfilt2 这些常用函数封装得相当成熟更关键的是它自带的深度学习工具箱可以无缝对接传统图像处理流程。你可以在同一个脚本里先给图像加噪声然后既调用传统滤波器又搭建和训练 CNN最后统一用 psnr、ssim 计算指标。这种“传统方法 深度学习方法”同一个管道对比的能力用别的语言搭起来要费不少劲MATLAB 基本开箱即用。1.2 ImageDenoise 的整体设计思路整个项目我按三个模块来组织加噪与预处理模块、去噪算法模块、质量评估模块。第一个模块负责生成实验数据包括对干净图像添加指定噪声类型和强度的高斯噪声或椒盐噪声第二个模块把均值、中值、NLM、CNN 这几种算法的接口统一封装成函数输入带噪图、输出去噪图第三个模块计算 PSNR、SSIM并把所有结果汇总成表格和对比图。模块化设计的最大好处是可扩展。后来组里同事想加一个双边滤波器只需要按照同样的接口写一个函数不碰其他任何代码就能跑通对比。我强烈建议做这类工具工程时别把所有逻辑堆在一个脚本里哪怕只是自用也值得把接口约定好。另外一个关键点是所有算法必须使用完全相同的测试图像和噪声添加参数否则对比结果没有意义。我在这上面吃过亏——有一次在 CNN 训练数据里混入了测试图的噪声版本结果 PSNR 虚高得离谱后来才发现是数据划分没做好。2. 传统去噪算法的 MATLAB 实现细节2.1 均值滤波看似简单坑也不少均值滤波是最基础的空间域去噪方法核心思想就是对目标像素的邻域取平均值。MATLAB 里最简单的实现是直接用 fspecial 生成均值核再用 imfilter 做卷积% 均值滤波3x3 邻域平均 h fspecial(average, [3 3]); img_denoised imfilter(img_noisy, h, replicate);代码很简单但有几个细节需要注意。首先是边界处理方式imfilter 的边界选项有 symmetric、replicate、circular 等实测下来 replicate复制边缘像素在大多数自然图像上表现比较稳不会像默认的零填充那样在边界产生一圈黑色伪影。其次均值滤波的核心矛盾在于核窗口越大噪声抑制越强但图像越模糊。3x3 和 5x5 的视觉效果差距可能不大一旦到 9x9 甚至更大边缘基本就糊成一团了。均值滤波的定位是“快速预览”和“轻度噪声压制”一般作为预处理步骤用。我试过在流水线检测里先用均值滤波压噪再做边缘提取效果并不好因为边缘同时被模糊了提取出的轮廓会偏移。所以后来我对它的定位很明确它更适合做工程上的快速降噪不适合作为最终效果输出。2.2 中值滤波对付椒盐噪声的利器中值滤波的思路和均值完全不同它不是求平均而是把邻域内的像素值排序后取中间值。这个操作让它在去除椒盐噪声像素值突然变白或变黑时效果非常出色因为突变的极值在排序后会被天然排除掉。MATLAB 中实现只需要一行% 中值滤波3x3 邻域取中值 img_denoised medfilt2(img_noisy, [3 3]);中值滤波最优秀的特点是它能在去噪的同时较好地保持边缘。原因也很好理解边缘两侧的像素值在排序后边缘像素取到的中值往往还在原本的边缘区间内不会像均值滤波那样把两侧的颜色混在一起。这个特性让它在文档扫描、文字图像处理里特别常用。但要注意medfilt2 默认只处理二维灰度图像如果你输入的是 RGB 彩色图会直接报错。处理彩色图时要逐通道调用比如对每个通道分别 medfilt2 后再合并。另外中值滤波对高斯噪声的效果很一般因为它没有从根本上解决高斯噪声“处处存在”的问题排序后的中值仍然是带噪的。实测下来对高斯噪声图用 5x5 中值滤波PSNR 提升通常只有 2-3 dB远低于 NLM 等高级算法。2.3 非局部均值滤波NLM传统算法里的旗舰款非局部均值滤波是我在这个项目里最喜欢深究的传统算法。它和前面两种滤波有一个本质区别均值和中值都只看目标像素周围一个小邻域而 NLM 认为图像中远距离的相似块也可以为目标像素的去噪提供参考。简单说它不是“邻域平均”而是“全图相似块加权平均”。NLM 的核心公式是对于每个像素 i去噪结果为搜索窗口内所有像素 j 的加权平均权重 w(i,j) 取决于以 i 和 j 为中心的两个图像块之间的相似度相似度用块间高斯加权欧氏距离的指数函数来衡量。MATLAB 里手写 NLM 的核心循环大致是这样的结构% NLM 核心逻辑示意代码实际需优化 % searchWindow 为搜索窗口半径patchSize 为相似块半径 sigma 25; % 噪声标准差 h 1.2 * sigma; % 平滑系数经验值 for i 1 : imgH for j 1 : imgW weightSum 0; valueSum 0; for m -searchWindow : searchWindow for n -searchWindow : searchWindow % 计算块间距离 d d sum((patch(i,j) - patch(im,jn)).^2) / (2 * patchSize 1)^2; w exp(-d / h^2); weightSum weightSum w; valueSum valueSum w * img(im, jn); end end img_denoised(i,j) valueSum / weightSum; end end这段代码逻辑上是标准 NLM但实际跑起来会非常慢因为两重循环套两重循环的复杂度是 O(像素数 × 搜索窗口面积)。我在测试 512x512 的图像上直接跑这套原始实现一晚上都没跑完一张图。后来我用矩阵化和积分图加速整个耗时才降到秒级。所以如果你第一次在 MATLAB 里写 NLM请务必提前做好性能优化心理准备。NLM 的参数选择经验是搜索窗口一般取 7 到 15 像素相似块patch取 3 到 5 像素半径。平滑系数 h 和噪声水平直接相关实测下来 h 取 1.2 倍 σ噪声标准差效果比较稳。h 太小时噪声残留多太大时图像会被过度平滑到出现“油画感”。要注意的是NLM 对纹理区域比较敏感相似块误匹配会导致局部发生阶梯状伪影这个现象在低纹理区域几乎看不见但在高纹理区域会非常明显。2.4 补充BM3D 也是可选项在写这个项目时我最初把三维块匹配滤波BM3D也列入了计划因为它可以说是传统去噪算法里的天花板效果和 NLM 相比又有明显提升。它的核心思路是在 NLM 的“块匹配”基础上加了一步三维变换域协同滤波把相似块堆叠成三维数组做三维变换后在变换域里做阈值收缩再做逆变换聚合。不过 BM3D 的 MATLAB 实现比较繁琐需要分别处理“基础估计”和“最终估计”两个阶段加上三维小波变换和维纳滤波代码量不小。而且 BM3D 的计算速度比 NLM 更慢内存占用也高。如果你是想快速上手对比传统算法先把均值、中值、NLM 这三个跑通就够了如果追求效果上限BM3D 值得再花一周时间去啃。3. 基于卷积神经网络CNN的去噪模型搭建与训练3.1 训练数据准备与预处理CNN 去噪的思路和传统方法完全不一样。传统算法是人工设计滤波规则CNN 则是从大量“干净图 带噪图”的配对数据中自己学习映射关系。这里最关键的一点是数据集怎么构造。我的做法是准备一批干净的灰度图像作为 ground truth对每张图像随机裁取 40x40 的 patch然后给 patch 添加指定强度的高斯噪声形成“带噪 patch - 干净 patch”的训练对。MATLAB 中可以用 imageDatastore 来管理图像数据集再用自定义的预处理函数完成加噪和 patch 提取。需要注意训练时噪声强度要和测试时保持一致否则模型会水土不服。比如你用 σ25 训练的模型拿去处理 σ50 的噪声图效果会大打折扣。更严谨的做法是在每个 epoch 里随机变更噪声强度让模型学会适应一定范围的噪声但这样模型容量要求更高训练时间也成倍增加。数据归一化是另一个容易翻车的地方。图像像素值在 MATLAB 默认是 uint80-255但深度网络训练时一般要求输入在 [0,1] 或 [-1,1] 区间。我一开始偷懒直接输入 uint8结果 loss 震荡得厉害梯度更新完全失常。后来统一改为 im2double 转换到 [0,1]并顺手把均值也做了零均值化训练才稳定下来。这里有一个必须记住的原则推理阶段的预处理必须和训练阶段完全一致否则相当于换了一个输入分布。3.2 网络结构设计与残差学习CNN 去噪的网络结构可以写得很复杂但我的经验是先从一个简单的三层卷积网络开始理解了残差学习的思想后再扩展效果会更好。这里的残差学习非常巧妙我们让网络学的是“带噪图与干净图的差”也就是噪声本身而不是直接输出干净图。因为干净的图像结构信息比较复杂网络很难直接预测而噪声相对于图像来说结构简单得多学起来容易很多。最后用带噪图减去网络预测的噪声就得到去噪图。% 构建一个轻量级 CNN 去噪网络残差学习 layers [ imageInputLayer([40 40 1], Normalization, none) convolution2dLayer(3, 64, Padding, same) reluLayer convolution2dLayer(3, 64, Padding, same) reluLayer convolution2dLayer(3, 1, Padding, same) regressionLayer ];我的网络结构是三个 3x3 卷积层中间两层用 ReLU 激活最后回归到单通道噪声图。虽然结构简单但残差学习的引入让它在实际效果上能赢过传统 NLM。 这里还有个细节因为我们在训练时故意把输出目标设成了“噪声”而不是“干净图”所以网络的 loss 必须是预测噪声和真实噪声之间的均方误差这一点在 regressionLayer 的定义里直接体现不需要额外处理。如果想要更好的效果可以把网络加深到 5-10 层、增大卷积核数量或者引入 inception、残差块这些更现代的结构。但要注意加深网络带来的训练时间剧增也很快。我用一个 3 层网络在 NVIDIA GTX 1660 上训练 30 个 epoch大概耗时 1 小时左右换成 10 层网络时间直接涨到 4 小时以上。做对比实验时建议先用浅层网络验证整个 pipeline 没问题再逐步加深。3.3 训练选项的设置细节MATLAB 的 trainingOptions 配置是个容易看走眼的地方。我常用的配置是这样的options trainingOptions(sgdm, ... InitialLearnRate, 0.01, ... LearnRateSchedule, piecewise, ... LearnRateDropFactor, 0.5, ... LearnRateDropPeriod, 10, ... MaxEpochs, 30, ... MiniBatchSize, 128, ... Shuffle, every-epoch, ... Verbose, false, ... Plots, training-progress);几个关键参数的解释优化器 SGDM 适合中小规模数据集训练比 Adam 更稳初始学习率 0.01 对这个小网络来说是保守但安全的选择如果网络加深到 10 层建议把初始学习率降到 0.001MiniBatchSize 受限于显存大小40x40 的 patch 是 128 还是 256 差异不大但再大的 patch 或更强算力需求就要相应调低。训练过程中我会盯着 training-progress 的曲线如果 loss 在前期掉得很快但后面震荡大概率是学习率设高了如果 loss 下降太慢那可能网络容量不够或者学习率低了。3.4 训练和推理的细节心得训练完成后做推理时要注意CNN 输入是固定尺寸的 patch但测试图往往是任意大小。我的做法是将整张图按 40x40 滑窗切块逐块去噪后再拼接回来。这种做法有一个需要注意的边界效应每个 patch 边缘的像素因为卷积 padding 的关系去噪质量会比中心区域略差一点。解决这个问题最简单的办法是重叠切块相邻 patch 之间重叠 10 个像素拼接时只取每个 patch 的中心区域效果会明显改善。还有一个大家很容易忽略的地方模型推理速度。GPU 推理一张 512x512 的灰度图大概 0.2 秒看起来挺快但如果部署到 CPU 环境就要 1.5 秒以上。相比之下传统的中值滤波在同等尺寸上只要几十毫秒。所以如果你做的是实时性要求很高的场景传统算法的速度优势是压倒性的。4. 实验结果对比与质量评估4.1 客观指标PSNR 和 SSIM任何去噪项目都离不开量化评估。我用两个最常用的指标PSNR峰值信噪比和 SSIM结构相似性。PSNR 看重像素级误差SSIM 更看重亮度、对比度和结构的相似程度两者可以互补。在 MATLAB 里可以调用 psnr 和 ssim 两个内置函数非常方便。我以 Set12 数据集中的一张标准测试图为基准添加 σ25 的高斯白噪声各算法去噪后的指标对比大致如下算法PSNR (dB)SSIM带噪原图20.150.334均值滤波 3x325.310.657中值滤波 3x325.080.633非局部均值 NLM28.440.797CNN3层残差29.210.821可以清楚看到NLM 相比均值和中值有质的提升而我的三层 CNN 在 PSNR 上比 NLM 又高了 0.8 dB 左右SSIM 也更高。这说明哪怕是很浅的深度学习模型只要引入了残差学习对高斯噪声的压制能力就已经能超越经典的非局部方法。4.2 主观视觉效果差异看指标之外还要看图像本身。均值滤波的图最明显的问题是“糊”边缘出现光晕一样的过度纹理细节丢失严重中值滤波在处理高斯噪声时残留下来的颗粒感很明显而且会产生一种不自然的“油画感”NLM 的图看起来最通透细节保真度比前两者好很多但纹理密集的区域会有轻微的水彩状伪影CNN 去噪的整体观感最接近原图边缘锐利、平坦区域干净不过在超高噪声下偶尔会出现“抹平”小细节的情况。有用户问过我为什么不直接以 PSNR 为准来选择算法。我的观点是PSNR 高不代表观感一定好像 NLM 在一些纹理区域出现的伪影可能对 PSNR 影响不大但人眼一看就穿帮。所以我最终的结论是做主观质量评估时一定要把去噪图局部放大来看尤其是高频纹理和边缘区域。4.3 运行效率对比传统算法在速度上的优势在测试中也体现得淋漓尽致。在同一台机器上处理 512x512 灰度图均值滤波和中值滤波都是百毫秒以内完成NLM 的矩阵化实现大概需要 2-3 秒CNN GPU 推理约 0.2 秒CNN CPU 推理约 1.5 秒。如果算上训练时间CNN 的整体成本是传统算法的几百倍。所以实际选型时如果只是做批量离线处理NLM 是性价比之王如果追求极致效果且算力允许CNN 是更好的选择如果做实时嵌入式部署传统的均值或中值滤波仍然不可替代。5. 常见问题、避坑指南与调参心得5.1 我踩过的几个典型报错和坑这个项目里我踩的坑不少挑几个最有代表性的说。第一个是 imfilter 的边界问题。默认情况下 imfilter 用 0 填充边界结果去噪图像的四周会出现一圈黑边PSNR 被拉低。用 replicate 选项可以解决但更隐蔽的是如果你把去噪后的图和原图做差来看残差会发现边界区域的残差明显偏大原因就是边界邻域不完整任何滤波器在边界都表现不好。稳妥的做法是在评估指标时裁掉边界一圈像素。第二个是 medfilt2 不兼容 RGB 图像的问题。给彩色图直接调用 medfilt2 会报错必须逐通道处理。如果你在 for 循环里对 R、G、B 三个通道分别调用 medfilt2每个通道用不同随机种子加噪后再合并还会引入色彩偏移的问题。正确做法是在加噪前先合并通道加噪后再逐通道滤波最后再合并。第三个是 CNN 训练时的显存溢出。我的第一个版本在生成分 Batch 的 patch 时把所有数据都一次性加载到内存结果 32GB 内存的机器直接撑爆。后来改用 minibatch 按需生成的 datastore 方式内存问题就再也没出现过。另外一个坑是 patch 提取时如果随机种子没有固定每次训练结果都会不同对比实验就缺乏可重复性所以我建议设置 rng(42) 这类固定种子。5.2 调参技巧与细节优化NLM 里的 h 参数我前面说了一个经验公式再补充一个细节h 和噪声的方差之间不是线性关系而是近似于 h c·σc 在 0.8 到 1.5 之间浮动。噪声越大c 可以取得稍大一些让权重衰减更平缓避免噪声残留在高权重区域。如果你用固定参数处理不同强度的噪声效果会明显不均匀。CNN 训练方面的一个实用技巧是先用一个低噪声强度σ15的样本快速验证网络能不能收敛。如果连低噪声都学不出来那大概率是网络结构或训练选项的问题等整体流程跑通了再上高噪声训练。我还习惯在训练结束后把网络在训练集和验证集上的 PSNR 差打印出来差值过大就说明过拟合了需要加数据增强或降低模型复杂度。5.3 这个项目还能怎么扩展做完整套对比之后我觉得这个项目的扩展空间还很大。方向上当前只做了高斯噪声可以继续添加椒盐噪声、泊松噪声、甚至混合噪声的处理让传统算法的对比更完整网络结构上可以尝试 DnCNN 的经典结构加入 BatchNorm 层或者转成盲去噪模型一次训练同时处理多个噪声等级数据上可以从灰度扩展到彩色图像不过要注意彩色图像噪声通道的相关性RGB 三通道独立加噪和联合加噪的训练效果完全不同。我个人的建议是如果你接下来要做更高级的方向可以把 NLM 和 CNN 做个结合用 NLM 的结果作为 CNN 的辅助输入帮助网络在训练初期更快收敛。我在实验里试过这种“传统结果作为先验”的思路收敛速度确实有明显提升不过最终 PSNR 提升有限是否值得增加复杂度需要根据实际需求权衡。最后再分享一个大实话很多人一上来就想用 CNN 替代所有传统算法但我做完这个项目后的感悟是传统算法和深度学习并不是替代关系。传统算法在可解释性、速度、小样本场景下的稳定性上仍然有优势CNN 则在效果上限和大数据量下表现更优。真正聪明的方式是理解各自的边界然后在合适的场景里选合适的工具。比如在资源受限的嵌入式设备上我宁可调半天 NLM 参数也不会去部署一个跑不动的 CNN 模型而在效果优先的离线上报任务里CNN 就是首选。这就是这个项目带给我的最大收获。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价