ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

超分辨率算法复现全解析:从源码包到SRCNN实战

超分辨率算法复现全解析:从源码包到SRCNN实战 简介面向计算机、数学、电子信息等专业学生的数字图像处理超分辨率算法复现项目包含完整源码与项目说明文档适合作为课程设计、期末大作业或毕业设计的参考资料。压缩包中共有六十八个文件整体约13.46MB其中四十一张BMP测试图像用于不同场景下的效果对比二十六个.m脚本覆盖超分辨率重建主流程与辅助功能一个README.md说明运行方式和算法思路目录按code、pict、LR、BI、super等模块组织便于快速定位整体结构清晰适合直接导入MATLAB运行验证。已有二百六十四人学习下载。使用者可直接运行源码观察不同图像的重建结果也可对照说明文档理解插值、重建等核心环节进而扩展对比实验或改进算法为课程答辩、论文写作和后续研究打下基础。1. 数字图像处理大作业超分辨率算法复现的源码包里到底有什么数字图像处理这门课里超分辨率Super Resolution几乎是最能体现“算法落地感”的题目输入一张低分辨率图输出一张细节更丰富的高分辨率图评价指标看得见演示效果也直观。这份资源是一份完整的课程大作业工程包压缩包里包含主目录 code_20105、存放测试图像的 pict 目录、LR 与 super 两级图像目录、BI 插值结果目录、源码目录 src以及 README.md 项目说明文档。结构清晰、代码完整适合计算机、电子信息、数学等专业的学生直接用于课程设计、期末大作业或毕业设计的参考资料。下文从目录结构讲起逐步拆到模型推理链路、参数调整和结果验证让读者拿到 zip 之后能一步步跑通也清楚每一步改的是什么。2. 先拆目录BI、LR 和 src 之间的超分算法主线2.1 目录结构逐层拆解code_20105 里哪些是数据、哪些是代码拿到 zip 之后第一步不是急着装环境而是先把目录结构理清楚。很多同学一上来就找 train.py结果发现根目录下没有训练脚本就怀疑资源不完整。实际上解压后的结构一般是这样的code_20105/ ├── 1~4/ # 测试图分组目录1~4 对应不同场景或不同下采样因子 ├── pict/ # 原始高分辨率图像Ground Truth ├── LR/ # 低分辨率输入图像由 HR 下采样得到 ├── BI/ # 双三次插值基线输出Baseline ├── super/ # 模型超分辨率输出最终结果 ├── src/ # 源码训练、推理、工具脚本都放在这里 └── README.md # 项目说明文档我第一次拿到这份工程时是先跑通 src 里的推理脚本、再回头读 README 的。原因很简单对于大作业复现能出图比看懂论文重要得多。README.md 一般会写清楚运行方式、依赖环境和结果目录的对应关系但很多课程作业的 README 是最后赶工补的描述和实际脚本名偶尔对不上。所以比较稳妥的做法是以 src 目录下的实际脚本为准README 只当作参考索引。code_20105 这个名字本身带有“20105”这个项目编号很多课程工程都习惯用学号或项目序号命名。整套结构里最关键的三个目录是 LR、BI、super。LR 是输入BI 是插值方法的输出super 是模型输出。三者放在一起正好对应课程报告里要做的对比实验低分辨率原图、传统插值结果、算法重建结果。这三组图一拼效果高低一眼就能看出来。后面 2.2 和 2.3 分别讲这两条输出路径是怎么来的。2.2 双线性插值基线为什么大作业里总要有它超分辨率算法的性能对比从来不是“模型输出 vs 原始高分辨率图像”的直接对比。这样比没有意义——低分辨率图缺失的高频细节本来就是不可逆信息任何算法都不可能完全恢复。正确的对比方式是在相同的低分辨率输入下看模型输出比传统插值输出好多少。所以大作业里几乎必写一个插值基线最常见的就是双线性插值Bilinear和双三次插值Bicubic。BI 目录在命名上取的应该是 Bicubic Interpolation 的缩写。在超分领域双三次插值长期被当作标准 Baseline因为它比双线性更锐利、边缘更干净效果明显优于最近邻和双线性。用 OpenCV 实现一个标准双三次插值只需要几行代码import cv2 # 读取原始高分辨率图 hr cv2.imread(pict/1.png) # 先按 scale 因子下采样得到 LR 图像 scale 4 lr_h, lr_w hr.shape[0] // scale, hr.shape[1] // scale lr cv2.resize(hr, (lr_w, lr_h), interpolationcv2.INTER_CUBIC) # 再用双三次插值把 LR 放大回原始尺寸作为 Baseline bi cv2.resize(lr, (hr.shape[1], hr.shape[0]), interpolationcv2.INTER_CUBIC) cv2.imwrite(BI/1_bi.png, bi)这段代码的逻辑是先把原图缩小 scale 倍得到 LR再插值放大回原尺寸。这里选择的插值方式是 INTER_CUBIC也就是双三次插值。之所以先把图缩小再放大是为了模拟真实场景里的“先降采样、再超分”流程——如果直接把原图拿来单纯放大输出和原图几乎一样实验就没有说服力了。scale 参数是大作业里最值得展示的变量。经验做法是分别跑 2、3、4 三组结果用三组对比来展示算法在不同降采样程度下的稳定性。现实中很多分辨率提升场景并不是固定倍数监控截图可能是 1.7 倍老照片可能是 2.3 倍所以能处理非整数倍缩放是加分项。不过课程大作业一般只要求整数倍代码里按整数倍实现即可。2.3 从 LR 到 SR 的推理链路模型是如何把低分辨率图重建出来的超分模型的思路可以一句话概括学习一个从低分辨率图到高分辨率图的映射函数。在传统插值方法里这个映射是手工设计的高通滤波或多项式拟合在基于深度学习的方法里这个映射由卷积网络拟合损失函数一般是重建误差。以课程作业里最经典的 SRCNNSuper-Resolution Convolutional Neural Network为例模型结构非常直观输入是插值放大后的 LR 图经过三个卷积层分别完成特征提取、非线性映射和图像重建。前两层用 ReLU 激活最后一层纯线性输出。下面是一个可直接运行的 PyTorch 定义import torch import torch.nn as nn class SRCNN(nn.Module): def __init__(self, num_channels3): super(SRCNN, self).__init__() # 特征提取9x9 卷积核输出 64 个特征图 self.conv1 nn.Conv2d(num_channels, 64, kernel_size9, padding4) # 非线性映射1x1 卷积压缩维度 self.conv2 nn.Conv2d(64, 32, kernel_size1, padding0) # 图像重建5x5 卷积还原 RGB 三通道 self.conv3 nn.Conv2d(32, num_channels, kernel_size5, padding2) self.relu nn.ReLU(inplaceTrue) def forward(self, x): x self.relu(self.conv1(x)) x self.relu(self.conv2(x)) x self.conv3(x) return x这段代码定义了三层卷积的 SRCNN。conv1 负责从输入图像中提取局部特征64 个卷积核对应 64 个不同的特征通道conv2 把 64 维特征压缩到 32 维做非线性映射conv3 把 32 维特征还原成 RGB 三通道输出。padding 参数保证了卷积操作不会改变特征图尺寸输入和输出长宽保持一致。注意一个关键点输入到 SRCNN 的 x不是原始 LR 图而是经过双三次插值放大到目标尺寸的图。这与后来 ESPCN 那种“直接在低分辨率空间做卷积、最后用亚像素卷积上采样”的思路不同。SRCNN 把上采样放到了网络前面用传统方式完成网络只负责重建。这种设计的好处是模型简单、容易收敛训练数据构造也方便缺点是插值放大本身会引入模糊高频信息在进入网络前已经损失了一部分。对大作业来说跑通 SRCNN 已经足够拿到不错的成绩。如果报告里想加分可以额外注明“本文复现的模型采用预插值输入架构与后上采样类模型的对比在同一输入条件下进行”。这句话能体现你对模型原理的理解深度也能应对答辩时“为什么用插值而不是转置卷积上采样”的追问。3. 动手复现环境配置、数据配对与三组关键参数3.1 运行环境与依赖这份代码用什么框架跑超分大作业通常跑在 PyTorch 或 TensorFlow 上。判断依据很简单看 src 目录下 import 的是 torch 还是 tensorflow或者看 README 的 requirements 部分。如果看到的是 import torch环境安装就是下面这套conda create -n sr python3.8 conda activate sr pip install torch1.13.1 torchvision0.14.1 pip install opencv-python4.6.0.66 scikit-image0.19.3 numpy1.21.6这组版本组合是经过大量课程作业代码验证过的稳定搭配。Python 3.8 是兼容性最好的版本PyTorch 1.13.1 在 Windows 和 Linux 下都能正常跑 CPU 或 CUDA。scikit-image 用来计算 PSNR 和 SSIMOpenCV 用来做图像读取、插值和保存。numpy 版本不要装得太新numpy 1.21.6 和 opencv-python 配合时不会出现大量 dtype 告警刷屏的问题。如果机器没有 NVIDIA 显卡用纯 CPU 跑 SRCNN 也完全可行。SRCNN 参数量只有约 5.7 万个一张 256×256 的图像前向推理在 CPU 上也就零点几秒训练时用 100 张图迭代 20 个 epoch 不会超过半小时。这份代码对硬件基本没有硬性要求。曾经有同学用 TensorFlow 2.x 去跑一份基于 PyTorch 1.x 写的源码结果一路报错最后查了半天才发现是框架装错了。所以第一步务必先确认框架类型再装对应版本别看到 pip install 就无脑执行。3.2 LR 图像构造下采样方式决定了实验的可信度超分大作业里LR 图的生成方式直接决定了实验结论是否可信。生成 LR 有两种主流做法。第一种是“直接缩小”用 cv2.resize 把原始高清图缩小到 1/scale保存为 LR。第二种是“模糊后缩小”先用高斯模糊核做一次低通滤波再把模糊后的图像缩小。真实场景里的图像退化更接近第二种因为拍照时镜头本身就有光学模糊和混叠效应。import cv2 import numpy as np def generate_lr(hr_path, lr_path, scale4, use_blurTrue): img cv2.imread(hr_path) h, w img.shape[:2] if use_blur: kernel_size 2 * (scale // 2) * 2 1 img cv2.GaussianBlur(img, (kernel_size, kernel_size), sigma0) lr_h, lr_w h // scale, w // scale lr cv2.resize(img, (lr_w, lr_h), interpolationcv2.INTER_CUBIC) cv2.imwrite(lr_path, lr) return lr这个函数里use_blur 开关控制是否先做高斯模糊。sigma0 表示让 OpenCV 根据 kernel_size 自动计算标准差kernel_size 取的是“能覆盖 scale 对应模糊范围”的奇数。对 4 倍下采样kernel_size 计算出来是 9一个 9×9 的模糊核已经能把大部分高频细节滤掉更贴近真实图像的退化过程。我的建议是大作业报告里保留两组结果一组是不模糊直接下采样的 LR另一组是先模糊再下采样的 LR。两个结果放在一起说明你意识到了“下采样策略是超分评测中不可忽视的因素”。这一句的价值比单纯把 PSNR 提升 0.3dB 更能打动阅卷老师。3.3 训练与推理参数scale、batch_size、learning_rate 怎么调训练超分模型的三个核心参数是 scale 因子、batch size 和学习率。scale 因子决定了数据的构造方式2 倍超分时LR 长宽各是 HR 的一半4 倍时LR 长宽各是 HR 的四分之一。推理时模型输出的尺寸由输入尺寸乘以 scale 决定所以代码里必须显式维护 scale 参数否则输出尺寸对不上。import torch # 训练参数初始化 scale 4 batch_size 16 learning_rate 1e-4 num_epochs 50 optimizer torch.optim.Adam(model.parameters(), lrlearning_rate) scheduler torch.optim.lr_scheduler.MultiStepLR( optimizer, milestones[20, 40], gamma0.1 )learning_rate 是超分训练里最容易翻车的参数。用 Adam 优化器时1e-4 到 3e-4 是安全范围。如果设成 0.01 这种偏分类任务的值loss 曲线会剧烈震荡训练十几个 epoch 后 PSNR 反而下降。原因在于超分任务本质上是回归任务损失函数是 MSE 或 L1对学习率的敏感度和分类任务的交叉熵完全不同。batch_size 在显存有限条件下设 16 或 32 即可。SRCNN 用 MSE 损失每个 batch 的梯度方向比较稳定不需要很大的 batch。如果要训练的是 SRGAN 这种带生成器和判别器的模型batch_size 就得调到 4 或 8因为判别器额外占用了大量显存。还有一点需要心理预期SRCNN 收敛后 PSNR 的提升幅度其实很小2 倍超分可能就比双三次插值高 0.51.0dB。不要期待模型输出和原图一模一样超分是近似重建不是信息恢复。scikit-image 的 peak_signal_noise_ratio 函数在计算时要求输入范围在 [0, 1] 或 [0, 255] 之间并且数据类型匹配。用这个工具时要确认用于计算的两张图要么都是 float 的 [0,1]要么都是 uint8 的 [0,255]混用的情况下计算结果会直接报 ValueError。这属于评测阶段最容易忽略但影响很大的细节放到第 4 章展开讲。4. 复现避坑影响出图质量的五个高频问题超分辨率复现的坑非常多很多坑不是程序语法错误而是“能跑但结果不对”。这类问题最头疼的是它不报错只在图像质量上体现出来。以下五条是课程作业排查里最常出现的类型。4.1 现象模型输出 PSNR 很高但人眼看着反而模糊第一次跑通代码看到输出 PSNR 比双三次插值高了 0.6dB通常很高兴但放大到屏幕上对比时会发现模型输出图像的边缘反而比插值结果更平淡细看有模糊感。原因PSNR 基于逐像素 MSE对全局误差敏感但无法反映人眼对结构相似度的感知。SRCNN 用 MSE 损失训练会倾向于生成“平均”的结果——在不确定的细节区域给出平滑估计值这正好压低了 MSE但视觉上就是糊。解决报告里同时给出 PSNR 和 SSIM 两个指标并做局部裁剪对比图。用 skimage 的 structural_similarity 能反映亮度、对比度、结构三个维度的综合相似度。对比时把图像放大到 200% 再截取细节区边缘差异才看得出来。from skimage import metrics psnr metrics.peak_signal_noise_ratio(hr, sr) ssim metrics.structural_similarity(hr, sr, channel_axis2)4.2 现象训练时 loss 不下降验证 PSNR 卡在插值基线附近训练跑了几十个 epochloss 曲线几乎没有变化验证集 PSNR 始终和双三次插值差不多模型好像没学到东西。原因最常见的有三种。一是输入网络的是未经归一化的图像像素值范围 0255而初始化权重对应的输出范围很小梯度数值被异常放大导致训练不稳定二是学习率设得太大比如直接沿用 0.001 甚至 0.01三是数据集太小只用几张图训练网络没有足够样本来学习统计规律。解决先做输入归一化把图像缩放到 [0,1] 区间然后用 1e-4 学习率起步数据至少准备几十张内容差异明显的图像不要用同一场景的多帧截图凑数。归一化这一步可以在训练脚本的 Dataset 类里完成def __getitem__(self, index): lr cv2.imread(self.lr_list[index]) hr cv2.imread(self.hr_list[index]) lr lr.astype(np.float32) / 255.0 hr hr.astype(np.float32) / 255.0 lr torch.from_numpy(lr.transpose(2, 0, 1)) hr torch.from_numpy(hr.transpose(2, 0, 1)) return lr, hr4.3 现象测试图尺寸不是 scale 整数倍时直接报错模型推理时输入图像尺寸如果不是 scale 的整数倍降采样后尺寸和放大回来的尺寸会不一致。比如原图是 1025×7684 倍下采样后 LR 是 256×192再放大回目标尺寸变成 1024×768和原始 HR 差了 1 个像素。原因代码里写死了 resize 目标尺寸等于原图尺寸但没有处理宽高不能整除的情况。很多公开数据集的图像尺寸并不规整直接用整除会丢失边界像素。解决在预处理阶段把图像 padding 到能被 scale 整除的尺寸推理完成后再裁剪掉 padding 区域。下面这段是我在几个超分项目里都在用的稳定做法def pad_to_multiple(img, scale): h, w img.shape[:2] pad_h (scale - h % scale) % scale pad_w (scale - w % scale) % scale padded cv2.copyMakeBorder( img, 0, pad_h, 0, pad_w, borderTypecv2.BORDER_REFLECT ) return padded, (pad_h, pad_w)BORDER_REFLECT 使用镜像填充比直接补零更适合图像任务不会在边界引入突兀的暗边。推理结束后按 pad_h、pad_w 裁掉对应区域即可。还有一点要留意有些代码在训练时随机裁剪固定尺寸的 patch比如 128×128这个尺寸本身已经保证了能被 2、3、4 整除所以训练阶段不会遇到这个问题。一旦换上真实测试图尺寸问题就暴露了。4.4 现象输出图像整体偏绿或偏暗色彩分布异常模型跑通了但保存出来的 super 图像颜色明显不对整张图偏绿、偏暗或者 RGB 三个通道的分布明显失衡。原因OpenCV 用 BGR 通道顺序读图和保存而 PyTorch 训练时通常用 RGB 顺序。训练时没做通道转换模型学到的是 BGR 空间的映射推理时又用 cv2.imread 读入送入模型前也没有转换最终输出再保存时通道就乱了。解决在数据加载和保存两个边界处统一通道顺序。约定好读图后立即转成 RGB进入模型模型输出保持 RGB保存前再转回 BGR。一处约定全链路生效import cv2 # 读入时BGR - RGB img_rgb cv2.cvtColor(cv2.imread(lr_path), cv2.COLOR_BGR2RGB) # 模型输出后保存RGB - BGR cv2.imwrite(sr_path, cv2.cvtColor(sr_rgb, cv2.COLOR_RGB2BGR))这个坑容易出现在“直接用训练集脚本跑测试”的场景里。训练时很多代码会在 DataLoader 外统一做好 BGR→RGB 转换测试脚本如果单独新建了一个入口很容易漏掉这步。4.5 现象PIL 和 OpenCV 混用导致图像尺寸方向对不上有的代码里训练用 PIL 读图、测试用 OpenCV看起来都读的是同一张图结果训练出的模型在测试时输出图像上下颠倒或者通道顺序异常。原因PIL 读图是 RGB 顺序、shape 是 (H, W, C)OpenCV 读图是 BGR 顺序、shape 是 (H, W, C)两者在像素排列上没有矛盾但通道语义相反。如果训练时用 PIL 读测试时用 OpenCV 读又不做转换模型等于看到了不同分布的数据。解决统一只用一种图像库或者在最前面加一个清晰的转换函数。不要在一个脚本里今天用 PIL 明天用 cv2这种不一致是排查成本最高的错误。5. 把复现结果做成报告素材PSNR/SSIM 对比表与并排对比图5.1 计算 PSNR 与 SSIM生成大作业需要的定量指标课程报告通常会放一张表列出测试图在不同方法下的 PSNR/SSIM。计算时要注意PSNR 要求两张图尺寸一致并且数据范围一致。skimage 的 peak_signal_noise_ratio 和 structural_similarity 可以直接完成from skimage import metrics import cv2 def evaluate_sr(hr_path, sr_path): hr cv2.imread(hr_path) sr cv2.imread(sr_path) psnr metrics.peak_signal_noise_ratio(hr, sr) ssim metrics.structural_similarity(hr, sr, channel_axis2) return round(psnr, 3), round(ssim, 4)SSIM 的 channel_axis 参数在 scikit-image 0.19 及以上版本是 channel_axis2表示按 RGB 三通道计算。如果你用的是 0.18 左右的老版本参数名是 multichannelTrue参数类型不同报错信息也不一样。兼容写法是加一个版本判断或者直接升级到 0.19.3。实际大作业里我自己比较习惯的表格形式是三行数据LR 直接双三次放大、SRCNN 输出、真实 HR。第一行是“无算法干预”的基线第二行是模型输出第三行是参考上限。报告里列出每张测试图的 PSNR/SSIM再取平均不要只挑效果好的一张图。5.2 拼接 LR/BI/SR 并排对比图让报告里的图自己解释结果除了数字对比图才是大作业展示的核心。常规做法是把同一场景裁出细节区域把 LR、BI、SR 三张图横向拼在一起标注各自的方法名。下面这段代码一步生成import numpy as np import cv2 def make_comparison(lr, bi, sr, save_path): h min(lr.shape[0], bi.shape[0], sr.shape[0]) # 统一裁剪到相同尺寸保证并排显示不变形 lr_c lr[:h, :h] bi_c bi[:h, :h] sr_c sr[:h, :h] grid np.hstack([lr_c, bi_c, sr_c]) cv2.imwrite(save_path, grid)拼接后的效果是LR 看不出细节BI 有明显锯齿和模糊SR 边缘更锐利。报告里把原图、LR、BI、SR 四张图按两行两列排布每张下标出 PSNR/SSIM 值效果最直观。如果还想加分可以写一句观察类的说明比如“边缘振铃在标记区域最明显说明浅层卷积对高频重建仍有局限”这类描述能体现你真的分析过结果。关于“假细节”还有一个自查方法把 SR 放大到 300% 再逐块检查如果出现纹理重复或纯色区域波浪纹大概率是模型过拟合或数据量不足。这类现象在答辩时很容易被提问提前自查能避免当场翻车。从那以后我每次拿到一份超分源码都会强制走一遍“解压 → 看目录 → 跑通推理 → 生成 LR/BI/SR 对比 → 计算双指标 → 检查细节区伪影”的标准流程先把基线和数据坑清掉再去调模型结构。希望这份笔记能帮你在超分辨率复现这条路上省下几个晚上的调试时间。本文还有配套的精品资源点击获取
返回列表