FFT NPainting LaMa批量处理思路:脚本化调用实现自动化修复
1. 为什么需要批量处理?——从手动点击到自动化的必然选择
你有没有遇到过这样的场景:一张宣传图上有多个水印,需要逐个框选修复;几十张电商商品图里都要去掉模特手里的手机;或者一批老照片里统一清除划痕和噪点?每次打开WebUI、上传、画笔标注、点击“开始修复”、等待、下载……重复几十次,不仅耗时,还容易手误漏标。
FFT NPainting LaMa本身是一个功能扎实的图像修复WebUI工具,由科哥基于LaMa模型二次开发,支持高质量重绘、智能边缘融合与BGR自动转换。但它的默认交互是面向单图、人工操作的——这在工程落地中就成了瓶颈。
真正的生产力提升,不在于“能不能修”,而在于“能不能一口气修完一整批”。本文不讲模型原理,也不堆砌参数,就聚焦一个务实目标:把WebUI背后的能力“解放出来”,用Python脚本驱动,实现全自动、可复现、可调度的批量修复流程。你会看到:
- 如何绕过浏览器,直接调用WebUI的API接口
- 怎样构造符合要求的标注掩码(mask)并自动匹配原图
- 批量任务如何管理状态、捕获错误、保存结果
- 一套开箱即用的脚本结构,适配你自己的文件夹和命名习惯
全程无需修改源码,不依赖GUI,纯命令行驱动,小白也能照着跑通。
2. 核心思路:WebUI不是终点,而是服务端口
2.1 WebUI本质是一个FastAPI服务
很多人把start_app.sh启动的界面当成“软件”,其实它底层是一个标准的FastAPI后端服务。查看app.py或启动日志,你会发现它监听在http://0.0.0.0:7860,所有按钮点击背后,都是HTTP请求。
比如,当你在界面上点击“ 开始修复”,浏览器实际发出了这样一个POST请求:
POST /api/repair HTTP/1.1 Host: 127.0.0.1:7860 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary... ------WebKitFormBoundary... Content-Disposition: form-data; name="image"; filename="input.jpg" Content-Type: image/jpeg <binary image data> ------WebKitFormBoundary... Content-Disposition: form-data; name="mask"; filename="mask.png" Content-Type: image/png <binary mask data> ------WebKitFormBoundary...只要我们能模拟这个请求,就不需要打开浏览器,更不需要手动画笔——图像和掩码,全由脚本生成、封装、发送。
2.2 批量处理的三要素:图 + 掩码 + 调度
要让脚本替你干活,必须明确三个输入:
- 原图(image):你要修复的PNG/JPG文件,放在
inputs/目录下 - 掩码(mask):一张和原图同尺寸的灰度图,白色(255)区域代表要修复的部分,黑色(0)代表保留。它不是手动画的,而是程序自动生成的
- 调度逻辑(runner):遍历文件、配对图与掩码、发请求、检查响应、保存结果、记录日志
这三者构成闭环,缺一不可。下面我们就逐个拆解。
3. 实战:三步构建你的批量修复脚本
3.1 第一步:准备环境与验证API连通性
确保WebUI服务已在后台运行(bash start_app.sh),然后在终端执行以下命令测试基础连通性:
curl -X GET "http://127.0.0.1:7860/health"如果返回{"status":"ok"},说明服务就绪。这是后续所有操作的前提。
注意:如果你在远程服务器上运行,且从本地电脑调用,请将
127.0.0.1替换为服务器真实IP,并确认防火墙放行7860端口。
3.2 第二步:自动生成掩码——告别手动画笔
掩码质量直接决定修复效果。手动画几十张图的mask不现实,但我们可以用OpenCV+规则逻辑自动生成。以下是两个高频场景的掩码生成策略:
场景A:移除固定位置水印(如右下角LOGO)
假设所有图片右下角100×40像素区域都有水印,脚本可这样生成mask:
# generate_mask_by_position.py import cv2 import numpy as np import os def create_corner_mask(image_path, output_dir, corner="bottom_right", w=100, h=40): img = cv2.imread(image_path) h_img, w_img = img.shape[:2] # 创建全黑掩码 mask = np.zeros((h_img, w_img), dtype=np.uint8) if corner == "bottom_right": x1, y1 = w_img - w, h_img - h x2, y2 = w_img, h_img elif corner == "top_left": x1, y1 = 0, 0 x2, y2 = w, h # 填充白色矩形(需修复区域) cv2.rectangle(mask, (x1, y1), (x2, y2), 255, -1) # 保存掩码(与原图同名,加_mask后缀) basename = os.path.splitext(os.path.basename(image_path))[0] mask_path = os.path.join(output_dir, f"{basename}_mask.png") cv2.imwrite(mask_path, mask) print(f" 已生成掩码:{mask_path}") # 批量处理 for img_file in os.listdir("inputs/"): if img_file.lower().endswith((".png", ".jpg", ".jpeg")): create_corner_mask(f"inputs/{img_file}", "masks/")场景B:基于颜色/纹理自动检测水印区域
对于半透明、位置不固定的水印,可用HSV阈值+轮廓分析粗略定位:
# generate_mask_by_color.py def create_color_mask(image_path, output_dir, lower_hsv=(0, 0, 200), upper_hsv=(180, 30, 255)): img = cv2.imread(image_path) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 提取高亮度低饱和区域(常见于浅色水印) mask_hsv = cv2.inRange(hsv, lower_hsv, upper_hsv) # 形态学闭运算连接断裂区域 kernel = np.ones((5,5), np.uint8) mask_clean = cv2.morphologyEx(mask_hsv, cv2.MORPH_CLOSE, kernel) # 保存 basename = os.path.splitext(os.path.basename(image_path))[0] mask_path = os.path.join(output_dir, f"{basename}_mask.png") cv2.imwrite(mask_path, mask_clean)小贴士:生成的mask必须是单通道灰度图(
cv2.IMREAD_GRAYSCALE读取验证),尺寸必须与原图严格一致,否则API会报错。
3.3 第三步:编写主调度脚本——真正实现“一键批量”
下面是一份精简、健壮、带错误处理的批量调用脚本(batch_repair.py):
# batch_repair.py import requests import os import time import json from pathlib import Path API_URL = "http://127.0.0.1:7860/api/repair" INPUT_DIR = "inputs/" MASK_DIR = "masks/" OUTPUT_DIR = "outputs_batch/" # 创建输出目录 Path(OUTPUT_DIR).mkdir(exist_ok=True) def send_repair_request(image_path, mask_path): try: with open(image_path, "rb") as img_f, open(mask_path, "rb") as mask_f: files = { "image": (os.path.basename(image_path), img_f, "image/png"), "mask": (os.path.basename(mask_path), mask_f, "image/png"), } response = requests.post(API_URL, files=files, timeout=120) if response.status_code == 200: result = response.json() if result.get("success"): output_path = os.path.join(OUTPUT_DIR, result["filename"]) with open(output_path, "wb") as f: f.write(response.content) return True, output_path else: return False, result.get("error", "Unknown error from API") else: return False, f"HTTP {response.status_code}: {response.text[:100]}" except Exception as e: return False, f"Exception: {str(e)}" # 主流程 success_count = 0 failures = [] for img_file in os.listdir(INPUT_DIR): if not img_file.lower().endswith((".png", ".jpg", ".jpeg")): continue basename = os.path.splitext(img_file)[0] image_path = os.path.join(INPUT_DIR, img_file) mask_path = os.path.join(MASK_DIR, f"{basename}_mask.png") if not os.path.exists(mask_path): print(f" 缺少掩码:{mask_path},跳过") failures.append(f"{img_file} -> missing mask") continue print(f"🔧 正在处理:{img_file}") success, msg = send_repair_request(image_path, mask_path) if success: print(f" 成功:{msg}") success_count += 1 else: print(f"❌ 失败:{msg}") failures.append(f"{img_file} -> {msg}") # 避免请求过于密集(可选) time.sleep(0.5) # 输出汇总 print("\n" + "="*50) print(" 批量处理完成汇总") print(f" 成功:{success_count} 张") print(f"❌ 失败:{len(failures)} 张") if failures: print("\n失败详情:") for f in failures: print(f" • {f}")运行方式:
python batch_repair.py它会:
- 自动配对
inputs/xxx.jpg与masks/xxx_mask.png - 发送标准multipart请求到WebUI API
- 将返回的修复图保存至
outputs_batch/ - 记录成功/失败明细,便于排查
进阶提示:你可以将此脚本接入定时任务(
crontab)或工作流引擎(如Airflow),实现“每天凌晨自动清理昨日截图水印”。
4. 效果优化与避坑指南
4.1 掩码不是越“准”越好,而是要“略大”
LaMa模型依赖上下文推理。如果掩码刚好卡在物体边缘,修复后可能出现生硬接缝。实测经验表明:掩码应比目标区域外扩5–15像素,让模型有足够缓冲区做自然过渡。
修改生成脚本中的矩形坐标即可:
# 原来 x1, y1 = w_img - w, h_img - h # 改为(外扩10像素) x1, y1 = max(0, w_img - w - 10), max(0, h_img - h - 10) x2, y2 = min(w_img, w_img + 10), min(h_img, h_img + 10)4.2 处理大图?先缩放再修复,保质又提速
WebUI对超大图(>3000px)支持不稳定,且耗时陡增。建议预处理:
# resize_preprocess.py def resize_if_large(image_path, max_dim=2000): img = cv2.imread(image_path) h, w = img.shape[:2] if max(h, w) > max_dim: scale = max_dim / max(h, w) new_w, new_h = int(w * scale), int(h * scale) resized = cv2.resize(img, (new_w, new_h)) cv2.imwrite(image_path, resized) print(f"🖼 已缩放:{w}x{h} → {new_w}x{new_h}")在批量前运行一次,大幅提升吞吐量。
4.3 错误排查速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
HTTP 422 Unprocessable Entity | 图像或掩码不是PNG格式,或尺寸不匹配 | 用cv2.imread(x, cv2.IMREAD_GRAYSCALE)验证掩码是否为单通道 |
Connection refused | WebUI未运行,或端口被占 | ps aux | grep app.py检查进程;lsof -ti:7860查端口 |
| 返回空白图或黑图 | 掩码全黑(没标任何区域) | 检查掩码生成逻辑,用cv2.imshow临时预览mask |
| 修复后颜色偏灰/失真 | 输入图为BGR但未正确转换 | 确认WebUI已启用BGR自动转换(v1.0.0默认开启) |
5. 更进一步:构建你的修复流水线
脚本化只是起点。当需求变复杂,你可以轻松扩展:
- 多阶段修复:第一轮去水印 → 下载结果 → 第二轮精细修人像瑕疵 → 合并结果
- 条件分支:根据文件名关键词(如
_logo、_text)自动切换掩码生成策略 - 结果质检:用SSIM指标自动比对修复前后相似度,低于阈值则告警重试
- 集成到CI/CD:PR提交新图时,自动触发修复并生成对比报告
这一切,都建立在“WebUI可编程”这一基础上。你不再是一个被动使用者,而是整个图像修复能力的调度者。
6. 总结:自动化不是替代人,而是让人专注真正重要的事
FFT NPainting LaMa的WebUI设计初衷是降低使用门槛,而脚本化调用则是释放其工程潜力。本文带你走完了从“点鼠标”到“写脚本”的关键一步:
- 看清本质:WebUI = FastAPI服务,一切操作皆可API化
- 掌握核心:图 + 掩码 + 请求,三者闭环即成批量能力
- 落地实用:提供可直接运行的生成脚本与调度脚本,附带避坑指南
- 展望延伸:从单次批量,走向可持续、可监控、可集成的修复流水线
技术的价值,从来不在炫技,而在解决真实重复劳动。当你把几十分钟的手动操作压缩成一条命令,省下的不仅是时间,更是持续创造的注意力。
现在,就去你的inputs/目录放下第一张图,运行python batch_repair.py吧。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。