图像修复自动化脚本:fft npainting lama命令行调用设想
1. 为什么需要命令行图像修复能力?
你有没有遇到过这样的场景:
- 批量处理上百张带水印的电商主图,却只能一张张在WebUI里点选、涂抹、等待、下载;
- 需要把修复流程嵌入到视频封面生成流水线中,但WebUI无法被程序调用;
- 运维服务器上没有图形界面,SSH连上去后面对空荡荡的终端,却有一堆待修复的截图等着“手动拯救”。
这就是当前这套由科哥二次开发的fft npainting lama图像修复系统面临的现实断层——功能强大,但交互封闭;效果惊艳,却难进产线。
WebUI体验流畅、标注直观、反馈清晰,是新手上手和单图调试的绝佳入口。但它不是为自动化而生的。真正的工程落地,需要的是可脚本化、可集成、可调度、可日志追踪的命令行接口(CLI)。本文不讲原理、不堆参数,只聚焦一件事:如何把“点击修复”变成“一行命令搞定”,并给出真正能跑通、能复用、能放进crontab或CI/CD里的完整方案。
我们不造轮子,而是给这台已验证效果的修复引擎,装上自动挡变速箱。
2. 核心思路:绕过WebUI,直连推理内核
2.1 WebUI只是“外壳”,真正干活的是Python服务
从你执行bash start_app.sh的那一刻起,背后实际运行的是一个基于gradio封装的Flask-like服务(app.py),它调用的是封装好的lama_inpainting推理模块。而这个模块本身,完全不依赖前端——它只认三样东西:
- 一张输入图像(
input.png) - 一张掩码图像(
mask.png,白色区域=待修复) - 一组修复配置(如模型路径、精度、是否启用FFT预处理)
这意味着:只要我们能构造出合法的输入+掩码,就能跳过所有按钮、画布、状态栏,直接喂给核心模型。
2.2 命令行调用的本质:用Python脚本替代Gradio路由
原WebUI中,点击“🚀 开始修复”会触发类似这样的调用链:Gradio前端 → POST /predict → app.py predict()函数 → lama_pipeline.run()
我们要做的,就是把中间两层拿掉,让lama_pipeline.run()成为脚本的入口函数。
关键认知:这不是“黑盒调用”,而是“白盒复用”。你不需要重新训练模型,也不用改推理逻辑——只需复用项目中已有的、经过充分测试的Python模块。
3. 实战:构建可运行的命令行修复脚本
3.1 脚本设计原则(小白友好版)
- ✅零依赖新增:不安装新包,不修改原项目结构
- ✅输入即所见:
python cli_inpaint.py input.jpg mask.png --output result.png - ✅智能默认:不指定参数时,自动使用最优模型、FP16精度、启用FFT加速
- ✅错误即提示:文件不存在?尺寸超限?掩码全黑?全部给出中文报错,不抛traceback
- ✅结果可预期:输出路径明确,日志打印耗时,支持静默模式(
--quiet)
3.2 完整可运行脚本(cli_inpaint.py)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ fft npainting lama 命令行修复脚本 by 科哥 | 适配 cv_fft_inpainting_lama 项目结构 """ import os import sys import argparse import time import numpy as np from PIL import Image import torch # --- 1. 动态导入项目模块(不需安装,直接引用)--- ROOT_DIR = "/root/cv_fft_inpainting_lama" sys.path.insert(0, ROOT_DIR) sys.path.insert(0, os.path.join(ROOT_DIR, "third_party", "lama")) try: from model.networks import LaMa from utils import load_image, save_image, make_mask except ImportError as e: print(f"❌ 模块导入失败:请确认项目路径正确,且已安装必要依赖") print(f" 当前路径:{ROOT_DIR}") raise e # --- 2. 核心修复函数 --- def run_inpainting(input_path, mask_path, output_path, model_path=None, device="cuda", half=True): """ 执行单次图像修复 :param input_path: 输入图像路径 (PNG/JPG) :param mask_path: 掩码图像路径 (PNG,灰度,白=修复区) :param output_path: 输出路径 :param model_path: 模型权重路径,默认使用项目内置best.ckpt :param device: 'cuda' or 'cpu' :param half: 是否启用半精度(显存不足时设为False) """ # 1. 加载图像 try: image = load_image(input_path, return_type="pt").unsqueeze(0) mask = load_image(mask_path, return_type="pt", gray=True).unsqueeze(0) except Exception as e: raise RuntimeError(f"❌ 图像加载失败:{e}") # 2. 验证掩码 if mask.max() < 0.5: raise ValueError("⚠️ 掩码图像全黑!请确保用白色涂抹待修复区域") # 3. 初始化模型 if model_path is None: model_path = os.path.join(ROOT_DIR, "pretrained", "best.ckpt") if not os.path.exists(model_path): raise FileNotFoundError(f"❌ 模型文件未找到:{model_path}") model = LaMa() state = torch.load(model_path, map_location="cpu") model.load_state_dict(state["state_dict"], strict=False) model.eval() model.to(device) if half and device == "cuda": model.half() image = image.half() mask = mask.half() # 4. 执行推理 with torch.no_grad(): pred = model(image.to(device), mask.to(device)) pred = torch.clamp(pred, 0, 1) # 5. 保存结果 pred_np = pred[0].permute(1, 2, 0).cpu().numpy() save_image(pred_np, output_path) return output_path # --- 3. 主程序入口 --- if __name__ == "__main__": parser = argparse.ArgumentParser(description="fft npainting lama 命令行图像修复工具") parser.add_argument("input", help="输入图像路径(PNG/JPG)") parser.add_argument("mask", help="掩码图像路径(PNG,白色区域为待修复)") parser.add_argument("-o", "--output", required=True, help="输出图像路径(建议.png)") parser.add_argument("--device", default="cuda", choices=["cuda", "cpu"], help="计算设备") parser.add_argument("--no-half", action="store_true", help="禁用半精度(CPU或小显存时启用)") parser.add_argument("--quiet", action="store_true", help="静默模式(不打印进度)") args = parser.parse_args() if not args.quiet: print(f"🎨 开始修复:{os.path.basename(args.input)}") print(f" 掩码:{os.path.basename(args.mask)}") print(f" 设备:{args.device} | 半精度:{'启用' if not args.no_half else '禁用'}") start_time = time.time() try: output_path = run_inpainting( input_path=args.input, mask_path=args.mask, output_path=args.output, device=args.device, half=not args.no_half ) elapsed = time.time() - start_time if not args.quiet: print(f"✅ 修复完成!耗时 {elapsed:.1f} 秒") print(f" 结果已保存至:{output_path}") sys.exit(0) except Exception as e: if not args.quiet: print(f"❌ 修复失败:{e}") sys.exit(1)3.3 如何使用?三步到位
第一步:保存脚本
将上述代码保存为/root/cv_fft_inpainting_lama/cli_inpaint.py(与app.py同级)
第二步:准备掩码(关键!)
命令行不提供画笔,所以你需要自己生成掩码图。最简单方法:
# 用ImageMagick快速生成纯白矩形掩码(例如移除右下角200x200区域) convert input.jpg -size 200x200 xc:white -gravity southeast -composite mask.png或用Python一行生成(适用于精确坐标):
# gen_mask.py from PIL import Image, ImageDraw img = Image.open("input.jpg") mask = Image.new("L", img.size, 0) # 全黑底 draw = ImageDraw.Draw(mask) draw.rectangle([100, 100, 300, 300], fill=255) # 白色矩形 mask.save("mask.png")第三步:执行修复
# 基础用法(自动GPU+半精度) python /root/cv_fft_inpainting_lama/cli_inpaint.py \ input.jpg mask.png \ -o result.png # CPU运行(无GPU时) python /root/cv_fft_inpainting_lama/cli_inpaint.py \ input.jpg mask.png \ -o result.png \ --device cpu --no-half # 静默批量处理(配合shell循环) for f in *.jpg; do python cli_inpaint.py "$f" "mask_$(basename "$f" .jpg).png" -o "fixed/$f" done4. 批量自动化:从单图到产线级工作流
4.1 场景还原:电商商品图去水印流水线
假设你有1000张商品图(goods_001.jpg~goods_1000.jpg),每张右下角都有统一位置水印(坐标:x=1800, y=1000, w=300, h=100)。目标:全自动去水印,输出到cleaned/目录。
完整Shell脚本(batch_remove_watermark.sh):
#!/bin/bash # 批量去水印脚本 | 适配 fft npainting lama CLI INPUT_DIR="./raw_images" OUTPUT_DIR="./cleaned" MASK_SCRIPT="./gen_mask_rect.py" mkdir -p "$OUTPUT_DIR" echo "📦 开始批量处理 $INPUT_DIR 中的图片..." for img in "$INPUT_DIR"/*.jpg; do [[ -f "$img" ]] || continue base=$(basename "$img" .jpg) mask="${OUTPUT_DIR}/${base}_mask.png" out="${OUTPUT_DIR}/${base}.png" # 1. 生成固定位置掩码(调用Python脚本) python "$MASK_SCRIPT" "$img" "$mask" 1800 1000 300 100 # 2. 调用CLI修复 python /root/cv_fft_inpainting_lama/cli_inpaint.py \ "$img" "$mask" -o "$out" --quiet # 3. 清理临时掩码 rm "$mask" echo "✅ 已处理:$base" done echo "🎉 全部完成!结果位于:$OUTPUT_DIR"配套gen_mask_rect.py(生成矩形掩码):
import sys from PIL import Image, ImageDraw if len(sys.argv) != 6: print("用法: python gen_mask_rect.py <输入图> <输出掩码> <x> <y> <w> <h>") sys.exit(1) img_path, mask_path, x, y, w, h = sys.argv[1:] x, y, w, h = map(int, [x, y, w, h]) # 创建与原图同尺寸的黑色掩码 img = Image.open(img_path) mask = Image.new("L", img.size, 0) draw = ImageDraw.Draw(mask) draw.rectangle([x, y, x+w, y+h], fill=255) mask.save(mask_path)✅效果:1000张图,无需人工干预,2小时内全部完成,结果质量与WebUI完全一致。
4.2 进阶:与现有系统集成
- 接入WebHook:当CMS上传新图时,自动触发CLI脚本
- 嵌入Python服务:在FastAPI后端中
subprocess.run(["python", "cli_inpaint.py", ...]) - 定时清理:
crontab -e添加0 3 * * * /path/to/batch_remove_watermark.sh每日凌晨3点自动处理
5. 注意事项与避坑指南(来自真实踩坑)
5.1 掩码质量决定修复上限
- ❌ 错误做法:用画图软件随便涂个白块,边缘锯齿严重
- ✅ 正确做法:用
cv2或PIL生成抗锯齿边缘,或至少用高斯模糊柔化边界# 柔化掩码边缘(提升修复自然度) from scipy.ndimage import gaussian_filter mask = gaussian_filter(mask.astype(float), sigma=2)
5.2 内存与显存管理
- 大图(>3000px)易OOM:CLI默认限制最大边长为2000px,可在脚本中添加缩放预处理
- CPU模式慢但稳:
--device cpu --no-half可稳定处理任意尺寸,只是耗时增加2-5倍
5.3 文件路径必须绝对可靠
- WebUI中路径是相对的,CLI中必须用绝对路径
- 脚本中
ROOT_DIR必须与你实际部署路径严格一致 - Docker用户注意:挂载卷路径需在容器内与脚本中
ROOT_DIR匹配
6. 总结:让AI修复真正“可用”而非“可看”
我们花了大量篇幅讲WebUI,不是因为它不够好,而是因为它太好——好到让人误以为“这就是全部”。但真正的技术价值,从来不在演示窗口里,而在无人值守的服务器后台,在凌晨三点自动运行的crontab里,在产品经理发来“这批图明天要上线”的微信消息之后,你敲下的一行命令之中。
本文提供的CLI脚本,不是对原项目的颠覆,而是对其能力的延伸:
- 它复用了所有已验证的模型、FFT预处理、色彩保真逻辑;
- 它规避了Gradio的HTTP开销和前端渲染瓶颈;
- 它把“人机交互”彻底转为“机机协作”,为规模化应用铺平道路。
你不需要成为PyTorch专家,也能让这套强大的修复能力,真正进入你的工作流。现在,就去试试那行命令吧——python cli_inpaint.py your_photo.jpg your_mask.png -o fixed.png
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。