如何批量处理照片?GPEN脚本扩展方法分享
你是不是也遇到过这样的情况:手头有几十张老照片,有的模糊、有的泛黄、有的带噪点,一张张手动修复太耗时,而市面上的在线工具又限制数量、要排队、还担心隐私泄露?其实,用GPEN人像修复增强模型,完全可以在本地一次性批量处理整批照片——而且不需要从零写代码,只需在原有推理脚本基础上做轻量扩展。
本文不讲理论推导,不堆参数配置,只聚焦一个实际问题:怎么把单张图片修复脚本,变成能自动遍历文件夹、批量处理、按原名保存、跳过非图像文件的实用工具?全程基于镜像预装环境,无需额外安装依赖,10分钟就能跑通,小白也能照着操作成功。
1. 为什么单图脚本不够用?
先看镜像文档里提供的标准用法:
python inference_gpen.py --input ./my_photo.jpg它确实能修好一张图,但真实场景中,我们面对的从来不是“一张图”,而是:
- 一个叫
family_2005的文件夹,里面存着47张JPG和3张PNG; - 一个叫
graduation_old的目录,混着.jpg、.jpeg、.JPG多种后缀; - 还有些
.DS_Store或缩略图文件,直接传入会报错; - 更关键的是:每次都要改命令、等结果、再改下一条……效率极低。
也就是说,原生脚本是为“验证功能”设计的,不是为“日常使用”准备的。
真正提升效率的关键,不在于换更强的模型,而在于让工具适配你的工作流。
2. 批量处理的核心思路
批量不是靠“多开几个终端”,而是用程序思维解决重复劳动。我们只需要三步:
2.1 明确输入输出规则
| 项目 | 说明 |
|---|---|
| 输入源 | 指定一个文件夹路径(如./old_photos/),自动读取其中所有支持的图像文件 |
| 文件过滤 | 只处理.jpg、.jpeg、.png、.bmp(大小写不敏感),跳过隐藏文件、临时文件、非图像文件 |
| 输出命名 | 保持原文件名,仅在前面加enhanced_前缀,或可选覆盖原图(不推荐) |
| 错误容错 | 单张图处理失败(如损坏、非人脸)不影响其余图片,记录日志并继续 |
这个逻辑清晰、边界明确,不依赖复杂框架,纯Python标准库就能实现。
2.2 复用原有推理能力
GPEN的inference_gpen.py本身已封装好全部核心逻辑:加载模型、人脸检测、对齐、增强、保存。我们不重写模型调用,只包装调用方式——就像给一台好相机装上自动连拍模式,而不是重新造镜头。
关键点在于:找到脚本中真正执行推理的函数入口。查看/root/GPEN/inference_gpen.py源码可知,主流程由main()函数驱动,而核心处理逻辑集中在enhance_image()或类似命名函数(实际为infer())。我们只需提取其调用接口,避免重复初始化模型。
3. 实战:编写批量处理脚本
下面这个脚本,命名为batch_enhance.py,放在/root/GPEN/目录下即可直接运行。全文不到80行,无第三方依赖,全部使用镜像预装环境。
3.1 完整脚本代码(含详细注释)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ GPEN 批量人像修复脚本 功能:遍历指定文件夹,对所有人脸图像进行高清增强,结果自动保存 作者:适配CSDN星图GPEN镜像环境 """ import os import glob import argparse from pathlib import Path import cv2 import numpy as np # 确保在GPEN项目根目录下运行(即包含inference_gpen.py的位置) GPEN_ROOT = "/root/GPEN" os.chdir(GPEN_ROOT) # 动态导入原推理模块(避免硬编码路径) import sys sys.path.insert(0, GPEN_ROOT) try: from inference_gpen import main as gpen_main except ImportError as e: print(f"❌ 无法导入GPEN推理模块:{e}") print("请确认当前路径为 /root/GPEN,且 inference_gpen.py 存在") exit(1) def get_image_files(folder_path): """获取文件夹内所有支持的图像文件(忽略大小写)""" folder = Path(folder_path) if not folder.exists(): raise FileNotFoundError(f"文件夹不存在:{folder_path}") patterns = ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.JPG", "*.JPEG", "*.PNG", "*.BMP"] files = [] for pattern in patterns: files.extend(folder.glob(pattern)) # 去重并排序,确保顺序一致 files = sorted(set(files)) return [str(f) for f in files if f.is_file()] def safe_enhance(input_path, output_path, args): """安全执行单张图增强,捕获异常不中断流程""" try: # 构造GPEN所需的命令行参数(模拟原脚本调用) # 注意:此处复用原脚本的argparse逻辑,不修改其内部 import subprocess cmd = [ "python", "inference_gpen.py", "--input", input_path, "--output", output_path ] if args.size: cmd.extend(["--size", str(args.size)]) if args.channel: cmd.extend(["--channel", str(args.channel)]) result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) if result.returncode == 0: print(f" 已处理:{Path(input_path).name} → {Path(output_path).name}") return True else: print(f" 处理失败:{Path(input_path).name}") print(f" 错误信息:{result.stderr[:200]}...") return False except Exception as e: print(f" 运行异常:{Path(input_path).name} — {e}") return False def main(): parser = argparse.ArgumentParser(description="GPEN 批量人像修复工具") parser.add_argument("--input", "-i", type=str, required=True, help="输入文件夹路径(必须)") parser.add_argument("--output", "-o", type=str, default="./batch_output", help="输出文件夹路径(默认:./batch_output)") parser.add_argument("--size", type=int, default=512, help="输出图像尺寸(默认:512,可选 256/512/1024)") parser.add_argument("--channel", type=int, default=3, help="通道数(默认:3,RGB)") parser.add_argument("--skip-existing", action="store_true", help="跳过已存在的输出文件(用于断点续跑)") args = parser.parse_args() # 创建输出目录 output_dir = Path(args.output) output_dir.mkdir(exist_ok=True) # 获取所有图像文件 image_files = get_image_files(args.input) if not image_files: print(f"❌ 未在 {args.input} 中找到支持的图像文件") return print(f" 扫描到 {len(image_files)} 张图像文件") print(f"⚙ 使用参数:尺寸={args.size}, 通道={args.channel}") print(f" 输出目录:{output_dir.absolute()}") print("-" * 50) # 逐张处理 success_count = 0 for idx, img_path in enumerate(image_files, 1): input_name = Path(img_path).name output_name = f"enhanced_{input_name}" output_path = output_dir / output_name # 跳过已存在文件(可选) if args.skip_existing and output_path.exists(): print(f"⏩ 已存在,跳过:{input_name}") continue print(f"[{idx}/{len(image_files)}] 正在处理:{input_name}") if safe_enhance(img_path, str(output_path), args): success_count += 1 print("-" * 50) print(f" 批量处理完成!成功 {success_count}/{len(image_files)} 张") if success_count < len(image_files): print(f"❗ 有 {len(image_files)-success_count} 张处理失败,请检查日志或图片格式") if __name__ == "__main__": main()3.2 脚本使用方法
保存脚本:将上述代码复制,保存为
/root/GPEN/batch_enhance.py准备照片:把待处理的照片统一放入一个文件夹,例如:
mkdir -p /root/photos_to_fix cp ~/Downloads/old_pics/*.jpg /root/photos_to_fix/运行批量处理(推荐首次用小样本测试):
cd /root/GPEN python batch_enhance.py --input /root/photos_to_fix --output /root/enhanced_results --size 512查看结果:
- 输出目录
/root/enhanced_results/下会生成enhanced_xxx.jpg等文件; - 每张图处理完成后终端都有明确提示( 或 );
- 失败图片会打印简要错误,方便定位问题。
- 输出目录
小贴士:如果某张图报错“no face detected”,说明GPEN未检出有效人脸(如侧脸过大、遮挡严重、非正面照),可单独用原脚本加
--det_size 640参数重试,或先用其他工具裁切。
4. 进阶技巧:让批量更智能
基础批量已够用,但若想进一步提效,这几个技巧值得掌握:
4.1 按分辨率分组处理
GPEN对不同尺寸输入效果有差异。老照片常为低分辨率(如640×480),而新手机图可能达4000×3000。统一用--size 512可能导致小图过度拉伸、大图细节丢失。
推荐做法:先用脚本自动分类,再分批处理:
# 查看所有图尺寸(一行命令) find /root/photos_to_fix -iname "*.jpg" -exec identify -format "%f %wx%h\n" {} \; | sort -k2 -n然后创建子文件夹:
/root/photos_to_fix/low_res/(宽/高 < 1000)/root/photos_to_fix/high_res/(宽/高 ≥ 1000)
分别运行:
python batch_enhance.py -i /root/photos_to_fix/low_res -o /root/out_low --size 256 python batch_enhance.py -i /root/photos_to_fix/high_res -o /root/out_high --size 10244.2 自动跳过非人像图
GPEN专为人像优化,处理风景、文字、截图效果不佳。可在批量前加简单人脸检测预筛:
# 在 batch_enhance.py 的 get_image_files 后添加 def has_face(img_path): try: img = cv2.imread(img_path) if img is None: return False gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 使用OpenCV内置级联检测器(轻量,不依赖facexlib) face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') faces = face_cascade.detectMultiScale(gray, 1.1, 4) return len(faces) > 0 except: return False # 使用时过滤 image_files = [f for f in image_files if has_face(f)]注:此功能需镜像中已预装
opencv-python(文档已确认存在),无需额外安装。
4.3 生成对比图合集(HTML可视化)
处理完所有图,快速生成一个本地网页,左右对比原图与增强图:
# 运行后生成 index.html,用浏览器打开即可浏览 cd /root/GPEN python -m http.server 8000 # 启动简易服务器 # 然后访问 http://localhost:8000/batch_output/ 查看或用以下脚本自动生成对比页(保存为gen_compare_html.py):
import os from pathlib import Path input_dir = Path("/root/photos_to_fix") output_dir = Path("/root/enhanced_results") html_path = output_dir / "compare.html" with open(html_path, "w", encoding="utf-8") as f: f.write("<html><head><title>GPEN修复对比</title><style>body{font-family:sans-serif;} .pair{margin:20px 0;} img{max-width:400px;vertical-align:top;}</style></head><body>") f.write("<h1>GPEN人像修复效果对比</h1>") for img_file in input_dir.glob("*.*"): if img_file.suffix.lower() in ['.jpg', '.jpeg', '.png']: orig_name = img_file.name enhanced_name = f"enhanced_{orig_name}" if (output_dir / enhanced_name).exists(): f.write(f'<div class="pair"><h3>{orig_name}</h3>') f.write(f'<img src="../photos_to_fix/{orig_name}" alt="原图"> → ') f.write(f'<img src="{enhanced_name}" alt="增强图"></div>') f.write("</body></html>") print(f" 对比网页已生成:file://{html_path.absolute()}")5. 常见问题与避坑指南
即使脚本写得再稳,实际运行中仍可能遇到典型问题。以下是基于真实测试总结的高频问题及解法:
5.1 “CUDA out of memory” 内存不足
现象:处理大图(如4K)时崩溃,报CUDA out of memory
原因:GPEN 1024模型显存占用约10GB,镜像默认分配可能不足
解法:
- 优先用
--size 512(显存占用约4GB,兼容多数显卡); - 若必须用1024,添加环境变量限制显存:
CUDA_VISIBLE_DEVICES=0 python batch_enhance.py -i ... -o ... --size 1024 - 或在脚本开头加入:
import os os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"
5.2 输出图全黑或空白
现象:输出文件存在,但打开是纯黑/纯白
原因:输入图色彩空间异常(如CMYK格式JPG)或位深度不匹配
解法:
- 用OpenCV预转换色彩空间(在
safe_enhance前插入):img = cv2.imread(input_path) if img is not None and len(img.shape) == 3 and img.shape[2] == 4: img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) # 透明通道转BGR cv2.imwrite(input_path + "_fixed.jpg", img) input_path = input_path + "_fixed.jpg"
5.3 处理速度慢,CPU占满
现象:GPU利用率低,CPU持续100%,进度缓慢
原因:subprocess启动新进程导致重复加载模型(每次调用都初始化)
解法(进阶):改用模块化调用,避免反复启动Python解释器。修改batch_enhance.py,直接调用GPEN内部函数:
# 替换 safe_enhance 函数为: from inference_gpen import infer from basicsr.utils import imwrite def fast_enhance(input_path, output_path, size=512): try: img = cv2.imread(input_path) if img is None: return False # 直接调用infer函数(需查看原脚本确认签名) enhanced = infer(img, size=size) # 此处需根据实际infer函数参数调整 imwrite(enhanced, output_path) return True except Exception as e: print(f"处理失败 {input_path}: {e}") return False提示:该方式需阅读
/root/GPEN/inference_gpen.py源码确认infer()函数定义。镜像中该文件结构清晰,通常位于if __name__ == '__main__':上方,可快速定位。
6. 总结
批量处理照片,本质不是追求“一次跑完1000张”,而是建立一套可靠、可复现、易维护的本地化工作流。本文分享的方法,没有引入新框架、不修改模型、不重写核心逻辑,只在GPEN原生能力之上,用最朴素的Python脚本做了三层增强:
- 自动化层:自动发现文件、过滤格式、管理路径;
- 健壮性层:异常捕获、日志反馈、断点续跑;
- 体验层:尺寸分组、人脸预筛、对比可视化。
你会发现,真正节省时间的,往往不是模型本身,而是让模型“听懂你的话”的那几行胶水代码。下次再面对一整个硬盘的老照片,你不再需要纠结“要不要修”,而是直接敲下命令,去泡杯茶,回来就看到焕然一新的相册。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。