目录
-
项目简介
-
环境配置
-
数据集介绍
-
项目结构
-
核心实现流程
-
详细使用步骤
- 1. 下载数据集
- 2. 生成"老化"图像
- 3. 训练修复模型
- 4. 修复单张图像
-
各文件功能详解
-
网络架构设计
-
损失函数详解
-
实验结果与分析
-
常见问题解答
-
总结与展望
-
代码清单【附件】
项目简介
本项目实现了一个基于生成对抗网络(GAN)的老旧风景照片修复系统。通过对干净的风景照片施加噪声、色彩衰减和划痕等效果,模拟自然老化的照片,然后训练GAN网络学习从老化照片恢复到原始清晰照片的映射关系。这种技术可以应用于修复实际的老旧照片,恢复其原有的清晰度和色彩。
与传统的图像修复方法相比,基于GAN的方法能够更好地保留图像的细节和纹理信息,产生更加自然、真实的修复效果。本项目特别针对风景照片进行了优化,能够有效处理各种老化效应,如色彩褪色、噪点增加和表面划痕等。
该工程基于GAN(生成对抗网络)实现自然风景图片的修复。其核心流程为:
- 从原始清晰图像生成"磨损"图像(高斯噪声、色彩漂移、划痕等);
- 使用自定义Dataset加载成对图像;
- 定义U-Net风格多分支生成器与PatchGAN判别器;
- 训练GAN,优化对抗+内容+可选感知损失;
- 验证阶段评估PSNR/SSIM;
- 单图推理完成修复。
环境配置
本项目使用Python和PyTorch开发,主要依赖包括:
pip install torch torchvision tqdm opencv-python pillow scikit-image kagglehub
推荐使用conda创建虚拟环境:
conda create -n landscape-repair python=3.8
conda activate landscape-repair
pip install torch torchvision tqdm opencv-python pillow scikit-image kagglehub
GPU环境配置(推荐使用CUDA加速训练):
- CUDA 11.3+
- PyTorch 1.10+
- 至少8GB显存的NVIDIA GPU(GTX 1080Ti或更高)
- VRAM需求:batch_size=8,img_size=256时约需6GB显存
CPU训练也可行,但速度会大幅降低(约为GPU的1/10)。如需在CPU上训练,请调整batch_size为较小值(如2或4)。
数据集介绍
本项目使用Kaggle上的"Landscape Recognition Image Dataset",包含约12,000张高质量风景图像,分为以下主要类别:
- Coast(海岸):约2000张图像,展示各种海岸线、沙滩和海洋场景
- Desert(沙漠):约2000张图像,展示沙漠景观和荒漠地形
- Forest(森林):约2000张图像,包含各种森林、树木和植被场景
- Glacier(冰川):约2000张图像,展示冰川、雪山和冰雪景观
- Mountain(山脉):约2000张图像,包含各种山脉和高地景观
- Buildings(建筑):约2000张图像,展示与自然景观结合的建筑物
每个类别的图像都有训练集和测试集的划分。图像分辨率大多在1000×1000像素左右,格式为JPEG。该数据集具有丰富的纹理细节和色彩变化,适合用于训练和测试图像修复模型。
数据集总大小约为500MB,下载后需解压并组织为项目所需的目录结构。
项目结构
初始项目结构如下:
GAN_landscape_img_repair-master/
├── add_noise.py # 图像老化处理脚本
├── dataset.py # 数据集加载类
├── download_datasets.py # 数据集下载脚本
├── inference.py # 单图像推理脚本
├── model.py # 模型架构定义
├── train.py # 模型训练脚本
└── utils.py # 工具函数
核心实现流程
本项目的核心实现流程分为六个主要步骤:
1. 从原始清晰图像生成"磨损"图像
-
使用
add_noise.py
脚本对原始风景照片应用多种老化效果 -
主要包括三种老化处理:
- 色彩调整:降低饱和度、微调色相和亮度,模拟老照片的褪色效果
- 高斯噪声:添加随机强度的噪点,模拟胶片颗粒感和时间侵蚀
- 随机划痕:添加浅色线条,模拟照片表面的物理损伤
2. 使用自定义Dataset加载成对图像
dataset.py
中的LandscapeDataset
类负责加载和预处理图像对- 自动配对"原始-老化"图像,确保一一对应
- 实现图像预处理:调整尺寸、标准化、可选的数据增强
- 提供批量加载机制,支持PyTorch的DataLoader接口
3. 定义U-Net风格多分支生成器与PatchGAN判别器
-
在
model.py
中实现两个网络架构:RepairNetGenerator
:多分支U-Net生成器,由共享编码器、三路解码器和细节增强模块组成RepairNetDiscriminator
:PatchGAN判别器,判断图像块级别的真假
-
生成器专注于不同尺度的特征重建,判别器关注局部纹理质量
4. 训练GAN,优化对抗+内容+可选感知损失
-
train.py
实现完整训练循环 -
交替训练判别器和生成器:先优化D再优化G
-
综合三种损失:
- 对抗损失:促使生成图像骗过判别器
- 内容损失(MSE):保证像素级相似性
- 感知损失(可选):基于VGG特征,提升视觉质量
5. 验证阶段评估PSNR/SSIM
-
每个epoch结束后在测试集上评估模型性能
-
计算两个关键指标:
- PSNR(峰值信噪比):评估整体重建质量
- SSIM(结构相似度):评估结构和纹理保留程度
-
保存SSIM值最高的模型作为最佳模型
6. 单图推理完成修复
- 使用
inference.py
加载训练好的生成器模型 - 对单张老化图像进行前向传播,得到修复结果
- 支持批量处理多张图像的扩展功能
详细使用步骤
1. 下载数据集
使用download_datasets.py
脚本从Kaggle下载风景图像数据集:
python download_datasets.py
下载完成后,数据集会被存储在默认位置(~/.cache/kagglehub/datasets/)。然后您需要将数据集解压并组织成以下结构:
GAN_landscape_img_repair-master/
├── Landscape Classification/
│ ├── Training Data/
│ │ ├── Coast/
│ │ │ ├── Coast-Train (1).jpeg
│ │ │ ├── Coast-Train (2).jpeg
│ │ │ └── ...
│ │ ├── Desert/
│ │ │ ├── Desert-Train (1).jpeg
│ │ │ └── ...
│ │ ├── Forest/
│ │ │ ├── Forest-Train (1).jpeg
│ │ │ └── ...
│ │ ├── Glacier/
│ │ │ ├── Glacier-Train (1).jpeg
│ │ │ └── ...
│ │ └── Mountain/
│ │ ├── Mountain-Train (1).jpeg
│ │ └── ...
│ └── Testing Data/
│ ├── Coast/
│ │ ├── Coast-Test (1).jpeg
│ │ └── ...
│ ├── Desert/
│ ├── Forest/
│ ├── Glacier/
│ └── Mountain/
├── add_noise.py
├── dataset.py
├── download_datasets.py
├── inference.py
├── model.py
├── train.py
└── utils.py
注意事项:
- 如果遇到kagglehub访问问题,需确保已正确配置Kaggle API凭证
- 您可能需要手动将数据集从下载位置移动到项目目录下
- 确保类别名称和文件名格式与上述结构一致,否则需修改
dataset.py
中的路径处理逻辑
2. 生成"磨损"图像
运行add_noise.py
脚本,对原始图像添加老化效果:
python add_noise.py
该脚本会自动处理"Landscape Classification"目录中的所有图像,为每张图像应用三种老化效果:
- 色彩衰减:
adjust_color_randomly
函数调整HSV值,主要降低饱和度(15%左右),轻微调整色相(±15°)和亮度(±10%) - 随机高斯噪点:
add_random_gaussian_noise
函数添加均值为0,标准差在5-25范围内的高斯噪声 - 随机划痕:
add_scratches
函数在图像上添加40条随机位置、随机长度的浅色线条
处理过程显示进度条,每处理一张图像会在对应的"Landscape Classification Noise"目录下保存一份老化版本,保持原目录结构和文件名不变。
处理完成后,目录结构将变为:
GAN_landscape_img_repair-master/
├── Landscape Classification/
│ ├── Training Data/
│ │ └── ...
│ └── Testing Data/
│ └── ...
├── Landscape Classification Noise/ # 新生成的模拟磨损图像目录
│ ├── Training Data/
│ │ ├── Coast/
│ │ │ ├── Coast-Train (1).jpeg # 老化版本
│ │ │ ├── Coast-Train (2).jpeg
│ │ │ └── ...
│ │ ├── Desert/
│ │ ├── Forest/
│ │ ├── Glacier/
│ │ └── Mountain/
│ └── Testing Data/
│ ├── Coast/
│ ├── Desert/
│ ├── Forest/
│ ├── Glacier/
│ └── Mountain/
├── add_noise.py
├── dataset.py
├── download_datasets.py
├── inference.py
├── model.py
├── train.py
└── utils.py
处理12,000张图像大约需要30-60分钟,取决于CPU性能和图像分辨率。如果需要调整老化效果的强度,可以修改add_noise.py
中相应函数的参数:
- 色彩调整:修改
hue_range
、saturation_range
和value_range
参数 - 噪点强度:修改
sigma_range
参数 - 划痕数量:修改
num_scratches
参数
3. 训练修复模型
使用train.py
训练GAN模型:
python train.py --root_dir . --epochs 30 --batch_size 8 --lr 5e-5 --img_size 256 --lambda_content 100.0 --use_perceptual --device cuda --save_dir checkpoints
参数详细说明:
-
--root_dir
:项目根目录,包含数据集的位置。默认为当前目录"." -
--epochs
:训练轮数,建议至少30轮获得较好效果,更多轮数可能获得更好结果 -
--batch_size
:批量大小,根据GPU内存调整- 8GB显存建议设置为8
- 12GB显存可设置为16
- 4GB显存建议降至4
-
--lr
:学习率,默认5e-5,较低的学习率有助于稳定训练 -
--img_size
:训练时的图像大小,默认256×256像素- 较大的尺寸可捕获更多细节,但需要更多显存
- 可选值:128、256、384、512
-
--lambda_content
:内容损失权重,控制修复保真度和对抗性的平衡- 默认100.0,更高的值会更注重像素级还原
- 更低的值会增强GAN的创造性,但可能导致细节不准确
-
--use_perceptual
:使用VGG感知损失提升视觉质量,略微增加显存占用 -
--device
:计算设备,可选"cuda"或"cpu" -
--save_dir
:模型保存目录,默认为"checkpoints"
训练过程中,程序会在每个epoch后评估模型在测试集上的性能,并打印三个关键指标:
- 生成器损失(G_loss):综合了对抗损失、内容损失和可选的感知损失
- 判别器损失(D_loss):衡量判别器区分真实和生成图像的能力
- PSNR和SSIM:客观评价指标,值越高表示修复质量越好
程序会保存SSIM指标最高的模型作为最佳模型。训练完成后,目录结构变为:
GAN_landscape_img_repair-master/
├── Landscape Classification/
│ └── ...
├── Landscape Classification Noise/
│ └── ...
├── checkpoints/ # 新生成的模型目录
│ └── best_generator.pth # 最佳生成器模型(约100-200MB)
├── add_noise.py
├── dataset.py
├── download_datasets.py
├── inference.py
├── model.py
├── train.py
└── utils.py
典型的训练时间:
- GTX 1080Ti:约4-6小时完成30个epoch
- RTX 3090:约2-3小时完成30个epoch
- CPU(8核):约40-50小时完成30个epoch
训练过程中可能会观察到:
- 前5个epoch:PSNR和SSIM快速提升
- 5-15个epoch:提升速度减缓
- 15个epoch以后:缓慢改善,主要是细节和纹理的提升
4. 修复单张图像
使用训练好的模型对单张老化图像进行修复:
python inference.py --model_path checkpoints/best_generator.pth --input path/to/noise_image.jpeg --output path/to/repaired_image.png
参数详细说明:
-
--model_path
:已训练模型的路径,默认为"checkpoints/best_generator.pth" -
--input
:待修复的老化图像路径,可以是任意尺寸的.jpg/.jpeg/.png图像 -
--output
:修复后图像的保存路径,推荐使用.png格式保留所有细节 -
--img_size
:处理图像的大小(默认256),可根据需要调整- 较大的值(如512)可能获得更好的细节,但处理更慢
- 无论设置多大,输出图像都会保持与输入相同的分辨率
-
--device
:使用"cuda"或"cpu"(默认"cuda")
推理速度参考:
- GPU(GTX 1080Ti):处理一张1000×1000的图像约0.5秒
- CPU(Intel i7):处理同样大小的图像约2-3秒
如果你希望批量处理多张图像,可以编写一个简单的脚本调用inference.py
中的process_single
函数:
import os
from inference import process_single
import torch
# 加载模型
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
G = torch.load('checkpoints/best_generator.pth', map_location=device)
G.to(device).eval()
# 批量处理图像
input_dir = 'path/to/noisy_images'
output_dir = 'path/to/repaired_images'
os.makedirs(output_dir, exist_ok=True)
for img_file in os.listdir(input_dir):
if img_file.lower().endswith(('.jpg', '.jpeg', '.png')):
input_path = os.path.join(input_dir, img_file)
output_path = os.path.join(output_dir, os.path.splitext(img_file)[0] + '.png')
process_single(input_path, output_path, G, 256, device)
print(f'已处理: {
img_file}')
执行后,您的项目目录可能会变为:
GAN_landscape_img_repair-master/
├── Landscape Classification/
├── Landscape Classification Noise/
├── checkpoints/
│ └── best_generator.pth
├── repaired_images/ # 新生成的修复图像目录
│ ├── image1.png
│ ├── image2.png
│ └── ...
├── add_noise.py
├── dataset.py
├── download_datasets.py
├── inference.py
├── model.py
├── train.py
└── utils.py
各文件功能详解
1. add_noise.py
这个脚本用于模拟老化效果,主要包含三个核心函数:
-
adjust_color_randomly
:随机调整图像的HSV值,模拟老照片的色彩退化def adjust_color_randomly(image, hue_range=15, saturation_range=0.15, value_range=0.1): # 转换为HSV空间 # 随机调整色相、饱和度和亮度 # 将图像转回BGR格式
-
add_random_gaussian_noise
:添加高斯噪声,模拟年代久远的照片中常见的颗粒感def add_random_gaussian_noise(image, mean=0, sigma_range=(5, 25)): # 生成随机高斯噪声 # 将噪声添加到图像上 # 保证像素值在有效范围内
-
add_scratches
:添加随机划痕,模拟照片表面的机械损伤def add_scratches(image, num_scratches=40): # 在随机位置生成随机方向的线条 # 使用浅色(接近白色)表示划痕 # 添加到图像上
此外,还提供了单图处理函数Apply_photo_wear_effect_single
和批量处理函数Apply_photos_wear_effect_all
,后者还包含完整的目录遍历和进度显示功能。
该文件是整个工作流程的第一步,负责生成训练和测试所需的"老化"图像数据。
2. dataset.py
定义了PyTorch数据集类LandscapeDataset
,负责加载成对的老化/干净风景图像:
class LandscapeDataset(Dataset):
def __init__(self, root_dir, split='train', img_size=256):
# 初始化路径
# 查找配对的图像
# 设置图像变换(调整大小、标准化等)
def __len__(self):
# 返回数据集大小
def __getitem__(self, idx):
# 根据索引加载图像对
# 应用变换
# 返回(noisy, clean)图像对
主要功能包括:
- 自动查找和配对对应的老化图像和原始图像
- 图像预处理:调整到指定大小(默认256×256)
- 标准化:将像素值缩放到[-1, 1]范围
- 数据增强:训练集可选的随机水平翻转和轻微旋转
- 按批次提供给训练循环
设计上采用了成对加载机制,确保老化图像和原始图像严格对应,便于监督学习。
3. download_datasets.py
使用kagglehub工具从Kaggle平台下载风景识别数据集:
import kagglehub
# 下载最新版本
path = kagglehub.dataset_download("utkarshsaxenadn/landscape-recognition-image-dataset-12k-images")
print("数据集文件路径:", path)
这个脚本虽然简短,但执行了重要的数据获取任务。它会自动下载和解压数据集,并返回数据集的本地路径。需要注意的是,使用前应确保已安装kagglehub并配置了Kaggle API凭证。
4. inference.py
提供单张图像的推理功能,主要包含:
-
参数解析函数
parse_args
,处理命令行参数 -
图像处理函数
process_single
:def process_single(input_path, output_path, G, img_size, device): # 加载与预处理图像 # 记录原始尺寸 # 送入模型推理 # 后处理生成结果(反标准化等) # 恢复原始尺寸 # 保存结果
-
主函数
main
,负责加载模型和调用处理函数
工作流程:
- 加载图像并调整大小
- 标准化到[-1, 1]范围
- 送入生成器模型进行推理
- 将输出反标准化回[0, 1]范围
- 恢复原始图像尺寸
- 保存为指定格式
该脚本设计成可以作为独立工具使用,也可以作为模块导入到其他Python脚本中用于批处理。
5. model.py
定义GAN的网络架构,包含以下主要组件:
-
基础模块:
class DownSample(nn.Module): # 下采样模块:卷积 + 可选批归一化 + LeakyReLU class UpSample(nn.Module): # 上采样模块:转置卷积 + 可选批归一化 + 可选ReLU
-
生成器:
class RepairNetGenerator(nn.Module): # 多分支U-Net结构 # 共享编码器(3层) # 多路径解码器(3条路径) # 初步融合模块 # 细节增强模块
-
判别器:
class RepairNetDiscriminator(nn.Module): # PatchGAN判别器 # 接收拼接的输入和目标/生成图像 # 输出每个图像块的真假判断
生成器采用创新的多分支U-Net结构,包括:
- 共享编码器:提取多尺度特征
- 三个独立解码路径:各自关注不同尺度的重建
- 融合模块:结合三条路径的输出
- 细节增强:进一步提升局部细节
判别器采用PatchGAN设计,以70×70的感受野判断图像块的真实性,有助于提升局部纹理质量。
6. train.py
实现了GAN的训练循环,主要功能包括:
-
参数配置和数据加载
-
网络初始化(生成器和判别器)
-
损失函数定义(BCE、MSE、可选的VGG感知损失)
-
优化器设置
-
训练循环:
for epoch in range(1, args.epochs+1): # 训练阶段 for noisy, real in train_loader: # 判别器更新 # 生成器更新 # 验证阶段 with torch.no_grad(): for noisy, real in test_loader: # 计算PSNR和SSIM # 保存最佳模型
-
评估指标计算(PSNR和SSIM)
-
模型保存
训练采用标准的GAN交替优化策略:
- 先训练判别器:最大化真实图像的分数,最小化生成图像的分数
- 再训练生成器:最大化生成图像的分数,同时最小化与真实图像的差异
评估使用两个客观指标:
- PSNR(峰值信噪比):评估整体像素差异
- SSIM(结构相似度):评估结构和纹理保留程度
模型保存逻辑是保留验证集上SSIM值最高的模型。
7. utils.py
提供基础工具函数:
-
load_image
:加载图像并转换为RGB模式def load_image(path): return Image.open(path).convert('RGB')
-
save_image
:将张量保存为图像文件def save_image(tensor, path): # 处理张量:分离、CPU转移 # 从[-1,1]映射到[0,1] # 从[0,1]映射到[0,255] # 转换通道顺序并创建PIL图像 # 保存到指定路径
这些工具函数封装了常用的图像处理操作,确保在项目各部分保持一致的图像处理流程。
网络架构设计
生成器架构
本项目的生成器采用了创新的多分支U-Net结构,由以下几个部分组成:
-
共享编码器:
- 3层下采样,逐步将输入图像(3×H×W)编码为更深层的特征图
- 第一层:3→64通道,无批归一化
- 第二层:64→128通道,带批归一化
- 第三层:128→256通道,带批归一化
- 采用LeakyReLU激活函数,斜率0.2
-
多分支解码器:
- 分支1:直接从第一层特征上采样到输出尺寸(浅层特征路径)
- 分支2:从第二层特征经过两次上采样到输出尺寸(中层特征路径)
- 分支3:从第三层特征经过三次上采样到输出尺寸(深层特征路径)
- 每个分支独立工作,没有跳跃连接,专注于不同尺度的信息重建
-
初步融合模块:
- 将三个分支的输出拼接(concat)
- 通过两个连续的卷积层(带ReLU和Tanh)融合多尺度信息
- 将特征通道数从3×输出通道数减少到输出通道数
-
细节增强模块:
- 在融合后的结果上再次应用两个卷积层
- 专注于增强局部细节和边缘
- 最终输出通过Tanh激活,确保值域在[-1,1]
这种多分支设计的优势:
- 不同分支可以关注不同类型的图像退化:浅层分支处理噪声,深层分支处理结构
- 避免了传统U-Net中可能出现的信息损失
- 细节增强模块相当于残差学习,进一步提升图像质量
判别器架构
判别器采用PatchGAN设计,结构如下:
-
输入:拼接的条件图像和目标/生成图像(6×H×W)
-
4层下采样,每层将空间分辨率减半:
- 第一层:6→64通道,无批归一化
- 第二层:64→128通道,带批归一化
- 第三层:128→256通道,带批归一化
- 第四层:256→512通道,带批归一化
-
最终层:512→1通道,输出每个位置的判别分数
-
所有下采样层使用LeakyReLU激活函数
</