简介:这份资源面向图像处理与深度学习方向的开发者、学生及算法爱好者,聚焦现实世界中模糊人脸图像的清晰化恢复问题,以GFPGAN为核心实现方案,帮助读者理解生成对抗网络在人脸修复任务中的落地方式。压缩包共53个文件,约5.72MB,包含26个Python源码文件、4个yml与2个yaml训练配置、4个md说明文档,以及pth预训练权重、cfg与in等配置文件和少量png、jpg示例图,覆盖模型构建、训练、推理与测试各环节。资源围绕数据预处理、生成器与判别器搭建、对抗损失与感知损失训练、SSIM与PSNR评估、应用部署等关键流程展开,并配有详细流程教程与项目源码,便于读者对照复现实验、理解GFPGAN的工程结构,也可作为人脸识别、视频编辑等场景的参考实现。目前已有189人学习,适合希望系统掌握人脸恢复算法并积累实战经验的中高级读者。
1. 模糊人脸恢复到底难在哪:从一张糊成马赛克的旧照说起
手里有一张十几年前的合影,人脸区域只有指甲盖大小,放大后全是块状噪点,眼睛鼻子糊成一团。这种图丢给传统锐化算法,出来的结果要么是满脸噪点,要么是塑料感极强的假脸。模糊人脸恢复要解决的核心问题不是"把图放大",而是在像素信息严重缺失的前提下,把丢失的高频细节合理地"猜"回来,同时还得像个人。
GFPGAN 就是冲着这个场景来的。它把人脸超分和面部先验知识揉在一起,用生成式的方式重建五官结构,而不是单纯做插值。这份资源包给了一套能跑通的完整流程加源码,适合两类人:一类是手里有模糊人脸素材、想快速看到恢复效果的产品和运营同学;另一类是刚接触图像恢复、想拿一个真实项目练手的算法初学者。它不要求你从零推导 GAN 的损失函数,但要求你能把环境配起来、把权重加载对、把参数调明白。
我见过太多人卡在第一步——环境装完跑不通,或者跑通了效果跟演示图差十万八千里。这篇笔记就按"能复现"的标准来拆,把每个环节的参数含义和翻车点都摊开讲。
2. GFPGAN 的恢复链路拆解:为什么它比普通超分更像人
2.1 退化建模与生成式先验的配合逻辑
普通超分模型(比如 ESRGAN)的训练目标是让输出在像素层面接近高清原图,但它没见过的人脸结构,就只能靠纹理糊弄。GFPGAN 的思路不一样:它引入了一个预训练的人脸 GAN(通常是 StyleGAN2 系)作为先验,把低质人脸先映射到 GAN 的隐空间里,再从这个空间解码出高清人脸。换句话说,它不是在"修复像素",而是在"重建一张符合人脸分布的脸"。
这个链路大致分三段。第一段是退化去除模块,负责把输入图的噪声、模糊、压缩伪影压下去,输出一个相对干净的中间特征。第二段是 GAN 先验注入,把中间特征对齐到预训练生成器的隐编码上。第三段是解码与融合,生成高清人脸后再和原图做保真度融合,避免完全脱离原图变成另一张脸。
理解这个三段结构很重要,因为它直接决定了你调参时的方向:如果输出太假、不像本人,说明 GAN 先验权重过大,需要往回拉;如果输出还是糊的,说明退化去除没做够,或者输入分辨率太低,先验根本没东西可对齐。
2.2 环境搭建与依赖版本锁定
这份源码包基于 PyTorch 实现,常见做法是用 conda 建一个独立环境,避免和系统里的其他深度学习库打架。下面是我一般会走的安装流程,命令都验证过:
# 创建独立环境,python 版本建议 3.8 或 3.9 conda create -n gfpgan_env python=3.9 -y conda activate gfpgan_env # 安装 PyTorch,注意 CUDA 版本要和你的显卡驱动匹配 # 这里以 CUDA 11.3 为例,驱动版本不够就降级 pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 \ -f https://download.pytorch.org/whl/torch_stable.html # 安装项目依赖 pip install basicsr facexlib gfpgan pip install opencv-python pillow numpy逻辑说明:PyTorch 版本必须和 CUDA 驱动对齐,这是最常见的翻车点。basicsr是 GFPGAN 依赖的基础超分框架,facexlib提供人脸检测和对齐能力,gfpgan是主包。参数上,torch==1.12.1+cu113里的cu113表示编译时链接的 CUDA 版本,如果你机器上是 CUDA 11.6,就换成cu116对应的 wheel。
装完之后别急着跑,先验证一下:
import torch print(torch.__version__) print(torch.cuda.is_available()) # 必须输出 True print(torch.cuda.get_device_name(0))如果is_available()返回 False,后面所有推理都会退到 CPU,速度慢到没法用。这时候要检查驱动版本和 CUDA 运行时是否匹配,而不是反复重装 PyTorch。
2.3 权重文件放置与推理入口
GFPGAN 需要两类权重:人脸检测模型和恢复模型本身。源码包里一般会附带下载脚本,常见做法是手动放到指定目录,避免网络问题导致下载中断。
# 目录结构参考 GFPGAN/ ├── experiments/ │ └── pretrained_models/ │ ├── detection_Resnet50_Final.pth │ └── GFPGANv1.4.pth ├── inputs/ │ └── whole_photo.jpg └── results/权重放好后,推理命令通常长这样:
python inference_gfpgan.py \ -i inputs/whole_photo.jpg \ -o results \ -v 1.4 \ -s 2 \ --bg_upsampler realesrgan参数逐个说:-i是输入路径,可以是单张图也可以是文件夹;-o是输出目录;-v 1.4指定模型版本,不同版本对细节和保真度的取舍不一样;-s 2是放大倍数,2 表示输出分辨率是输入的 2 倍;--bg_upsampler realesrgan表示背景用 RealESRGAN 单独处理,因为 GFPGAN 只负责人脸区域,背景如果不管会显得很割裂。
跑完之后results目录下会有cmp(对比图)、cropped_faces(裁剪出的人脸)、restored_faces(恢复后的人脸)和restored_imgs(整图恢复结果)。先看cmp目录,能最直观判断效果。
3. 参数调优与批量处理:把单张跑通变成能干活
3.1 放大倍数与保真度的权衡
-s参数不是越大越好。设成 4 的时候,模型要在更大尺度上"编"细节,五官容易走形;设成 1 又几乎没放大,失去意义。我的经验是:原图人脸区域小于 64×64 像素时,用-s 2先恢复一轮,再把结果作为输入跑第二轮,比直接-s 4稳。这叫迭代恢复,虽然慢,但脸不容易崩。
还有一个隐藏参数是--upscale,它控制最终输出的整体缩放。如果你只想要人脸变清晰、背景保持原样,可以把背景上采样关掉,只保留人脸恢复。
3.2 批量处理脚本与命名规范
单张跑通之后,实际项目里往往是几百张图。直接循环调用命令行效率低,我一般写一个 Python 脚本批量处理,顺便统一命名和日志:
import os import cv2 import glob from gfpgan import GFPGANer # 初始化恢复器,只加载一次,避免重复占显存 restorer = GFPGANer( model_path='experiments/pretrained_models/GFPGANv1.4.pth', upscale=2, arch='clean', channel_multiplier=2, bg_upsampler=None # 批量时先不处理背景,省时间 ) input_dir = 'inputs/batch' output_dir = 'results/batch' os.makedirs(output_dir, exist_ok=True) for img_path in glob.glob(os.path.join(input_dir, '*.jpg')): img_name = os.path.basename(img_path) img = cv2.imread(img_path, cv2.IMREAD_COLOR) # 核心调用,返回裁剪人脸、恢复人脸、恢复整图 _, _, restored_img = restorer.enhance( img, has_aligned=False, only_center_face=False, paste_back=True ) if restored_img is not None: cv2.imwrite(os.path.join(output_dir, img_name), restored_img) print(f'done: {img_name}') else: print(f'no face detected: {img_name}')逻辑说明:GFPGANer初始化时把模型加载进显存,循环里只做前向推理,这是批量处理提速的关键。has_aligned=False表示输入是整图不是对齐后的人脸,让内部自己检测;only_center_face=False表示处理画面里所有人脸,如果只关心主角可以设 True 提速;paste_back=True把恢复后的人脸贴回原图。参数channel_multiplier=2控制网络宽度,调大更精细但更吃显存,一般保持 2 即可。
3.3 人脸检测失败时的兜底策略
批量跑的时候一定会遇到检测不到脸的情况——侧脸、遮挡、太小、太暗都会导致检测器罢工。这时候restored_img返回 None,如果不做处理,输出目录里就会缺文件,后续流程容易断。
常见做法是加一层兜底:检测失败时,直接把原图复制到输出目录,并在日志里标记。这样至少保证文件数量对得上,人工复查时能快速定位问题图。另一个思路是先用facexlib的检测器单独跑一遍,把置信度低的图挑出来,降低阈值再试一次,但要注意阈值太低会引入误检,把不是脸的区域也当脸处理。
4. 避坑与排查:那些让我重跑一整天的细节
4.1 现象:推理报错 "CUDA out of memory"
原因:批量处理时图片分辨率过大,或者channel_multiplier设得太高,显存扛不住。GFPGAN 在 2K 图上跑,显存占用会飙升。
解决:先把输入图缩到长边 1024 以内再送进去;如果还爆,把channel_multiplier降到 1;实在不行就分块处理,或者换显存更大的卡。别硬扛,爆显存之后进程可能留下僵尸占用,得重启内核。
4.2 现象:恢复后的人脸完全不像本人
原因:GAN 先验权重过大,模型"自由发挥"过头了。这种情况在输入质量极差时尤其明显,因为先验没有足够的约束。
解决:换用保真度更高的模型版本(比如 v1.3 比 v1.4 更保守),或者降低放大倍数,先恢复一轮再迭代。如果还是不像,说明输入信息量已经低于模型能合理重建的下限,这时候任何算法都救不回来,只能换素材。
4.3 现象:背景和人脸拼接处有明显色差或接缝
原因:人脸区域和背景用了不同的处理管线,亮度、色彩空间没对齐。
解决:开启--bg_upsampler realesrgan让背景也走一遍上采样,或者后期用泊松融合把接缝抹平。我一般会在贴回之前,对人脸区域边缘做一圈羽化,过渡会自然很多。
4.4 现象:安装 basicsr 时报错 "ModuleNotFoundError: No module named 'torch'"
原因:conda 环境和 pip 的路径没对齐,或者 PyTorch 装到了 base 环境里。
解决:确认conda activate之后which python指向的是当前环境的解释器,再重新装 PyTorch。别在没激活环境的情况下 pip install,这是新手最常踩的坑。
4.5 现象:输出图片偏色,整体发绿或发紫
原因:OpenCV 读图默认是 BGR 通道,而模型内部可能按 RGB 处理,通道顺序搞反了。
解决:读图后用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)转一下,输出前再转回 BGR。这个坑很隐蔽,因为图能出来,只是颜色不对,不仔细看容易忽略。
5. 进阶技巧:用分块推理把大图恢复做到可用
前面说的都是常规流程,但实际项目里经常遇到整张大合影,人脸只占很小一块,直接整图送进去要么爆显存,要么人脸区域被过度压缩。我后来固定用一套分块推理加人脸对齐的组合拳,效果稳定很多。
思路是这样的:先用facexlib的检测器把所有人脸框出来,按框裁剪出人脸区域,每张脸单独做恢复,再把恢复后的人脸按原坐标贴回大图。这样每张脸都能拿到足够的像素预算,不会被整图缩放拖累。代价是要处理贴回时的边缘融合,但比起整图崩掉,这点工作量值得。
from facexlib.detection import init_detection_model import cv2 import numpy as np # 初始化检测器 detector = init_detection_model('retinaface_resnet50', half=False) img = cv2.imread('inputs/group_photo.jpg') # 检测人脸,返回框和关键点 with torch.no_grad(): bboxes = detector.detect_faces(img, conf_threshold=0.5) for i, box in enumerate(bboxes): x1, y1, x2, y2 = map(int, box[:4]) # 外扩 20% 留出上下文,避免贴回时太生硬 w, h = x2 - x1, y2 - y1 x1 = max(0, x1 - int(w * 0.2)) y1 = max(0, y1 - int(h * 0.2)) x2 = min(img.shape[1], x2 + int(w * 0.2)) y2 = min(img.shape[0], y2 + int(h * 0.2)) face_crop = img[y1:y2, x1:x2] # 这里调用恢复器处理 face_crop,再贴回 # 贴回时用高斯羽化边缘参数上,conf_threshold=0.5是检测置信度阈值,调低能检出更多侧脸但误检也会增加;外扩 20% 是为了给贴回留过渡区,太小会有硬边,太大可能把旁边的人脸框进来。羽化半径一般取人脸框短边的 5% 到 10%,具体看分辨率。
验证恢复效果不能只看一张图。我习惯准备一组对照:原图、恢复图、以及一个用普通双三次插值放大的图,三张并排看。如果恢复图在五官结构上明显比插值图合理,说明模型起作用了;如果只是更锐但结构还是错的,那可能是锐化过度,得回头调参数。
从那以后我每次跑批量恢复,都强制先拿三张典型图(正脸、侧脸、小脸)做小样本验证,确认参数没问题再全量跑。这个习惯帮我省了至少两次通宵重跑。希望帮到你。
本文还有配套的精品资源,点击获取