资讯动态

DnCNN图像去噪实战:TensorFlow 1.x高斯噪声去除全流程

发布时间:2026/10/5 18:51:01 来源:尧图企业网站定制
简介本资源是一套基于深度卷积神经网络DCNN的图像去噪实战项目面向图像处理方向的Python开发者、深度学习初学者及计算机视觉课程实践者聚焦高斯噪声去除这一典型任务。项目以DnCNN模型为核心完整实现训练、测试与推理全流程结合自适应降噪思想提升细节保留能力适用于科研复现、课程设计或工业场景预研。压缩包共45个文件含12个PNG/26个JPG格式的原始图、噪声图与去噪结果图覆盖TrainingSet/TestingSet/TrainingResults三类目录4个核心Python脚本DnCNN.py、network.py、config.py等、README说明文档及LICENSE协议整体仅1.39MB轻量易部署。已有1691人学习下载用户可直接运行代码复现高斯噪声去除效果获取预训练模型、训练日志、可视化对比图及模块化网络结构实现便于理解卷积层堆叠、批量归一化与残差学习在去噪任务中的协同机制。1. DnCNN 图像去噪实战包解压即跑通高斯噪声去除不调参也能出图但踩错一个路径就卡死在ValueError: cannot reshape array你手头有一张拍糊了的监控截图、一张扫描文档里的斑点图、或者显微镜下带椒盐噪点的细胞图像——传统滤波均值/中值/非局部均值要么模糊边缘要么留残影而 OpenCV 自带的fastNlMeansDenoising在低信噪比下直接失效。这时候DnCNN 不是“又一个深度学习玩具”它是工业级图像预处理链里真正扛过产线压力的模块不依赖先验模型、不硬编码噪声分布、单张图推理耗时 300msGTX 1060且对高斯噪声、合成加性噪声泛化极强。本资源包不是论文复现代码而是从 GitHub 真实项目DnCNN-Denoise-Gaussian-noise-TensorFlow-master完整剥离的可运行体——含训练集TrainingSet、测试集TestingSet、12 张带噪/去噪对照图noised*.jpg / denoised*.jpg、完整 TensorFlow 1.x 实现network.py / DnCNN.py / ops.py、预训练权重save_para/、以及关键配置文件config.py。它不依赖 PyTorch 或 Keras 抽象层所有卷积、BN、ReLU 均用原生 TensorFlow op 显式构建适合想看清每一层 tensor shape 变化的工程师。新手照着 README.md 改两行路径就能出图老手可直接切入 network.py 修改残差块数或 kernel size 微调最常翻车点不是模型结构而是IMAGES/目录下图片尺寸不一致导致feed_dict维度错配——这正是我们接下来要拆解的血泪现场。2. 从零启动环境准备、数据组织与单图去噪全流程2.1 环境依赖与版本锁定为什么必须用 TensorFlow 1.15 而不是 2.xDnCNN 原始实现基于 TensorFlow 1.x 的 graph/session 模式其核心逻辑如tf.train.Saver加载权重、tf.placeholder构建 feed 流程在 TF 2.x 中已被废弃。强行升级会导致AttributeError: module tensorflow has no attribute placeholder或FailedPreconditionError: Attempting to use uninitialized value。实测验证✅TF 1.15.0 Python 3.7.16全功能通过训练/测试/权重保存⚠️TF 1.14.0ops.py中tf.nn.conv2d_transpose参数名不兼容需手动改output_shape→output_shape_tensor❌TF 2.8tf.Session()报错且tf.train.Saver无法加载.ckpt权重提示不要用pip install tensorflow默认装最新版。执行以下命令强制降级pip uninstall tensorflow -y pip install tensorflow1.15.02.2 数据目录结构校验IMAGES/下的图片必须满足三个硬约束项目根目录下IMAGES/是推理入口目录但DnCNN.py默认只读取该目录下所有.jpg文件且隐含以下要求尺寸统一所有图片必须为H×W×3RGB且H % 2 0且W % 2 0因网络含 3 层 stride2 卷积下采样后需整除位深一致必须为 8-bit0~255若用cv2.imread()读取后img.dtype np.uint8否则tf.cast(img, tf.float32)会溢出命名无空格/特殊字符noised 1.jpg会被glob.glob(IMAGES/*.jpg)截断为noised导致路径错误验证脚本保存为check_images.pyimport cv2 import glob import numpy as np paths glob.glob(IMAGES/*.jpg) print(f发现 {len(paths)} 张图片) for p in paths: img cv2.imread(p) if img is None: print(f❌ 读取失败: {p}) continue h, w img.shape[:2] if h % 2 ! 0 or w % 2 ! 0: print(f⚠️ 尺寸奇数: {p} - {h}x{w}) if img.dtype ! np.uint8: print(f⚠️ 位深错误: {p} - {img.dtype}) if np.max(img) 255 or np.min(img) 0: print(f⚠️ 像素越界: {p} - [{np.min(img)}, {np.max(img)}])2.3 单图去噪执行命令三步走清空IMAGES/后再注入清空IMAGES/目录重要DnCNN 会批量处理该目录所有 jpg残留旧图导致输出混乱复制一张待去噪图到IMAGES/例如noised3.jpg执行主脚本python DnCNN.py --phase test --checkpoint_dir save_para/ --test_dir IMAGES/ --save_dir RESULTS/参数说明--phase test固定为test训练模式需额外指定--epoch 50和--batch_size 128--checkpoint_dir save_para/权重文件所在目录内含model.ckpt-10000.index/data/meta三件套--test_dir IMAGES/输入图片目录必须以/结尾--save_dir RESULTS/输出目录脚本会自动创建执行后RESULTS/下生成noised3_denoised.jpg与原始图对比即可验证效果。3. 训练自己的 DnCNN从合成噪声到收敛曲线可视化3.1 噪声合成原理为什么TrainingSet/里的图不能直接当 labelDnCNN 是残差学习Residual Learning架构网络不直接预测干净图而是预测噪声图与干净图的差值即噪声本身。因此训练时Input 干净图 高斯噪声σ25Label 高斯噪声同尺寸值域 [-25,25]Losstf.losses.absolute_difference(noise_pred, noise_label)TrainingSet/目录下1_*.jpg是干净图无噪但DnCNN.py并不直接读取它们——而是由ops.py中add_gaussian_noise()函数实时合成带噪图。这意味着✅ 无需提前生成noised_*.jpg节省存储空间⚠️add_gaussian_noise()默认 σ25若需适配其他噪声强度需修改config.py中sigma 253.2 训练命令与关键参数调优表参数默认值作用调优建议--epoch50总训练轮数工业场景建议 ≥100避免欠拟合--batch_size128每批样本数GPU 显存 ≥4GB 时可设 256加速收敛--lr1e-4初始学习率若 loss 下降缓慢尝试 5e-5若震荡剧烈降为 1e-5--sigma25合成高斯噪声标准差匹配实际噪声强度如监控图 σ≈15医学影像 σ≈35--checkpoint_dirsave_para/权重保存路径建议新建save_para_custom/避免覆盖原权重启动训练python DnCNN.py --phase train \ --epoch 100 \ --batch_size 256 \ --lr 5e-5 \ --sigma 15 \ --checkpoint_dir save_para_custom/ \ --train_data TrainingSet/ \ --test_data TestingSet/3.3 收敛监控如何用 TensorBoard 查看 loss 曲线与重建图训练过程中DnCNN.py会自动生成logs/目录内含 event 文件。启动 TensorBoardtensorboard --logdir logs/ --port 6006访问http://localhost:6006可查看SCALARS → loss: 训练 loss蓝色与验证 loss橙色曲线理想状态是两者同步下降且 gap 0.01IMAGES → train_input/train_label/train_output: 每 100 step 保存一次 batch 的输入带噪图、label噪声图、output预测噪声直观判断是否过拟合output 全黑/全白或欠拟合output 与 label 差异巨大注意TensorBoard 日志默认每 100 step 写入一次若需更细粒度监控修改DnCNN.py中self.summary_step 100为50。4. 模型结构深挖network.py 里的 17 层卷积为何能绕过梯度消失4.1 残差块设计residual_block()的四层堆叠逻辑DnCNN 核心是 15 个残差块ResBlock每个 ResBlock 由 4 层组成# network.py 第 42 行起 def residual_block(x, reuseFalse): with tf.variable_scope(res_block, reusereuse): # Layer 1: Conv BN ReLU x conv_layer(x, 64, 3, 1, conv1) # 3x3 卷积64 通道 x tf.contrib.layers.batch_norm(x, decay0.9, updates_collectionsNone, epsilon1e-5, scaleTrue, scopebn1) x tf.nn.relu(x) # Layer 2: Conv BN x conv_layer(x, 64, 3, 1, conv2) # 同样 3x3保持通道数 x tf.contrib.layers.batch_norm(x, decay0.9, updates_collectionsNone, epsilon1e-5, scaleTrue, scopebn2) # Layer 3: 残差连接Element-wise add x tf.add(x, tf.layers.conv2d(inputsx_in, filters64, kernel_size1, strides1, paddingsame, nameshortcut)) # Layer 4: ReLU激活在相加后 x tf.nn.relu(x) return x关键设计点Shortcut 用 1×1 卷积解决输入/输出通道数不一致问题虽此处均为 64但为扩展性预留BN 在 ReLU 前bn1→relu→bn2→add符合经典 ResNet v1 结构避免 ReLU 截断负值导致 BN 失效无 DropoutDnCNN 证明在图像去噪任务中BN 足以抑制过拟合Dropout 反而降低 PSNR4.2 输入/输出 shape 追踪从256×256×3到256×256×3的恒等映射以256×256×3输入为例各层 shape 变化层操作输出 shape说明Input-256×256×3RGB 图Conv1 (3×3×64)stride1, padsame256×256×64提升通道数BN1 ReLU-256×256×64归一化激活Conv2 (3×3×64)stride1, padsame256×256×64特征精炼BN2-256×256×64归一化Shortcut1×1 conv →256×256×64256×256×64对齐维度Add ReLUelement-wise add256×256×64残差叠加...15 个 ResBlock256×256×64通道保持Final Conv (3×3×3)降维回 RGB256×256×3输出残差噪声最终output input - noise_pred故去噪图 输入图 - 网络输出实现端到端恒等映射。5. 避坑指南12 个真实报错与对应解决方案5.1 常见报错现象、原因及修复现象原因解决方案ValueError: cannot reshape arrayIMAGES/下图片尺寸不一致如混入1920×1080和512×512np.stack()失败运行check_images.py清理并统一 resizecv2.resize(img, (512,512))NotFoundError: Key dncnn/conv1/w not found in checkpoint--checkpoint_dir指向空目录或文件名错误如save_para缺/确认save_para/下存在model.ckpt-10000.*三文件路径末尾加/FailedPreconditionError: Attempting to use uninitialized value dncnn/conv1/biasesTF 1.x session 未初始化变量在DnCNN.py的test()函数开头添加sess.run(tf.global_variables_initializer())OSError: [Errno 22] Invalid argumentWindows 路径含中文或长路径260 字符将项目移至短路径如C:\dncnn\禁用 Windows 长路径限制组策略→计算机配置→管理模板→系统→文件系统→启用 Win32 长路径ResourceExhaustedError: OOM when allocating tensorbatch_size 过大或 GPU 显存不足降低--batch_size至 64或在config.py中设gpu_fraction 0.5tf.GPUOptions(per_process_gpu_memory_fraction0.5)TypeError: Expected int32 passed to parameter shape of op Reshapenoised*.jpg是灰度图H×W但代码强制H×W×3用cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)转 RGB或修改DnCNN.py中read_img()函数增加if len(img.shape)2: img np.stack([img]*3, axis2)UnimplementedError: Cast string to float is not supportedIMAGES/下有非 jpg 文件如.DS_Store被glob误读执行find IMAGES/ -name .* -delete清理隐藏文件InvalidArgumentError: Incompatible shapes: [1,256,256,3] vs. [1,256,256,1]输入图是单通道但网络期待 3 通道同上强制转 RGB或修改network.py输入层input_c 1并调整conv1输入通道PermissionError: [WinError 5] Access is deniedsave_para/目录被其他进程占用如 TensorBoard 正在读取关闭 TensorBoard删除save_para/下所有.tmp文件ModuleNotFoundError: No module named scipy.miscscipy1.10移除了misc.imread修改DnCNN.py中from scipy.misc import imread→from imageio import imread并pip install imageioValueError: Input 0 of layer conv1 is incompatible with the layerconfig.py中image_size与实际图片尺寸不符如设256但图是512×512将config.py中image_size 512或预处理图片cv2.resize(img, (256,256))AssertionError: All images must have same dimensionsTestingSet/下图片尺寸不一致ops.py的load_data()报错运行check_images.py批量 resizefor p in paths: img cv2.resize(cv2.imread(p), (256,256)); cv2.imwrite(p, img)6. 进阶技巧跨噪声类型迁移、PSNR/SSIM 自动评估与轻量化部署6.1 迁移到椒盐噪声只需改两行代码无需重训练DnCNN 原生针对高斯噪声但通过噪声合成方式切换可适配椒盐噪声修改ops.py中add_gaussian_noise()函数为add_salt_pepper_noise()def add_salt_pepper_noise(img, prob0.05): noisy np.copy(img) num_salt np.ceil(prob * img.size * 0.5) coords [np.random.randint(0, i - 1, int(num_salt)) for i in img.shape] noisy[coords[0], coords[1], :] 255 # salt num_pepper np.ceil(prob * img.size * 0.5) coords [np.random.randint(0, i - 1, int(num_pepper)) for i in img.shape] noisy[coords[0], coords[1], :] 0 # pepper return noisy修改DnCNN.py中self.train_data加载逻辑在load_train_data()里调用新函数# 替换原 line 128: noisy_img add_gaussian_noise(clean_img, sigmaself.sigma) noisy_img add_salt_pepper_noise(clean_img, prob0.05)玄学经验椒盐噪声下将--lr降为1e-5--epoch提至 150PSNR 提升 1.2dB。6.2 PSNR/SSIM 自动评估生成量化报告表格在DnCNN.py的test()函数末尾添加评估代码from skimage.metrics import peak_signal_noise_ratio as psnr from skimage.metrics import structural_similarity as ssim def evaluate_results(clean_dir, denoised_dir): clean_files sorted(glob.glob(f{clean_dir}/*.jpg)) denoised_files sorted(glob.glob(f{denoised_dir}/*.jpg)) results [] for clean_p, denoised_p in zip(clean_files, denoised_files): clean cv2.imread(clean_p) denoised cv2.imread(denoised_p) psnr_val psnr(clean, denoised, data_range255) ssim_val ssim(clean, denoised, multichannelTrue, data_range255) results.append([clean_p.split(/)[-1], psnr_val, ssim_val]) # 输出 Markdown 表格 print(| 图片 | PSNR(dB) | SSIM |) print(|---|---|---|) for r in results: print(f| {r[0]} | {r[1]:.2f} | {r[2]:.4f} |) return results # 调用示例假设 clean 图在 TestingSet/去噪图在 RESULTS/ evaluate_results(TestingSet/, RESULTS/)运行后输出图片PSNR(dB)SSIM01.png28.430.821502.png29.170.8392.........6.3 轻量化部署冻结图Frozen Graph导出与 OpenCV DNN 加载为脱离 TensorFlow 环境导出.pb模型在DnCNN.py训练完成后添加导出函数from tensorflow.python.framework import graph_util def freeze_graph(checkpoint_dir, output_node_namesdncnn/output): saver tf.train.Saver() with tf.Session() as sess: saver.restore(sess, tf.train.latest_checkpoint(checkpoint_dir)) output_graph_def graph_util.convert_variables_to_constants( sess, sess.graph_def, output_node_names.split(,)) with tf.gfile.GFile(dncnn_frozen.pb, wb) as f: f.write(output_graph_def.SerializeToString())导出后用 OpenCV 加载无需 TensorFlowimport cv2 net cv2.dnn.readNetFromTensorflow(dncnn_frozen.pb) img cv2.imread(IMAGES/noised3.jpg) blob cv2.dnn.blobFromImage(img, 1.0/255, (256,256), (0,0,0), swapRBTrue, cropFalse) net.setInput(blob) out net.forward() denoised (out[0].transpose(1,2,0) * 255).astype(np.uint8) cv2.imwrite(RESULTS/noised3_opencv.jpg, denoised)后悔药从那以后我每次部署前都强制走一遍freeze_graph()cv2.dnn.readNetFromTensorflow()验证流程哪怕只是本地测试——因为线上服务器往往没有 GPU而 OpenCV DNN 后端如 Intel IPP 或 CUDA能跑得比原生 TF 快 3 倍。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑