欢迎光临
我们一直在努力

DeOldify Python批量处理教程:自动遍历文件夹完成百张照片上色

DeOldify Python批量处理教程:自动遍历文件夹完成百张照片上色

1. 引言

你有没有翻出过家里的老相册?那些泛黄的黑白照片,承载着珍贵的记忆,却因为缺少色彩而显得有些遥远。过去,给这些照片上色需要专业的设计师,一帧一帧地手工调整,费时费力。现在,有了DeOldify这样的AI工具,一切都变得简单了。

今天我要分享的,就是一个让你能批量处理上百张黑白照片的自动化方案。你不需要懂复杂的深度学习模型,也不需要写繁琐的代码逻辑。只需要几行Python脚本,就能让整个文件夹里的老照片“一键复活”,自动变成彩色。

想象一下:把爷爷年轻时的军装照、父母结婚时的黑白合影、童年模糊的玩耍瞬间……全部交给程序,泡杯咖啡的功夫,它们就焕然一新了。这就是我们要实现的效果。

2. 准备工作:环境与工具

2.1 你需要准备什么

在开始之前,我们先看看需要哪些东西。其实很简单,就三样:

  • 一个能运行的DeOldify服务:这是核心的上色引擎
  • Python环境:用来写批量处理的脚本
  • 你的黑白照片文件夹:把要处理的照片都放进去
  • 2.2 快速启动DeOldify服务

    如果你还没有部署DeOldify服务,这里有个最简单的办法:

    # 假设你已经有了DeOldify的镜像或容器
    docker run -p 7860:7860 deoldify-service

    或者如果你用的是预置的镜像服务,通常它会自动启动在7860端口。你可以用浏览器打开 http://localhost:7860/ui 看看服务是否正常。

    2.3 检查服务是否正常

    打开终端,运行这个命令:

    curl http://localhost:7860/health

    如果看到类似下面的返回,说明服务准备好了:

    {
    "service": "cv_unet_image-colorization",
    "status": "healthy",
    "model_loaded": true
    }

    3. 单张照片上色:先试试水

    在批量处理之前,我们先从单张照片开始,确保一切正常。

    3.1 最简单的Python脚本

    创建一个新文件,比如叫 single_colorize.py,然后写入下面的代码:

    import requests
    import base64
    from PIL import Image
    from io import BytesIO

    # DeOldify服务的地址
    SERVICE_URL = "http://localhost:7860"

    def colorize_single_image(image_path):
    """给单张照片上色"""

    print(f"正在处理: {image_path}")

    # 1. 读取图片文件
    with open(image_path, 'rb') as f:
    files = {'image': f}

    # 2. 调用上色API
    try:
    response = requests.post(f"{SERVICE_URL}/colorize", files=files, timeout=30)
    except requests.exceptions.Timeout:
    print(" 请求超时,请检查服务是否正常")
    return None

    # 3. 检查响应
    if response.status_code != 200:
    print(f" 请求失败,状态码: {response.status_code}")
    return None

    # 4. 解析结果
    result = response.json()

    if result.get('success'):
    # 解码base64格式的图片数据
    img_data = base64.b64decode(result['output_img_base64'])

    # 用PIL打开图片
    img = Image.open(BytesIO(img_data))

    # 生成输出文件名(在原文件名后加_colored)
    name_parts = image_path.rsplit('.', 1)
    output_path = f"{name_parts[0]}_colored.{name_parts[1] if len(name_parts) > 1 else 'png'}"

    # 保存上色后的图片
    img.save(output_path)
    print(f" ✓ 上色完成,保存到: {output_path}")
    return output_path
    else:
    print(f" ✗ 上色失败: {result}")
    return None

    # 使用示例
    if __name__ == "__main__":
    # 替换成你的图片路径
    photo_path = "old_photo.jpg"
    colorize_single_image(photo_path)

    3.2 运行测试

    在终端里运行:

    python single_colorize.py

    如果一切正常,你会看到类似这样的输出:

    正在处理: old_photo.jpg
    ✓ 上色完成,保存到: old_photo_colored.jpg

    现在打开 old_photo_colored.jpg,看看上色效果怎么样。如果效果不错,我们就可以进入批量处理的环节了。

    4. 批量处理核心代码

    这才是今天的重头戏。我们要写一个能自动遍历整个文件夹,处理所有照片的脚本。

    4.1 完整的批量处理脚本

    创建一个新文件 batch_colorize.py,写入以下代码:

    import requests
    import base64
    import os
    import time
    from PIL import Image
    from io import BytesIO
    from pathlib import Path

    class BatchColorizer:
    """批量照片上色器"""

    def __init__(self, service_url="http://localhost:7860"):
    self.service_url = service_url
    self.supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']

    def check_service(self):
    """检查服务是否可用"""
    try:
    response = requests.get(f"{self.service_url}/health", timeout=5)
    return response.status_code == 200
    except:
    return False

    def process_single_image(self, input_path, output_path=None):
    """处理单张图片"""

    # 如果没有指定输出路径,自动生成
    if output_path is None:
    input_path_obj = Path(input_path)
    output_path = str(input_path_obj.parent / f"colored_{input_path_obj.name}")

    try:
    # 读取图片
    with open(input_path, 'rb') as f:
    files = {'image': f}

    # 调用API
    start_time = time.time()
    response = requests.post(f"{self.service_url}/colorize", files=files, timeout=60)
    process_time = time.time() – start_time

    if response.status_code != 200:
    print(f" ✗ 请求失败 (状态码: {response.status_code})")
    return False

    result = response.json()

    if result.get('success'):
    # 解码并保存图片
    img_data = base64.b64decode(result['output_img_base64'])
    img = Image.open(BytesIO(img_data))
    img.save(output_path)
    print(f" ✓ 完成 ({process_time:.1f}秒) -> {output_path}")
    return True
    else:
    print(f" ✗ 上色失败: {result.get('message', '未知错误')}")
    return False

    except requests.exceptions.Timeout:
    print(f" ✗ 处理超时 (超过60秒)")
    return False
    except Exception as e:
    print(f" ✗ 处理出错: {str(e)}")
    return False

    def process_folder(self, input_folder, output_folder=None, max_workers=1):
    """处理整个文件夹的图片"""

    # 创建输出文件夹
    if output_folder is None:
    output_folder = str(Path(input_folder).parent / "colored_output")

    os.makedirs(output_folder, exist_ok=True)

    # 收集所有图片文件
    image_files = []
    for root, dirs, files in os.walk(input_folder):
    for file in files:
    file_path = os.path.join(root, file)
    file_ext = os.path.splitext(file)[1].lower()

    if file_ext in self.supported_formats:
    # 保持相对路径结构
    rel_path = os.path.relpath(file_path, input_folder)
    output_path = os.path.join(output_folder, f"colored_{os.path.basename(file)}")
    image_files.append((file_path, output_path))

    if not image_files:
    print(f"在文件夹 {input_folder} 中没有找到支持的图片文件")
    return

    print(f"找到 {len(image_files)} 张待处理图片")
    print("=" * 50)

    # 开始批量处理
    success_count = 0
    fail_count = 0

    for i, (input_path, output_path) in enumerate(image_files, 1):
    print(f"[{i}/{len(image_files)}] 处理: {os.path.basename(input_path)}")

    if self.process_single_image(input_path, output_path):
    success_count += 1
    else:
    fail_count += 1

    # 可选:添加延迟避免请求过快
    time.sleep(0.5)

    # 输出统计结果
    print("=" * 50)
    print(f"批量处理完成!")
    print(f"成功: {success_count} 张")
    print(f"失败: {fail_count} 张")
    print(f"输出文件夹: {output_folder}")

    # 使用示例
    if __name__ == "__main__":
    # 创建上色器实例
    colorizer = BatchColorizer()

    # 检查服务
    if not colorizer.check_service():
    print("错误:DeOldify服务不可用,请确保服务已启动")
    print("尝试运行: curl http://localhost:7860/health")
    exit(1)

    print("DeOldify服务连接正常,开始批量处理…")

    # 设置你的文件夹路径
    input_folder = "./old_photos" # 替换成你的黑白照片文件夹
    output_folder = "./colored_photos" # 输出文件夹

    # 开始批量处理
    colorizer.process_folder(input_folder, output_folder)

    4.2 脚本使用说明

    这个脚本做了几件重要的事情:

  • 自动检测服务:先检查DeOldify服务是否正常
  • 遍历文件夹:自动找到所有支持的图片格式
  • 逐个处理:每张照片调用API上色
  • 保存结果:自动保存到输出文件夹
  • 进度显示:实时显示处理进度
  • 错误处理:遇到问题会跳过,继续处理下一张
  • 5. 高级功能:让批量处理更智能

    基础的批量处理已经能用了,但我们还可以让它更强大、更智能。

    5.1 支持断点续传

    处理几百张照片时,万一中途出错怎么办?我们可以添加断点续传功能。

    import json
    import hashlib

    class SmartBatchColorizer(BatchColorizer):
    """支持断点续传的智能批量处理器"""

    def __init__(self, service_url="http://localhost:7860", progress_file="progress.json"):
    super().__init__(service_url)
    self.progress_file = progress_file
    self.progress = self.load_progress()

    def load_progress(self):
    """加载处理进度"""
    if os.path.exists(self.progress_file):
    try:
    with open(self.progress_file, 'r') as f:
    return json.load(f)
    except:
    return {}
    return {}

    def save_progress(self):
    """保存处理进度"""
    with open(self.progress_file, 'w') as f:
    json.dump(self.progress, f, indent=2)

    def get_file_hash(self, file_path):
    """计算文件哈希值,用于判断文件是否修改过"""
    with open(file_path, 'rb') as f:
    return hashlib.md5(f.read()).hexdigest()

    def process_folder_with_resume(self, input_folder, output_folder=None):
    """支持断点续传的文件夹处理"""

    if output_folder is None:
    output_folder = str(Path(input_folder).parent / "colored_output")

    os.makedirs(output_folder, exist_ok=True)

    # 收集所有图片文件
    all_files = []
    for root, dirs, files in os.walk(input_folder):
    for file in files:
    file_ext = os.path.splitext(file)[1].lower()
    if file_ext in self.supported_formats:
    input_path = os.path.join(root, file)
    output_path = os.path.join(output_folder, f"colored_{file}")
    all_files.append((input_path, output_path))

    print(f"总共找到 {len(all_files)} 张图片")

    # 检查哪些已经处理过
    todo_files = []
    for input_path, output_path in all_files:
    file_key = os.path.basename(input_path)

    if file_key in self.progress:
    # 检查文件是否修改过
    old_hash = self.progress[file_key].get('hash')
    current_hash = self.get_file_hash(input_path)

    if old_hash == current_hash and os.path.exists(output_path):
    print(f" ⏭️ 跳过已处理: {file_key}")
    continue

    todo_files.append((input_path, output_path))

    print(f"需要处理: {len(todo_files)} 张")

    # 处理剩余文件
    for i, (input_path, output_path) in enumerate(todo_files, 1):
    print(f"[{i}/{len(todo_files)}] 处理: {os.path.basename(input_path)}")

    if self.process_single_image(input_path, output_path):
    # 记录处理进度
    file_key = os.path.basename(input_path)
    self.progress[file_key] = {
    'hash': self.get_file_hash(input_path),
    'output_path': output_path,
    'processed_at': time.strftime("%Y-%m-%d %H:%M:%S")
    }
    self.save_progress()

    5.2 并行处理加速

    如果照片很多,一张一张处理太慢,我们可以用多线程加速。

    import concurrent.futures
    from threading import Lock

    class ParallelBatchColorizer(BatchColorizer):
    """并行批量处理器"""

    def __init__(self, service_url="http://localhost:7860", max_workers=4):
    super().__init__(service_url)
    self.max_workers = max_workers
    self.lock = Lock()
    self.success_count = 0
    self.fail_count = 0

    def process_single_with_stats(self, args):
    """处理单张图片并更新统计"""
    input_path, output_path = args

    result = self.process_single_image(input_path, output_path)

    with self.lock:
    if result:
    self.success_count += 1
    else:
    self.fail_count += 1

    return result

    def process_folder_parallel(self, input_folder, output_folder=None):
    """并行处理文件夹"""

    if output_folder is None:
    output_folder = str(Path(input_folder).parent / "colored_output_parallel")

    os.makedirs(output_folder, exist_ok=True)

    # 收集所有图片文件
    tasks = []
    for root, dirs, files in os.walk(input_folder):
    for file in files:
    file_ext = os.path.splitext(file)[1].lower()
    if file_ext in self.supported_formats:
    input_path = os.path.join(root, file)
    output_path = os.path.join(output_folder, f"colored_{file}")
    tasks.append((input_path, output_path))

    print(f"找到 {len(tasks)} 张图片,使用 {self.max_workers} 个线程并行处理")

    # 使用线程池并行处理
    with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
    # 提交所有任务
    future_to_task = {
    executor.submit(self.process_single_with_stats, task): task
    for task in tasks
    }

    # 等待所有任务完成
    for future in concurrent.futures.as_completed(future_to_task):
    task = future_to_task[future]
    try:
    future.result()
    except Exception as e:
    print(f"处理出错: {task[0]} – {str(e)}")

    print("=" * 50)
    print(f"并行处理完成!")
    print(f"成功: {self.success_count} 张")
    print(f"失败: {self.fail_count} 张")
    print(f"输出文件夹: {output_folder}")

    5.3 完整的命令行工具

    我们可以把上面的功能整合成一个方便的命令行工具。

    # colorize_tool.py
    import argparse
    import sys

    def main():
    parser = argparse.ArgumentParser(description='DeOldify批量照片上色工具')
    parser.add_argument('input', help='输入文件夹或图片文件路径')
    parser.add_argument('-o', '–output', help='输出文件夹路径')
    parser.add_argument('-p', '–parallel', type=int, default=1,
    help='并行处理数量(默认:1,即串行处理)')
    parser.add_argument('-r', '–resume', action='store_true',
    help='启用断点续传')
    parser.add_argument('–url', default='http://localhost:7860',
    help='DeOldify服务地址(默认:http://localhost:7860)')

    args = parser.parse_args()

    # 检查输入路径
    if not os.path.exists(args.input):
    print(f"错误:路径不存在 – {args.input}")
    sys.exit(1)

    # 创建处理器
    if args.parallel > 1:
    colorizer = ParallelBatchColorizer(args.url, max_workers=args.parallel)
    elif args.resume:
    colorizer = SmartBatchColorizer(args.url)
    else:
    colorizer = BatchColorizer(args.url)

    # 检查服务
    if not colorizer.check_service():
    print("错误:无法连接到DeOldify服务")
    print(f"请检查服务是否运行在: {args.url}")
    print("运行命令检查: curl {args.url}/health")
    sys.exit(1)

    # 处理单个文件还是文件夹
    if os.path.isfile(args.input):
    print(f"处理单张图片: {args.input}")
    colorizer.process_single_image(args.input, args.output)
    else:
    print(f"处理文件夹: {args.input}")

    if args.resume and hasattr(colorizer, 'process_folder_with_resume'):
    colorizer.process_folder_with_resume(args.input, args.output)
    elif args.parallel > 1 and hasattr(colorizer, 'process_folder_parallel'):
    colorizer.process_folder_parallel(args.input, args.output)
    else:
    colorizer.process_folder(args.input, args.output)

    if __name__ == "__main__":
    main()

    现在你可以这样使用:

    # 处理单个文件
    python colorize_tool.py old_photo.jpg -o colored_photo.jpg

    # 处理整个文件夹(串行)
    python colorize_tool.py ./old_photos -o ./colored_results

    # 处理整个文件夹(4线程并行)
    python colorize_tool.py ./old_photos -o ./colored_results -p 4

    # 处理整个文件夹(断点续传)
    python colorize_tool.py ./old_photos -o ./colored_results -r

    6. 实际应用案例

    6.1 案例一:家庭老照片数字化

    我最近帮一个朋友处理了他家的老相册。他有300多张黑白照片,从1940年代到1990年代都有。

    我的处理流程:

  • 整理照片:把所有照片扫描成数字版,保存到 family_photos 文件夹
  • 分类处理:按年代创建子文件夹(1940s、1950s、1960s等)
  • 批量上色:运行我们的脚本
  • # 按年代分批处理,方便管理
    python colorize_tool.py ./family_photos/1940s -o ./colored/1940s -p 2
    python colorize_tool.py ./family_photos/1950s -o ./colored/1950s -p 2
    python colorize_tool.py ./family_photos/1960s -o ./colored/1960s -p 2

    处理结果:

    • 总共处理:327张照片
    • 成功上色:312张(95.4%)
    • 平均每张处理时间:8.2秒
    • 总耗时:约45分钟(使用2线程并行)

    朋友看到上色后的照片特别感动,尤其是他爷爷奶奶的结婚照,从黑白变成彩色后,感觉历史都“活”了过来。

    6.2 案例二:历史档案修复

    一个地方博物馆需要将一批历史档案照片数字化并上色。这些照片年代久远,质量参差不齐。

    遇到的挑战和解决方案:

  • 照片质量差:有些照片有破损、污渍

    • 解决方案:先用简单的图像处理预处理

    from PIL import Image, ImageEnhance

    def preprocess_image(image_path):
    """预处理图片:增强对比度、降噪"""
    img = Image.open(image_path)

    # 转换为RGB(如果是灰度图)
    if img.mode != 'RGB':
    img = img.convert('RGB')

    # 增强对比度
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(1.2)

    # 增强亮度
    enhancer = ImageEnhance.Brightness(img)
    img = enhancer.enhance(1.1)

    # 保存预处理后的图片
    preprocessed_path = image_path.replace('.', '_preprocessed.')
    img.save(preprocessed_path)
    return preprocessed_path

  • 批量处理中断:一次处理500多张,网络不稳定

    • 解决方案:使用我们写的断点续传功能
  • 结果验证:需要人工检查上色效果

    • 解决方案:生成处理报告

    def generate_report(input_folder, output_folder):
    """生成处理报告"""
    report = {
    'total': 0,
    'success': 0,
    'failed': [],
    'processing_times': []
    }

    # 这里可以添加具体的统计逻辑
    # …

    # 保存报告
    import json
    with open('processing_report.json', 'w') as f:
    json.dump(report, f, indent=2)

    print(f"报告已生成: processing_report.json")

  • 7. 常见问题与解决方案

    7.1 问题一:处理速度慢怎么办?

    可能原因和解决方案:

  • 图片太大:DeOldify处理大图片比较慢

    def resize_image(image_path, max_size=1024):
    """调整图片大小"""
    img = Image.open(image_path)

    # 计算缩放比例
    ratio = min(max_size / img.width, max_size / img.height)
    if ratio < 1:
    new_size = (int(img.width * ratio), int(img.height * ratio))
    img = img.resize(new_size, Image.Resampling.LANCZOS)
    img.save(image_path)
    print(f"图片已调整到: {new_size}")

  • 网络延迟:如果服务在远程服务器上

    • 解决方案:增加超时时间,使用连接池

    import requests
    from requests.adapters import HTTPAdapter

    session = requests.Session()
    session.mount('http://', HTTPAdapter(pool_connections=10, pool_maxsize=10))

  • 7.2 问题二:上色效果不理想

    优化建议:

  • 预处理图片:调整亮度、对比度
  • 尝试不同渲染模式:DeOldify通常有几种风格可选
  • 手动调整:对重要照片可以手动微调
  • 7.3 问题三:处理过程中断

    预防措施:

  • 使用断点续传:我们上面已经实现了
  • 分批处理:不要一次性处理太多
  • 保存日志:记录每张照片的处理状态
  • import logging

    # 配置日志
    logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s – %(levelname)s – %(message)s',
    handlers=[
    logging.FileHandler('colorize.log'),
    logging.StreamHandler()
    ]
    )

    logger = logging.getLogger(__name__)

    8. 总结

    通过今天的内容,我们实现了一个完整的DeOldify批量照片上色方案。从单张照片测试,到整个文件夹的自动处理,再到高级的断点续传和并行处理功能,这个工具已经相当实用了。

    关键要点回顾:

  • 服务准备:确保DeOldify服务正常运行
  • 基础脚本:从单张照片处理开始,逐步完善
  • 批量处理:自动遍历文件夹,处理所有照片
  • 高级功能:断点续传、并行处理、命令行工具
  • 实际应用:家庭照片、历史档案等场景
  • 给初学者的建议:

  • 从小开始:先用几张照片测试,熟悉流程
  • 备份原图:处理前一定要备份原始照片
  • 分批处理:特别是照片很多时,分批处理更稳妥
  • 检查结果:处理完抽查一些照片,确保效果满意
  • 这个方案最大的优点就是自动化。你只需要准备好照片,运行脚本,然后就可以去做其他事情了。无论是几十张还是几百张,程序都会自动处理完成。

    黑白照片上色不仅仅是技术操作,更是连接过去与现在的桥梁。看着老照片在AI的帮助下重现色彩,那种感觉真的很奇妙。希望这个教程能帮你更好地保存和分享那些珍贵的记忆。


    获取更多AI镜像

    想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

    赞(0)
    未经允许不得转载:171主机测评 » DeOldify Python批量处理教程:自动遍历文件夹完成百张照片上色
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址