FFT NPainting LaMa API接口扩展:Python调用初步尝试
1. 为什么需要API调用?从WebUI到自动化工作流
你有没有遇到过这样的场景:每天要处理上百张带水印的电商主图,或者批量清理用户上传照片里的杂物、文字、瑕疵?每次打开浏览器、上传图片、手动画圈、点击修复、下载结果……重复操作几十次后,手指酸了,时间也悄悄溜走了。
这就是WebUI的天然局限——它为人服务,却难以融入机器的工作节奏。而真正的生产力跃迁,往往发生在“人不再需要点鼠标”的那一刻。
FFT NPainting LaMa这套图像修复系统,底层基于强大的LaMa模型(Large Mask Inpainting),在去除物体、擦除水印、修复划痕等任务上表现稳定。科哥做的二次开发不仅封装了易用的Web界面,更关键的是——它默认就支持标准HTTP API接口。这意味着,你完全可以用Python脚本一键触发修复,把整个流程变成for image in image_list: repair(image)这样几行代码的事。
本文不讲模型原理,也不堆砌参数配置。我们就用最直白的方式,带你完成三件事:
- 看懂这个API长什么样、能干什么
- 写出第一个能跑通的Python调用脚本
- 解决实际调用中90%新手会卡住的坑(比如mask怎么生成、文件路径怎么传、响应怎么解析)
全程不需要改一行源码,不需要装额外依赖,只要你会写requests.post(),就能让这台“图像修复工厂”为你24小时自动运转。
2. API能力速览:它到底能帮你做什么
FFT NPainting LaMa的API不是摆设,而是真正为工程落地设计的。它不只支持“上传图+返回图”这种基础模式,还覆盖了真实业务中高频出现的多种需求:
2.1 核心能力一览
| 功能 | 是否支持 | 说明 |
|---|---|---|
| 单图修复 | 上传原图 + mask图 → 返回修复结果 | |
| 原图+mask合并上传 | 支持将mask以白色区域直接画在原图上(节省一次上传) | |
| 指定输出尺寸 | 可控制修复后图像宽高,避免失真 | |
| 异步处理模式 | 大图可提交后轮询状态,不阻塞主线程 | |
| 批量任务队列 | 通过简单循环即可实现百图连修(无需改服务端) | |
| 错误精准反馈 | 返回JSON含具体错误码(如"mask_empty"、"image_too_large") |
注意:所有接口均基于标准RESTful设计,无认证要求(内网部署场景下默认开放),请求地址统一为
http://<your-server-ip>:7860/api/xxx
2.2 和WebUI的对应关系
你熟悉的WebUI操作,在API里都有明确映射:
- WebUI里的“拖拽上传图片” → API的
POST /api/upload_image - “用画笔涂白区域” → API的
POST /api/upload_mask(或直接传mask_data字段) - “点击开始修复” → API的
POST /api/repair - “查看右侧结果图” → API响应体中的
result_url或base64_image
这种一一对应的设计,让你学一次WebUI操作,就自然理解API逻辑,零认知成本迁移。
3. 第一个Python调用:三步跑通全流程
我们不搞虚的。下面这段代码,就是你在自己机器上复制粘贴、改两处IP、放一张图,就能立刻看到效果的最小可行示例。
3.1 准备工作:确认服务已启动
先确保你的WebUI服务正在运行(参考手册中的bash start_app.sh)。终端里看到WebUI已启动提示后,记下服务器IP(比如192.168.1.100)和端口7860。
如果你在本地开发机测试,且服务也在本机运行,请用
http://127.0.0.1:7860;如果服务部署在远程服务器,请用服务器真实IP(非0.0.0.0)。
3.2 代码实现:清晰分步,拒绝黑盒
import requests import base64 from PIL import Image, ImageDraw, ImageOps import io # ====== 配置区(只需改这里)====== SERVER_URL = "http://192.168.1.100:7860" # ← 改成你的服务器IP INPUT_IMAGE_PATH = "./test_input.jpg" # ← 改成你本地的测试图路径 OUTPUT_DIR = "./repair_results/" # ← 保存结果的本地文件夹 # ================================== def pil_to_base64(img, format="PNG"): """PIL Image转base64字符串""" buffered = io.BytesIO() img.save(buffered, format=format) return base64.b64encode(buffered.getvalue()).decode() def create_simple_mask(image_path, x, y, width, height): """在指定位置生成矩形mask(白色区域)""" img = Image.open(image_path).convert("RGB") mask = Image.new("L", img.size, 0) # 全黑mask draw = ImageDraw.Draw(mask) draw.rectangle([x, y, x+width, y+height], fill=255) # 白色矩形 return mask # 步骤1:读取原图并生成简单mask(例如遮盖右下角一块) original = Image.open(INPUT_IMAGE_PATH) mask = create_simple_mask(INPUT_IMAGE_PATH, x=original.width-200, y=original.height-150, width=180, height=130) # 步骤2:构造API请求数据 payload = { "image": pil_to_base64(original), "mask": pil_to_base64(mask), "output_width": original.width, "output_height": original.height } # 步骤3:发送修复请求 response = requests.post(f"{SERVER_URL}/api/repair", json=payload) # 步骤4:解析响应 if response.status_code == 200: result_data = response.json() if result_data.get("status") == "success": # 解码base64结果图并保存 result_img_data = base64.b64decode(result_data["result_image"]) result_img = Image.open(io.BytesIO(result_img_data)) output_path = f"{OUTPUT_DIR}repaired_{int(time.time())}.png" result_img.save(output_path) print(f" 修复成功!结果已保存至:{output_path}") else: print(f"❌ 修复失败:{result_data.get('message', '未知错误')}") else: print(f"❌ HTTP错误:{response.status_code} - {response.text}")3.3 运行前必看:两个关键细节
mask必须是单通道灰度图(L模式)
很多人第一次调用失败,是因为直接用了RGB图当mask。记住:mask里只有黑白,白色(255)=要修复的区域,黑色(0)=保留的区域。上面代码中Image.new("L", ...)和fill=255就是关键。图像尺寸别超限
手册里提到“建议2000x2000以内”,API同样遵守。如果你传入一张5000x4000的图,接口会直接返回{"status":"error","message":"image_too_large"}。简单加个预处理:if original.width > 2000 or original.height > 2000: ratio = min(2000/original.width, 2000/original.height) new_size = (int(original.width*ratio), int(original.height*ratio)) original = original.resize(new_size, Image.Resampling.LANCZOS) mask = mask.resize(new_size, Image.Resampling.NEAREST)
跑通这段代码,你就已经跨过了API调用最大的门槛——剩下的,只是让它更健壮、更智能。
4. 实战增强:让脚本真正可用
上面的“Hello World”版脚本能跑,但离生产还有距离。这一节,我们加入三个真正解决痛点的功能:自动抠图生成mask、批量处理多张图、异常重试机制。
4.1 智能mask生成:不用手画,也能精准标注
手动画mask太慢?我们可以用OpenCV快速实现“自动框选”。比如移除水印,通常水印在固定位置(右下角、左上角),用模板匹配就能定位:
import cv2 import numpy as np def detect_watermark_area(image_path, template_path="./watermark_template.png"): """用模板匹配定位水印区域,返回(x,y,w,h)""" img = cv2.imread(image_path) template = cv2.imread(template_path, 0) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED) threshold = 0.7 loc = np.where(res >= threshold) if len(loc[0]) > 0: # 取第一个匹配点(可优化为取置信度最高) y, x = loc[0][0], loc[1][0] h, w = template.shape[:2] return (x, y, w, h) return None # 未找到 # 使用示例 area = detect_watermark_area(INPUT_IMAGE_PATH) if area: x, y, w, h = area mask = create_simple_mask(INPUT_IMAGE_PATH, x, y, w, h)小技巧:对于固定位置水印(如公司Logo),甚至可以不用模板匹配,直接写死坐标:
mask = create_simple_mask(..., x=10, y=10, w=120, h=60),快准稳。
4.2 批量处理:一次修复一百张图
把单图逻辑包进循环,就是批量处理:
import os import time def batch_repair(image_folder, output_folder): """批量修复文件夹内所有图片""" os.makedirs(output_folder, exist_ok=True) image_files = [f for f in os.listdir(image_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg'))] for i, filename in enumerate(image_files, 1): print(f"[{i}/{len(image_files)}] 正在处理:{filename}") full_path = os.path.join(image_folder, filename) try: # 复用前面的修复逻辑 original = Image.open(full_path) # ...(生成mask、构造payload、发送请求) if result_data.get("status") == "success": # 保存时用原文件名,避免时间戳混乱 name, ext = os.path.splitext(filename) output_path = os.path.join(output_folder, f"{name}_repaired.png") result_img.save(output_path) print(f" 已保存:{output_path}") else: print(f" 跳过:{filename} - {result_data.get('message')}") except Exception as e: print(f"❌ 处理失败 {filename}:{str(e)}") # 避免请求过于密集(可选) time.sleep(0.5) # 调用 batch_repair("./input_images/", "./output_repaired/")4.3 稳定性加固:网络波动、服务重启都不怕
真实环境里,网络抖动、服务短暂不可用很常见。加一层简单重试,脚本就从“偶尔能用”变成“基本可靠”:
import time def robust_api_call(url, payload, max_retries=3, delay=2): """带重试的API调用""" for attempt in range(max_retries): try: response = requests.post(url, json=payload, timeout=120) if response.status_code == 200: return response elif response.status_code == 503: print(f" 服务暂不可用,{delay}秒后重试...(第{attempt+1}次)") time.sleep(delay) continue else: print(f"❌ HTTP {response.status_code} 错误") return response except requests.exceptions.RequestException as e: print(f"❌ 网络错误:{e},{delay}秒后重试...(第{attempt+1}次)") time.sleep(delay) print("❌ 已达到最大重试次数,放弃请求") return None # 使用 response = robust_api_call(f"{SERVER_URL}/api/repair", payload) if response and response.status_code == 200: # 处理成功响应 pass5. 常见问题与避坑指南
即使按教程走,新手也常在几个地方反复踩坑。这里列出真实发生过的高频问题及解法:
5.1 “404 Not Found” —— 接口地址错了
- ❌ 错误写法:
http://127.0.0.1:7860/api/repair/(末尾多了斜杠) - 正确写法:
http://127.0.0.1:7860/api/repair - 验证方法:直接在浏览器访问
http://你的IP:7860/docs,能看到FastAPI自动生成的接口文档页,说明服务和路由都正常。
5.2 “mask_empty”错误 —— mask没传对
- 最常见原因:mask图不是纯黑白,而是带灰度过渡(比如用PS羽化画笔画的)。
- 解决方案:强制二值化
mask = mask.convert("L") mask = mask.point(lambda p: 255 if p > 128 else 0, mode='1') # 非黑即白5.3 结果图发虚、颜色偏 —— 图像模式不匹配
- WebUI内部统一处理为RGB,但如果你传入BGR(OpenCV默认)、CMYK(某些PNG)格式,会导致色彩错乱。
- 统一转RGB:
original = Image.open(INPUT_IMAGE_PATH) if original.mode in ("RGBA", "LA", "P"): original = original.convert("RGBA") background = Image.new("RGB", original.size, (255, 255, 255)) background.paste(original, mask=original.split()[-1]) original = background elif original.mode != "RGB": original = original.convert("RGB")5.4 大图超时 —— 调整服务端超时设置(可选)
如果经常处理大图(>3000px),默认60秒超时可能不够。可临时修改服务启动脚本中的--timeout-graceful-shutdown参数,或在start_app.sh里增加:
nohup python app.py --host 0.0.0.0 --port 7860 --timeout-graceful-shutdown 300 > app.log 2>&1 &6. 总结:从手动点击到自动流水线,只差这一步
回看开头那个“每天处理上百张图”的场景,现在你手里已经有了一套可立即投入使用的自动化方案:
- 用OpenCV自动识别水印位置,生成mask;
- 用循环遍历文件夹,批量提交修复请求;
- 用重试机制兜底网络和临时故障;
- 用PIL统一图像模式,规避色彩异常。
这不再是“理论上可行”,而是你电脑上正在运行的几行Python代码。它不会替代你的审美判断,但会把你从重复劳动中彻底解放出来——把时间留给真正需要人类创造力的地方:比如设计新模板、分析修复效果、优化业务流程。
API的价值,从来不在技术本身,而在于它把一个强大工具,变成了你工作流里一个可编程、可调度、可集成的标准部件。FFT NPainting LaMa做到了这一点,而你,已经拿到了开启它的钥匙。
下一步,你可以:
- 把这个脚本包装成命令行工具(
python repair.py --input ./imgs --output ./out) - 接入企业微信/钉钉机器人,修复完成自动推送通知
- 和你的CMS系统对接,用户上传图片后自动去水印再发布
路已经铺好,现在,轮到你出发了。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。