
简介这是一套基于深度学习的老照片修复项目工程包面向具备Python基础、希望入门或进阶计算机视觉的开发者。整体共81个文件包含54个Python脚本覆盖数据预处理、模型训练、测试及人脸检测对齐等完整链路17张图片用于新旧对比与流程示意4份PDF文档和1份演示视频可帮助快速理解项目方案与效果压缩包约50.71MB。目录按data、models、options、util等模块划分结构清晰便于按需提取训练脚本与工具函数。目前已有350人学习下载。读者可通过源码和文档了解CNN、GAN等模型在划痕、污损老照片修复中的应用也可借助演示视频与README快速复现推理流程适合课程设计、毕业课题或AI图像修复实践。1. 老照片修复项目先搞清楚你下载的这个 zip 里到底装了什么你手里应该是一个几百 MB 到几个 GB 不等的 zip 压缩包标题写着「老照片修复项目是通过深度学习的方法修复严重退化的老照片」。解压之前先想清楚一件事——你要处理的不是普通去噪而是修复「严重退化」。划痕、霉斑、大块噪点、褪色、细节丢失这些退化叠在一起传统 OpenCV 那套「去噪 对比度拉伸」基本没用。深度学习模型能做这件事靠的是从大量配对数据里学会「干净照片 → 退化照片」的逆向映射。这个标题真正指向的思路是用 Python 搭一个基于生成对抗网络GAN或扩散模型的老照片修复管线输入一张布满折痕和噪点的扫描件输出一张细节可信、颜色自然的数字照片。适合两类人——手里有大量真实老照片需要批量修复的从业者以及刚学完 PyTorch 想找一个完整实战项目练手的深度学习新人。前者关心能不能出活后者关心管线的每一步怎么拆。本文就按这个思路从解压 zip 到跑通推理、调参数、避坑、微调一条线讲完。2. 从 zip 到能跑的 Python 环境解压、目录检查和依赖安装老照片修复项目这类深度学习代码包拿到手之后最怕的不是代码看不懂而是环境装不上。先别急着双击运行什么 train.py按顺序做三件事解压、看目录结构、装依赖。这三步走稳后面所有问题都好排查。2.1 解压 zip 的三种方式与目录结构识别不管你是 Windows 还是 Linux解压一个深度学习项目压缩包都有讲究。Windows 上右键「全部解压缩」最省事但如果你习惯用命令行Linux 下的 unzip 命令要记住几个参数unzip old_photo_repair.zip -d old_photo_repair cd old_photo_repair ls -la-d指定解压目标目录避免把所有文件直接洒在当前文件夹里。解压完成后先别急逐个看目录。老照片修复项目沿用的是学术界比较统一的组织方式old_photo_repair/ ├── checkpoints/ # 预训练权重存放处有些项目用 weights/ 或 pretrained/ ├── data/ # 训练数据或测试图片 ├── scripts/ # 训练和推理脚本 ├── models/ # 网络结构定义 ├── requirements.txt # Python 依赖清单 └── README.md # 项目说明一定要读我见过不少翻车现场都是因为跳过了 README 就直接跑。这个文件里通常会写明权重文件的下载地址、Python 版本要求、CUDA 版本要求。如果 zip 里没有 README那你至少得确认 requirements.txt 里的依赖列表能不能在当前 Python 版本下安装。2.2 用 conda 建独立环境别污染你的主环境老照片修复项目依赖的 PyTorch、torchvision、opencv-python 版本不是随意定的。直接用 pip 装到系统 Python 里大概率会跟其他项目冲突。我一般习惯用 conda 建一个独立环境这也是深度学习环境配置里最稳妥的做法conda create -n photo_repair python3.8 conda activate photo_repair pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117Python 版本不要一上来就选最新的很多老项目是在 Python 3.7/3.8 下写的用的第三方库在 3.10 以上可能已经不做兼容。PyTorch 的安装要特别注意 CUDA 版本上面命令里的cu117表示 CUDA 11.7。先运行nvidia-smi查看你机器驱动支持的 CUDA 版本再选对应的 PyTorch 轮子包。如果你没有 NVIDIA 显卡把--index-url去掉装 CPU 版也能跑推理只是速度慢很多。依赖安装用 requirements.txt 批量装pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple这里用的是清华镜像源加速下载实测比默认源快好几倍。装完后先验证关键包能不能正常导入发现缺了就补而不是等到跑脚本时才报错。2.3 快速验证环境一张纯色图就跑通模型加载环境装没装好不要用 python 交互式一行一行敲直接写个小脚本验证 GPU 可用性和模型能否加载# verify_env.py import torch import torchvision print(PyTorch 版本:, torch.__version__) print(CUDA 可用:, torch.cuda.is_available()) print(GPU 名称:, torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU) from models import get_repair_model model get_repair_model() # 按项目实际 API 调整 print(模型参数量: {:.2f}M.format(sum(p.numel() for p in model.parameters()) / 1e6))CUDA 可用这一项如果输出 False后面一切推理都会慢到怀疑人生。参数量输出能帮你判断模型有没有正确加载一般在 50M 到 200M 之间太小的说明权重没加载进去。到这里环境就绪可以进入下一步了。3. 先跑通最小推理预训练权重、测试图像和第一张修复结果环境装好只是万里长征第一步。老照片修复项目能不能出图关键在预训练权重。这一步的坑最多也最容易被忽略。3.1 预训练权重zip 里通常没有你要单独下载大多数深度学习项目仓库不会把训练好的权重直接塞进 zip因为动辄几百 MB。zip 里一般只有一个 checkpoints 目录和一个包含下载链接或 md5 校验值的说明文件。你先检查checkpoints/目录下有没有.pth或.pt后缀的文件如果没有就去 README 里找下载地址。权重文件下载完先校验 md5 再做放置md5sum checkpoints/old_photo_repair.pth mkdir -p checkpoints mv ~/Downloads/old_photo_repair.pth checkpoints/我习惯的做法是从不跳过 md5 校验尤其是用网盘或第三方镜像下载的权重损坏概率比想象中高。放错位置的话训练脚本会报「找不到权重文件」推理脚本则有可能静默用随机初始化权重运行——出来的图当然全是噪声你还以为是模型不行。3.2 最小推理命令与脚本解析跑通推理的完整命令通常长这样python test.py \ --checkpoint ./checkpoints/old_photo_repair.pth \ --input ./data/test/old_photo.jpg \ --output ./results/ \ --device cuda:0--checkpoint指定权重路径--input是待修复图片路径--output是结果保存目录--device决定用 GPU 还是 CPU。有些项目还支持--with_scratch参数表示是否启用划痕检测模块——严重退化的老照片建议保持开启后面我会专门讲这个参数。第一次跑通别用太复杂的图。找一张只有轻度噪点和褪色的照片试水把模型推理全流程先走完。输出一张结果后用肉眼对比原图看看有没有以下现象整体变干净了还是出现了不该有的纹理。如果输出一片黑或一片白多半是输入图像预处理出了问题八成是图像归一化或数据类型转换的 bug往这个方向排查。3.3 推理脚本内部到底做了什么如果你打算把老照片修复项目接入自己的业务就不能只当一个黑匣子调用。看一遍推理脚本的主流程你会发现它无非在做这几件事# test.py 核心流程摘要 import cv2 import torch from torchvision import transforms # 1. 读取图片并做尺寸对齐 img cv2.imread(args.input) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) H, W img.shape[:2] img cv2.resize(img, (W // 16 * 16, H // 16 * 16)) # 对齐到16的倍数 # 2. 转 Tensor 并归一化到 [-1, 1] img_tensor transforms.ToTensor()(img).unsqueeze(0) * 2.0 - 1.0 # 3. 推理 with torch.no_grad(): result model(img_tensor.to(device))[0] # 4. 转回图像并保存 result (result.squeeze(0) 1.0) / 2.0 result transforms.ToPILImage()(result.clamp(0, 1)) result.save(args.output / args.input.split(/)[-1])注意第三步里的torch.no_grad()推理阶段不需要计算梯度加上能省大量显存。尺寸对齐到 16 的倍数是因为网络里有多层下采样输入尺寸不能被整除的话特征图尺寸会错位报错或者输出边缘异常。这里如果报size mismatch先检查是不是输入图片尺寸没有对齐而不是先去怀疑网络结构。4. 参数调节与效果优化退化程度、人脸区域和色彩偏差跑通不代表能交付。真实的老照片退化情况千差万别有划痕密集的有整体发黄的有人脸完全模糊的。这一章讲三个最影响出图质量的调节点每一项都是老照片修复项目实际使用中反复要动的参数。4.1 划痕检测阈值与形态学处理参数老照片最常见的退化就是划痕。这类项目普遍的做法是先检测出划痕区域生成一个掩码mask再用网络专门修复掩码覆盖的区域。掩码质量直接决定修复效果而掩码由两个参数控制python test.py --with_scratch --scratch_threshold 0.3 --scratch_dilation 3--scratch_threshold是划痕检测的灵敏度阈值值越小检测出的划痕越多但误检也越严重。--scratch_dilation是掩码膨胀的像素数划痕检测出来通常是一条细线直接交给修复网络容易留下不连续的痕迹膨胀几像素让修复区域覆盖到划痕边缘的完整上下文。我踩过最深的坑是阈值设太高细划痕全部漏检。一张 1960 年代的合照扫描后上面全是头发丝一样的细纹用默认阈值 0.5 跑了二十分钟输出图里细纹一条没少。把阈值降到 0.2膨胀调到 5重跑一次就干净了。经验参数如下参数名默认值建议范围适用场景scratch_threshold0.50.15~0.4划痕浅且细调低划痕深且宽调高scratch_dilation12~5划痕细密时调大覆盖完整上下文mask_blur03~7掩码边缘软化修复结果过渡更自然4.2 人脸区域增强比例让五官不再「糊成一团」严重退化的老照片里人脸往往是最难修复的部分。通用修复网络对纹理恢复效果好但人脸这种有强先验结构的区域直接修复的结果经常是「像一张脸但不像照片里的人」。这就需要用专门的人脸增强模型做二次修复而控制这个过程的参数是修复区域的扩展比例python test.py --face_enhance --face_scale_ratio 0.8--face_scale_ratio表示在检测到人脸框的基础上向外扩展的比例0.8 意味着面部区域向外扩 80% 的空间都交给增强网络处理。这个参数很有讲究调太大头发、衣领会被误改成不真实的样子调太小人脸边缘出现明显接缝。我用 0.6 到 0.9 之间的效果最稳先跑一张看接缝在哪再调整。另外一个相关参数是--face_denoise_strength控制人脸增强时的降噪强度。数值越大人脸越平滑但容易变成「塑料脸」。老照片修复的优先级永远是「真实感优先于精致感」宁可留一点噪点也不要磨皮过度。4.3 色彩偏差修复从 RGB 到 Lab 空间的校正严重退化的照片普遍偏色常见的有整体发黄、偏青、暗部发蓝。模型训练时见过的退化模式有限输出结果常常带着原图的色彩偏向需要后处理兜底。常见做法是先把结果转到 Lab 色彩空间只对亮度通道做增强色度通道保持不动# color_correction.py import cv2 import numpy as np def auto_white_balance(img, percent5): 简单的白平衡校正按百分比截断高低光 lab cv2.cvtColor(img, cv2.COLOR_BGR2LAB) L, A, B cv2.split(lab) # 对 a、b 通道做直方图截断 for channel in [A, B]: lo np.percentile(channel, percent) hi np.percentile(channel, 100 - percent) np.clip(channel, lo, hi, outchannel) cv2.normalize(channel, channel, 0, 255, cv2.NORM_MINMAX) corrected cv2.merge([L, A, B]) return cv2.cvtColor(corrected, cv2.COLOR_LAB2BGR) result auto_white_balance(result, percent2)percent控制色彩校正的强度2% 表示把 a、b 通道最亮和最暗的 2% 像素截断后重新拉伸。为什么只在 Lab 空间处理色度通道而不动 L 通道因为过度调整亮度会让修复区域暴露新的人工痕迹。这套方法不能替代模型的颜色修复能力但能大幅度提升交付时的观感。5. 老照片修复项目部署中的 5 个高频翻车点写到这一章你应该已经跑通了最小推理也试过调参。接下来这段时间你会在这里翻车无数次——我替你把最常踩的坑先填了。5.1 现象CUDA error: no kernel image is available for execution on the device原因显卡驱动支持的 CUDA 版本和 PyTorch 编译时的 CUDA 版本不匹配。老照片修复项目通常要求 CUDA 10.2 或 11.x但你的驱动可能只支持更新的版本。解决先看驱动支持的最高 CUDA 版本nvidia-smi右上角有个 CUDA Version那个是驱动支持的最高版本。然后按这个版本重装 PyTorchpip install torch torchvision --index-url https://download.pytorch.org/whl/cu121。不要盲目上最新版兼容性第一。5.2 现象权重文件秒加载完但输出全黑或全灰原因权重文件和模型结构不匹配或者预处理/后处理的归一化方向反了。很多项目训练时数据归一化到 [-1, 1]推理脚本里却写成了 [0, 1]结果张量经过 Sigmoid 后直接饱和。解决先检查推理脚本里有没有 Sigmoid 或 Tanh再确认图像读入后除以了 255 还是乘以 2 减 1。一个快排查方法用 Python 打开输出张量看数值分布是否在 [0, 1] 或 [-1, 1] 的合理区间内。如果分布正常但仍然全黑那就是权重和模型结构对不上——重新下载正确的权重文件。5.3 现象zip 解压时报「不可预料的压缩文件末端」原因压缩包没有下载完整或者网盘客户端限速导致文件被截断。这个 zip 一般会分成多个分卷少一个都不行但很多人只下了第一个就解压出几M然后放弃。解决核对文件大小是否和下载页面标注一致。用 7-Zip 打开压缩包时如果能看到目录列表但解压中途报错说明文件损坏需要重新下载。用命令行unzip -t测试完整性unzip -t old_photo_repair.zip | tail -5显示 No errors detected 再继续使用。平时下载这些重量级 zip 我都是先放机械硬盘用哈希校验工具看一遍避免坏档读不出再决定要不要动工。5.4 现象修复后的人脸出现「两张脸」的重影或诡异五官原因人脸检测模块把背景中的相似纹理误判为人脸或者人脸增强网络在图块拼接处产生了伪影。这类翻车在多人合影照片上尤其明显。解决先关闭人脸增强只看通用修复结果——如果正常说明问题出在人脸检测/增强模块。调低--face_scale_ratio缩小人脸区域范围。仍然不行就在人脸检测阶段加大置信度阈值减少误检。这种合成伪影不细看很难发现但交付给客户时一定会被放大看所以在保存结果前要放大检查眼睛和嘴周区域。5.5 现象显存占用飙到接近 OOM大批量修复时进程被杀原因一张 3000x2000 的扫描老照片直接送进模型特征图尺寸极大显存自然吃满。部分项目没有对大图做分块处理。解决看项目是否支持--tile_size参数把长边分块处理修复后再拼回去。多数老照片修复项目没做这个优化你就得自己把图缩小——但缩小意味着清晰度下降这是个两难。我常用的折中方案长边缩到 1200px 修复再用传统超分比如 Real-ESRGAN 的思路把结果放大回原始分辨率。效果比直接硬跑大图稳定得多显存占用降低一半以上。6. 进阶技巧用合成退化数据微调把模型「掰」向你的老照片风格通用预训练模型对大多数退化照片有效但它见过的是合成退化数据和你手里这批五六十年历史的老照片的划痕分布、胶片颗粒特征完全不同。想要交付质量上一个台阶一定绕不开微调这一步。做微调不需要收集真实老照片——真实的老照片没有对应的「干净原图」无法构成训练对。常见做法是合成退化找一批当前的高清图片人为叠加划痕、噪点、颜色偏移、模糊模拟老照片的退化过程# synthesize_degradation.py import cv2 import numpy as np def degrade(img, scratch_density0.3, noise_level15): 模拟老照片退化划痕 高斯噪声 褪色 degraded img.copy() h, w degraded.shape[:2] # 随机划痕 num_scratch int(h * w * scratch_density / 10000) for _ in range(num_scratch): x1, y1 np.random.randint(0, w), np.random.randint(0, h) x2, y2 np.random.randint(0, w), np.random.randint(0, h) cv2.line(degraded, (x1, y1), (x2, y2), (255, 255, 255), np.random.randint(1, 3)) # 高斯噪声 noise np.random.normal(0, noise_level, degraded.shape) degraded np.clip(degraded noise, 0, 255).astype(np.uint8) # 整体褪色 degraded cv2.addWeighted(degraded, 0.8, img, 0.2, 0) return degraded用三四百张高清人像和风景照生成对应的退化版本组成微调数据对。学习率要比预训练时小两个数量级1e-5到5e-5之间防止把模型原有的修复能力抹掉。20 到 40 个 epoch 就好步数太多模型会过拟合到你合成的退化模式上真实老照片的表现反而下降。验证模型效果不要只看眼睛。用 PSNR 和 SSIM 看像素级恢复质量同时参考 LPIPS 评估感知相似度——后者更接近人眼对「像不像原图」的判断。具体到老照片修复场景还得保留一定数量的真实老照片作为「验收集」跑完一轮微调挑几张没参与训练的图做肉眼对比重点看不规则划痕和胶片颗粒的自然程度。这种判断没有客观指标但它决定了客户验收时一句「这图修过吗」是惊喜还是质疑。我每次接到批量老照片修复任务都会做一轮这样的微调再把权重固定下来。之后批量跑图全程黑盒运行除了随机种子引发的小幅波动结果稳定可复现。等哪一天你发现模型的修复结果越来越不稳定先回想是不是微调时学习率设太大把模型权重搞乱了。这个项目玩到现在我最深的体会就是老照片修复不是让模型「画」一部分内容骗过眼睛而是让模型「知道」干净的旧照片长什么样剩下的事都是参数和耐心的磨合。希望帮到你。本文还有配套的精品资源点击获取