🔥 还在为图片修复头疼?这个开源工具让AI修图变得像PS一样简单

🔥 还在为图片修复头疼?这个开源工具让AI修图变得像PS一样简单

🔥 还在为图片修复头疼?这个开源工具让AI修图变得像PS一样简单

实测可商用!一款支持40+模型的本地图片修复神器,再也不用担心隐私泄露


一、为什么这个项目值得关注

1.1 图像修复的痛点

在日常工作和创意设计中,你是否遇到过这些情况:

  • 照片里突然闯入的路人,想完美抹除却总是留下痕迹
  • 老照片破损,想要修复却不知道从何下手
  • 想给图片扩展画面,却担心AI生成的内容不自然
  • 使用在线修图工具时,总担心自己的图片被滥用

这些问题的核心在于:缺乏一个本地化、免费、功能强大的图像修复解决方案

1.2 IOPaint 是什么

IOPaint 是由开发者 Sanster 开源的一个自托管图像修复(Inpainting)和扩展(Outpainting)工具。它的核心特点是:

项目地址:https://github.com/Sanster/IOPaint
主要语言:Python
支持平台:Windows、MacOS、Linux

1.3 四大核心优势

优势 详细说明
🔒 隐私安全 所有处理都在本地完成,图片不会上传到任何服务器
🎨 模型丰富 支持 40+ 种 AI 模型,包括 LaMa、MAT、LDM 等主流算法
💻 跨平台 支持 Windows、Mac、Linux 系统
🆓 完全免费 开源项目,可自由使用和二次开发

1.4 与其他工具的对比

对比维度          IOPaint        在线工具         Photoshop AI
---------------------------------------------------------------
隐私保护           ✅ 本地处理      ❌ 上传云端        ✅ 本地处理
模型数量           40+            1-2              内置
使用成本           免费           按次收费          订阅制
学习曲线           低             低               高
扩展功能           丰富           有限             有限
开源可定制         ✅              ❌                ❌

二、环境搭建:5分钟快速上手

2.1 系统要求

在开始之前,确认你的电脑满足以下基本要求:

最低配置:
- 显卡:NVIDIA GTX 1060 4GB 或同等性能
- 内存:8GB
- 硬盘:10GB 可用空间

推荐配置:
- 显卡:NVIDIA RTX 3060 8GB 或更高
- 内存:16GB
- 硬盘:20GB 可用空间(用于存储模型)

2.2 安装方式一:Docker(推荐新手)

如果你熟悉 Docker,这是最简单的方式:

# 拉取最新镜像
docker pull sanster/iopaint

# 运行容器
docker run -d \
    --name iopaint \
    -p 8080:8080 \
    -v ./output:/app/output \
    -v ./models:/root/.cache/torch/hub/models \
    sanster/iopaint

# 访问 http://localhost:8080 即可使用

2.3 安装方式二:Python 虚拟环境

步骤 1:检查 Python 环境

# 检查 Python 版本(需要 3.8 或更高)
python --version

# 如果没有 Python,先安装
# Ubuntu/Debian:
sudo apt update && sudo apt install python3 python3-pip python3-venv

# Windows: 从 python.org 下载安装包

步骤 2:创建虚拟环境

# 创建名为 iopaint_env 的虚拟环境
python -m venv iopaint_env

# 激活虚拟环境
# Linux/Mac:
source iopaint_env/bin/activate

# Windows:
iopaint_env\Scripts\activate

步骤 3:安装 IOPaint

# 升级 pip
pip install --upgrade pip

# 安装 IOPaint
pip install iopaint

# 如果你使用 NVIDIA 显卡,安装 CUDA 版本
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

2.4 安装方式三:手动安装(开发者版本)

# 克隆仓库
git clone https://github.com/Sanster/IOPaint.git
cd IOPaint

# 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# 安装依赖
pip install -r requirements.txt

# 安装开发依赖(可选)
pip install -r requirements-dev.txt

2.5 验证安装

# 运行 IOPaint
iopaint run --host 0.0.0.0 --port 8080

如果一切正常,你应该能看到类似输出:

========================================
   IOPaint v1.x.x 启动成功!
   访问地址: http://localhost:8080
========================================

现在,打开浏览器访问 http://localhost:8080 ,你应该能看到 IOPaint 的 Web 界面。


三、核心功能详解

3.1 功能架构概览

IOPaint 提供了完整的图像修复解决方案,主要包括以下功能模块:

┌─────────────────────────────────────────────────┐
│                  IOPaint 界面                    │
├─────────────────────────────────────────────────┤
│  📷 图像导入        │  🎨 模型选择              │
│  ✏️ 涂抹遮罩        │  ⚙️ 参数调整              │
│  🔧 图像编辑        │  💾 导出保存              │
└─────────────────────────────────────────────────┘

3.2 支持的 AI 模型

IOPaint 支持多种先进的图像修复算法,下面详细介绍:

3.2.1 LaMa(快速且效果稳定)

模型名称:LaMa
适用场景:通用图像修复
显存需求:约 4GB
处理速度:快
特点:对边缘处理较好,适合大部分场景

代码示例 – 使用 LaMa 模型:

from iopaint.api import IOService
from iopaint.schema import ModelConfig

# 初始化服务
service = IOService()

# 配置模型
config = ModelConfig(
    model_name="lama",  # 使用 LaMa 模型
    device="cuda",       # 使用 GPU 加速
    model_path=None      # 自动下载模型
)

# 加载图像和遮罩
image = service.load_image("input.jpg")
mask = service.load_mask("mask.png")

# 执行修复
result = service.inpaint(image, mask, config)

# 保存结果
service.save_image(result, "output.jpg")

3.2.2 MAT(细节丰富)

模型名称:MAT(MATNet)
适用场景:需要保留细节的高质量修复
显存需求:约 6GB
处理速度:中等
特点:能更好地保留纹理细节

代码示例 – 使用 MAT 模型:

from iopaint.api import IOService
from iopaint.schema import ModelConfig, HDStrategy

config = ModelConfig(
    model_name="mat",
    device="cuda",
    # 高清修复策略
    hd_strategy=HDStrategy.ORIGINAL,
    hd_strategy_crop_margin=32,
    hd_strategy_crop_size=512,
    # 修复相关参数
    l2_zero_thresh=0.5,
    use_cudnn=True
)

service = IOService()
result = service.inpaint(image, mask, config)

3.2.3 LDPM(处理大面积缺失)

模型名称:LDPM(Latent Diffusion Prior)
适用场景:大面积缺失修复、创意生成
显存需求:约 8GB
处理速度:较慢
特点:生成能力强,适合创意场景

代码示例 – 使用 LDPM 模型:

config = ModelConfig(
    model_name="ldpm",
    device="cuda",
    # 控制生成的多样性
    ddim_steps=50,
    guidance_scale=7.5,
    # 随机种子(固定可复现)
    seed=42
)

result = service.inpaint(image, mask, config)

3.2.4 支持模型完整列表

模型名称 用途 显存需求 推荐场景
lama 通用修复 4GB 日常使用首选
mat 细节修复 6GB 高清图片
sd1.5 通用生成 4GB 创意扩展
sd2 高清生成 6GB 高质量输出
instruct-pix2pix 指令编辑 6GB 文本引导编辑
plugin-remove-bg 背景移除 2GB 抠图
plugin-rembg 背景移除 2GB 抠图备选

3.3 图像编辑功能

3.3.1 遮罩工具

IOPaint 提供了专业的遮罩编辑功能:

# 遮罩创建示例
from iopaint.schema import BrushConfig

brush_config = BrushConfig(
    size=30,           # 画笔大小
    mode="erase",      # erase 或 fill
    hardness=0.8,      # 边缘硬度
    smooth_level=3     # 平滑级别
)

3.3.2 图像扩展(Outpainting)

支持向图像四周扩展内容:

# 扩展图像示例
from iopaint.schema import OutpaintConfig

outpaint_config = OutpaintConfig(
    direction="right",      # 扩展方向
    pixels=256,             # 扩展像素数
    model_name="sd1.5",     # 使用的模型
    prompt="seamless continuation of the scene"
)

result = service.outpaint(image, outpaint_config)

3.3.3 背景移除

# 背景移除示例
from iopaint.api import BackgroundRemover

remover = BackgroundRemover(model_name="u2net")

# 移除背景,返回透明图像
result = remover.remove(image, return_mask=False)

# 只返回遮罩
mask_only = remover.remove(image, return_mask=True)

3.4 参数调整技巧

不同的参数设置会产生截然不同的效果:

from iopaint.schema import InpaintRequest

# 创建修复请求
request = InpaintRequest(
    # === 基础参数 ===
    image=image,              # 原图
    mask=mask,                # 遮罩
    model="lama",             # 模型选择

    # === 生成参数 ===
    prompt="",                # 文本提示(某些模型需要)
    negative_prompt="blurry, low quality",  # 负面提示
    guidance_scale=7.5,       # 生成引导强度(1-20)

    # === 高级参数 ===
    hd_strategy="ORIGINAL",   # 高清处理策略
    hd_strategy_crop_size=512,  # 裁剪大小
    sd_steps=50,              # 采样步数

    # === 控制参数 ===
    crossattend_uniform=False,
    controlnet_model=None,
    controlnet_weight=1.0
)

四、实战教程:从入门到精通

4.1 教程一:去除照片中的路人

场景:你在景点拍照,但画面中突然闯入了一个路人。

4.1.1 准备图片

首先,准备一张需要处理的图片:

import cv2
import numpy as np
from PIL import Image

# 读取图片
image_path = "tourist_photo.jpg"
image = Image.open(image_path)

# 检查图片尺寸
print(f"图片尺寸: {image.size}")
print(f"图片模式: {image.mode}")

# 如果图片太大,先缩小(加快处理速度)
max_size = 1024
if max(image.size) > max_size:
    ratio = max_size / max(image.size)
    new_size = (int(image.size[0] * ratio), int(image.size[1] * ratio))
    image = image.resize(new_size, Image.LANCZOS)
    print(f"已调整为: {new_size}")

4.1.2 创建遮罩

用代码创建一个简单的遮罩:

# 创建一个与图片相同大小的遮罩(黑色 = 不修复,白色 = 修复)
mask = Image.new("L", image.size, 0)

# 在遮罩上绘制要修复的区域
from PIL import ImageDraw

draw = ImageDraw.Draw(mask)

# 假设路人位置在图片中心附近
# 绘制一个圆形区域(可以根据实际情况调整)
center_x, center_y = image.size[0] // 2, image.size[1] // 2
radius = 100

# 画一个白色的圆表示要修复的区域
draw.ellipse(
    [center_x - radius, center_y - radius,
     center_x + radius, center_y + radius],
    fill=255
)

# 保存遮罩查看
mask.save("mask_circle.png")

实际上,在 IOPaint 的 Web 界面中,你可以直接用画笔涂抹选择区域,更加直观方便。

4.1.3 执行修复

from iopaint.api import IOService
from iopaint.schema import ModelConfig

# 初始化服务
service = IOService()

# 配置模型 - LaMa 速度快,效果好
config = ModelConfig(
    model_name="lama",
    device="cuda",  # 使用 GPU
    # 如果没有 GPU,改为 device="cpu",但速度会很慢
)

# 执行修复
result = service.inpaint(image, mask, config)

# 保存结果
result.save("result_no_stranger.jpg")

print("修复完成!")

4.1.4 完整脚本

"""
图片修复脚本 - 去除路人
使用方法:python remove_object.py --input 输入图片 --output 输出图片
"""

import argparse
from pathlib import Path
from PIL import Image, ImageDraw
from iopaint.api import IOService
from iopaint.schema import ModelConfig


def create_mask(image_size, regions):
    """
    根据给定的区域创建遮罩

    参数:
        image_size: (width, height) 图片尺寸
        regions: 区域列表,每个区域为 (x, y, w, h) 或 (x, y, r)
    返回:
        遮罩图像
    """
    mask = Image.new("L", image_size, 0)
    draw = ImageDraw.Draw(mask)

    for region in regions:
        if len(region) == 3:
            # 圆形区域 (x, y, radius)
            x, y, r = region
            draw.ellipse([x-r, y-r, x+r, y+r], fill=255)
        else:
            # 矩形区域 (x, y, w, h)
            x, y, w, h = region
            draw.rectangle([x, y, x+w, y+h], fill=255)

    return mask


def remove_objects(image_path, output_path, regions, model="lama"):
    """
    去除图片中的指定物体

    参数:
        image_path: 输入图片路径
        output_path: 输出图片路径
        regions: 要去除的区域列表
        model: 使用的模型名称
    """
    # 加载图片
    image = Image.open(image_path).convert("RGB")

    # 创建遮罩
    mask = create_mask(image.size, regions)

    # 初始化服务
    service = IOService()
    config = ModelConfig(model_name=model, device="cuda")

    # 执行修复
    result = service.inpaint(image, mask, config)

    # 保存结果
    result.save(output_path)
    print(f"✅ 已保存到: {output_path}")


# 主程序入口
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="图片物体去除工具")
    parser.add_argument("--input", "-i", required=True, help="输入图片路径")
    parser.add_argument("--output", "-o", default="output.jpg", help="输出图片路径")
    parser.add_argument("--model", "-m", default="lama", help="使用的模型")

    # 可以添加多个矩形或圆形区域
    # 格式: x,y,w,h (矩形) 或 x,y,r (圆形)
    parser.add_argument("--regions", "-r", nargs="+", default=[],
                        help="区域坐标,如: 100,100,50,50")

    args = parser.parse_args()

    # 解析区域参数
    parsed_regions = []
    for region in args.regions:
        coords = list(map(int, region.split(",")))
        if len(coords) == 4:
            # 矩形:转换为 (x, y, w, h) 格式
            parsed_regions.append(tuple(coords))
        elif len(coords) == 3:
            # 圆形:转换为 (x, y, r) 格式
            parsed_regions.append(tuple(coords))

    remove_objects(args.input, args.output, parsed_regions, args.model)

使用示例:

# 去除一个矩形区域的物体
python remove_object.py -i photo.jpg -o result.jpg -r "100,100,80,80"

# 去除多个区域
python remove_object.py -i photo.jpg -o result.jpg -r "100,100,50,50" "300,200,40,40"

# 使用圆形区域(圆形需要3个参数:x, y, radius)
python remove_object.py -i photo.jpg -o result.jpg -r "200,200,60"

4.2 教程二:老照片修复

场景:有一张破损的老照片,想要修复划痕和缺失部分。

4.2.1 分析老照片的问题

from PIL import Image, ImageFilter
import numpy as np

def analyze_old_photo(image_path):
    """分析老照片的问题"""
    image = Image.open(image_path).convert("RGB")

    # 转换为 numpy 数组进行分析
    img_array = np.array(image)

    # 检测问题区域
    # 1. 低对比度检测
    gray = np.mean(img_array, axis=2)
    contrast = np.std(gray)

    # 2. 噪点检测
    noise_level = np.std(gray[1:] - gray[:-1])  # 简单的边缘噪声估计

    # 3. 颜色退化检测
    r_mean, g_mean, b_mean = np.mean(img_array, axis=(0,1))

    print(f"对比度分数: {contrast:.2f}")
    print(f"噪点等级: {noise_level:.2f}")
    print(f"颜色偏移: R={r_mean:.1f}, G={g_mean:.1f}, B={b_mean:.1f}")

    # 评估照片状态
    if contrast < 30:
        print("⚠️ 照片对比度较低,建议先增强对比度")
    if noise_level > 15:
        print("⚠️ 检测到较多噪点")

    return image


# 分析照片
analyze_old_photo("old_photo.jpg")

4.2.2 照片预处理

from PIL import Image, ImageEnhance, ImageFilter

def preprocess_old_photo(image_path, output_path):
    """
    预处理老照片
    包括:去噪、对比度增强、色彩校正
    """
    image = Image.open(image_path)

    # === 步骤1:去噪 ===
    # 使用中值滤波去除小的噪点
    denoised = image.filter(ImageFilter.MedianFilter(size=3))

    # === 步骤2:对比度增强 ===
    enhancer = ImageEnhance.Contrast(denoised)
    enhanced = enhancer.enhance(1.5)  # 1.5倍对比度

    # === 步骤3:亮度调整 ===
    enhancer = ImageEnhance.Brightness(enhanced)
    brightened = enhancer.enhance(1.1)  # 稍微提亮

    # === 步骤4:色彩校正 ===
    enhancer = ImageEnhance.Color(brightened)
    color_corrected = enhancer.enhance(1.2)

    # === 步骤5:锐化 ===
    sharpened = color_corrected.filter(
        ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3)
    )

    # 保存预处理结果
    sharpened.save(output_path)
    print(f"预处理完成: {output_path}")

    return sharpened


# 执行预处理
preprocessed = preprocess_old_photo("old_photo.jpg", "old_photo_preprocessed.jpg")

4.2.3 创建智能遮罩

import cv2
import numpy as np
from PIL import Image

def create_smart_mask(image, sensitivity=30):
    """
    自动检测照片中需要修复的区域

    参数:
        image: PIL Image 对象
        sensitivity: 检测灵敏度(值越大检测越多)
    """
    # 转换为灰度图
    gray = np.array(image.convert("L"))

    # 使用自适应阈值检测暗区和亮区
    # 这些区域通常是划痕、污渍或缺失部分

    # 检测暗区域(可能是污渍或划痕)
    dark_mask = gray < sensitivity
    dark_regions = dark_mask.astype(np.uint8) * 255

    # 检测亮区域(可能是反光或氧化)
    bright_mask = gray > (255 - sensitivity)
    bright_regions = bright_mask.astype(np.uint8) * 255

    # 合并两个遮罩
    combined = np.maximum(dark_regions, bright_regions)

    # 形态学操作 - 膨胀和腐蚀,使遮罩更加平滑
    kernel = np.ones((5, 5), np.uint8)
    combined = cv2.dilate(combined, kernel, iterations=1)
    combined = cv2.erode(combined, kernel, iterations=1)

    # 中值滤波去除孤立噪点
    combined = cv2.medianBlur(combined, 5)

    return Image.fromarray(combined)


# 创建自动遮罩
auto_mask = create_smart_mask(preprocessed, sensitivity=40)

# 混合遮罩:使用自动检测 + 手动绘制
# 保存自动检测结果供参考
auto_mask.save("auto_detected_mask.png")
print("自动检测遮罩已保存")

4.2.4 执行修复

from iopaint.api import IOService
from iopaint.schema import ModelConfig

def restore_old_photo(image_path, mask_path, output_path, model="mat"):
    """
    修复老照片

    参数:
        image_path: 预处理后的照片路径
        mask_path: 遮罩路径
        output_path: 输出路径
        model: 使用的模型
    """
    # 加载图片和遮罩
    image = Image.open(image_path).convert("RGB")
    mask = Image.open(mask_path).convert("L")

    # 初始化服务
    service = IOService()

    # MAT 模型对细节保留更好,适合老照片修复
    config = ModelConfig(
        model_name=model,
        device="cuda",
        # 高清策略
        hd_strategy="ORIGINAL",
        l2_zero_thresh=0.5
    )

    # 执行修复
    result = service.inpaint(image, mask, config)

    # 保存结果
    result.save(output_path)
    print(f"✅ 修复完成: {output_path}")

    return result


# 执行修复
restored = restore_old_photo(
    "old_photo_preprocessed.jpg",
    "mask_for_restoration.png",  # 你可以用画笔手动绘制遮罩
    "old_photo_restored.jpg",
    model="mat"  # MAT 模型保留更多细节
)

4.2.5 完整的老照片修复流程

"""
老照片修复完整流程
"""

import cv2
import numpy as np
from PIL import Image, ImageEnhance, ImageFilter
from iopaint.api import IOService
from iopaint.schema import ModelConfig


class OldPhotoRestorer:
    """老照片修复类"""

    def __init__(self, device="cuda"):
        self.device = device
        self.service = IOService()

    def preprocess(self, image):
        """图像预处理"""
        # 去噪
        denoised = image.filter(ImageFilter.MedianFilter(size=3))

        # 增强对比度
        enhanced = ImageEnhance.Contrast(denoised).enhance(1.5)

        # 调整亮度
        brightened = ImageEnhance.Brightness(enhanced).enhance(1.1)

        # 色彩校正
        color_corrected = ImageEnhance.Color(brightened).enhance(1.2)

        # 锐化
        sharpened = color_corrected.filter(
            ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3)
        )

        return sharpened

    def create_mask(self, image):
        """创建修复遮罩"""
        gray = np.array(image.convert("L"))

        # 自动检测问题区域
        dark_regions = (gray < 30).astype(np.uint8) * 255
        bright_regions = (gray > 225).astype(np.uint8) * 255

        combined = np.maximum(dark_regions, bright_regions)

        # 形态学处理
        kernel = np.ones((5, 5), np.uint8)
        combined = cv2.dilate(combined, kernel, iterations=1)
        combined = cv2.erode(combined, kernel, iterations=1)
        combined = cv2.medianBlur(combined, 5)

        return Image.fromarray(combined)

    def restore(self, image_path, output_path, use_auto_mask=True, 
                mask_path=None, model="mat"):
        """
        执行完整的修复流程

        参数:
            image_path: 输入图片路径
            output_path: 输出图片路径
            use_auto_mask: 是否使用自动遮罩
            mask_path: 手动遮罩路径(可选)
            model: 使用的模型
        """
        # 1. 加载图片
        print("📷 加载图片...")
        image = Image.open(image_path).convert("RGB")

        # 2. 预处理
        print("🔧 预处理中...")
        preprocessed = self.preprocess(image)
        preprocessed.save("step1_preprocessed.jpg")

        # 3. 创建/加载遮罩
        print("🎨 创建遮罩...")
        if use_auto_mask:
            mask = self.create_mask(preprocessed)
        else:
            mask = Image.open(mask_path).convert("L")

        mask.save("step2_mask.jpg")

        # 4. 执行修复
        print("✨ AI 修复中(这可能需要几分钟)...")
        config = ModelConfig(
            model_name=model,
            device=self.device,
            hd_strategy="ORIGINAL"
        )

        result = self.service.inpaint(preprocessed, mask, config)

        # 5. 后处理 - 轻微去噪
        print("💫 后处理...")
        final = result.filter(ImageFilter.SurfaceBlur(radius=1))

        # 6. 保存结果
        final.save(output_path)
        print(f"✅ 修复完成!结果已保存到: {output_path}")

        return final


# 使用示例
if __name__ == "__main__":
    restorer = OldPhotoRestorer(device="cuda")

    restorer.restore(
        image_path="my_old_photo.jpg",
        output_path="restored_photo.jpg",
        use_auto_mask=True,
        model="mat"
    )

4.3 教程三:智能扩图(Outpainting)

场景:想把图片扩展到更宽的画幅,让AI帮你生成缺失的内容。

4.3.1 基础扩图

from iopaint.api import IOService
from iopaint.schema import OutpaintConfig, ModelConfig

def expand_image_basic(image_path, output_path, direction="right", pixels=512):
    """
    基础扩图功能

    参数:
        image_path: 输入图片路径
        output_path: 输出图片路径
        direction: 扩展方向 ("left", "right", "top", "bottom")
        pixels: 扩展的像素数
    """
    # 加载图片
    image = Image.open(image_path).convert("RGB")

    # 初始化服务
    service = IOService()

    # 配置扩图参数
    config = OutpaintConfig(
        direction=direction,
        pixels=pixels,
        model_name="sd1.5"  # 使用 Stable Diffusion 进行扩图
    )

    # 执行扩图
    result = service.outpaint(image, config)

    # 保存结果
    result.save(output_path)
    print(f"✅ 扩图完成: {output_path}")


# 使用示例
expand_image_basic(
    image_path="portrait.jpg",
    output_path="portrait_expanded.jpg",
    direction="right",
    pixels=512
)

4.3.2 四方向扩展(创建全景图)

from iopaint.api import IOService
from iopaint.schema import OutpaintConfig, ModelConfig
from PIL import Image

def expand_all_directions(image_path, output_path, pixels_per_side=256):
    """
    四个方向同时扩展,创建全景效果

    参数:
        image_path: 输入图片路径
        output_path: 输出图片路径
        pixels_per_side: 每个方向扩展的像素数
    """
    # 加载图片
    image = Image.open(image_path).convert("RGB")
    w, h = image.size

    service = IOService()

    # 扩展方向顺序(顺时针)
    directions = ["left", "top", "right", "bottom"]

    # 每次扩展后的新图片
    current_image = image.copy()

    for i, direction in enumerate(directions):
        print(f"🔄 正在扩展 {direction} 方向 ({i+1}/{len(directions)})...")

        config = OutpaintConfig(
            direction=direction,
            pixels=pixels_per_side,
            model_name="sd1.5",
            guidance_scale=7.5,
            ddim_steps=30
        )

        current_image = service.outpaint(current_image, config)

        # 保存中间步骤(方便调试)
        current_image.save(f"step_{i+1}_{direction}.jpg")

    current_image.save(output_path)
    print(f"✅ 全景扩展完成: {output_path}")
    print(f"最终尺寸: {current_image.size}")

    return current_image


# 使用示例 - 创建全景效果
expand_all_directions(
    image_path="landscape.jpg",
    output_path="landscape_panorama.jpg",
    pixels_per_side=300
)

4.3.3 带提示词的智能扩图

def expand_with_prompt(image_path, output_path, direction, pixels, 
                       prompt, negative_prompt=""):
    """
    使用文本提示词引导扩图

    参数:
        image_path: 输入图片路径
        output_path: 输出图片路径
        direction: 扩展方向
        pixels: 扩展像素数
        prompt: 正面提示词,描述你想要生成的内容
        negative_prompt: 负面提示词,描述你不想要的内容
    """
    image = Image.open(image_path).convert("RGB")

    service = IOService()

    # 创建带提示词的配置
    config = OutpaintConfig(
        direction=direction,
        pixels=pixels,
        model_name="sd1.5",
        # 提示词设置
        prompt=prompt,
        negative_prompt=negative_prompt,
        # 生成参数
        guidance_scale=7.5,
        ddim_steps=50,
        # 控制随机性
        seed=-1  # -1 表示随机,指定数字可复现
    )

    result = service.outpaint(image, config)
    result.save(output_path)

    return result


# 使用示例 - 扩展风景照片
expand_with_prompt(
    image_path="mountain.jpg",
    output_path="mountain_extended.jpg",
    direction="right",
    pixels=512,
    prompt="continue the mountain landscape, blue sky with clouds, green hills",
    negative_prompt="buildings, people, cars, text, watermark"
)

4.3.4 创意扩图 – 不同风格的扩展

def expand_with_style(image_path, output_path, direction, style="realistic"):
    """
    不同风格的扩图

    参数:
        image_path: 输入图片路径
        output_path: 输出图片路径
        direction: 扩展方向
        style: 风格 ("realistic", "artistic", "fantasy")
    """
    # 不同风格的提示词配置
    style_configs = {
        "realistic": {
            "prompt": "realistic continuation, natural lighting, high quality photo",
            "negative": "cartoon, anime, drawing, painting, artificial",
            "guidance_scale": 7.5,
            "steps": 50
        },
        "artistic": {
            "prompt": "oil painting style, artistic interpretation, museum quality",
            "negative": "photograph, realistic, low quality",
            "guidance_scale": 10.0,
            "steps": 60
        },
        "fantasy": {
            "prompt": "magical fantasy landscape, ethereal glow, mystical atmosphere",
            "negative": "modern buildings, cars, power lines, mundane objects",
            "guidance_scale": 12.0,
            "steps": 60
        }
    }

    config_style = style_configs.get(style, style_configs["realistic"])

    image = Image.open(image_path).convert("RGB")
    service = IOService()

    config = OutpaintConfig(
        direction=direction,
        pixels=512,
        model_name="sd1.5",
        prompt=config_style["prompt"],
        negative_prompt=config_style["negative"],
        guidance_scale=config_style["guidance_scale"],
        ddim_steps=config_style["steps"],
        seed=42  # 固定种子便于复现
    )

    result = service.outpaint(image, config)
    result.save(output_path)

    return result


# 测试不同风格
styles = ["realistic", "artistic", "fantasy"]
for style in styles:
    expand_with_style(
        image_path="forest.jpg",
        output_path=f"forest_{style}.jpg",
        direction="right",
        style=style
    )

4.4 教程四:批量处理大量图片

当需要处理多张图片时,批量处理可以大大提高效率:

4.4.1 批量去除水印

import os
from pathlib import Path
from PIL import Image, ImageDraw
from iopaint.api import IOService
from iopaint.schema import ModelConfig

class BatchProcessor:
    """批量图片处理器"""

    def __init__(self, device="cuda"):
        self.service = IOService()
        self.device = device

    def batch_remove_watermark(self, input_dir, output_dir, 
                               watermark_positions, model="lama"):
        """
        批量去除水印

        参数:
            input_dir: 输入文件夹路径
            output_dir: 输出文件夹路径
            watermark_positions: 水印位置列表
                格式: [(x1, y1, w1, h1), (x2, y2, w2, h2), ...]
            model: 使用的模型
        """
        # 确保输出目录存在
        os.makedirs(output_dir, exist_ok=True)

        # 获取所有图片文件
        input_path = Path(input_dir)
        image_files = list(input_path.glob("*.jpg")) + \
                      list(input_path.glob("*.png")) + \
                      list(input_path.glob("*.jpeg"))

        print(f"找到 {len(image_files)} 张图片")

        # 配置模型
        config = ModelConfig(
            model_name=model,
            device=self.device
        )

        # 处理每张图片
        success_count = 0
        for i, image_file in enumerate(image_files):
            try:
                print(f"🔄 处理 {i+1}/{len(image_files)}: {image_file.name}")

                # 加载图片
                image = Image.open(image_file).convert("RGB")

                # 创建遮罩(覆盖所有水印位置)
                mask = Image.new("L", image.size, 0)
                draw = ImageDraw.Draw(mask)

                for x, y, w, h in watermark_positions:
                    draw.rectangle([x, y, x+w, y+h], fill=255)

                # 执行修复
                result = self.service.inpaint(image, mask, config)

                # 保存结果
                output_file = os.path.join(output_dir, image_file.name)
                result.save(output_file)

                success_count += 1
                print(f"   ✅ 已保存: {output_file}")

            except Exception as e:
                print(f"   ❌ 处理失败: {e}")

        print(f"\n🎉 批量处理完成!成功: {success_count}/{len(image_files)}")

        return success_count


# 使用示例
processor = BatchProcessor(device="cuda")

# 假设所有图片的水印位置相同
watermark_positions = [
    (100, 50, 200, 30),      # 顶部水印
    (100, 100, 150, 20),     # 左下水印
]

processor.batch_remove_watermark(
    input_dir="images_with_watermark",
    output_dir="images_cleaned",
    watermark_positions=watermark_positions,
    model="lama"
)

4.4.2 批量老照片修复

def batch_restore_photos(input_dir, output_dir, mask_type="auto"):
    """
    批量修复老照片

    参数:
        input_dir: 输入文件夹
        output_dir: 输出文件夹
        mask_type: 遮罩类型 ("auto", "full")
    """
    os.makedirs(output_dir, exist_ok=True)

    input_path = Path(input_dir)
    image_files = list(input_path.glob("*.jpg")) + \
                  list(input_path.glob("*.png"))

    restorer = OldPhotoRestorer(device="cuda")

    results = []
    for image_file in image_files:
        print(f"\n📷 处理: {image_file.name}")

        try:
            # 修复照片
            result = restorer.restore(
                image_path=str(image_file),
                output_path=os.path.join(output_dir, image_file.name),
                use_auto_mask=(mask_type == "auto"),
                model="mat"
            )

            results.append({
                "file": image_file.name,
                "status": "success",
                "size": result.size
            })

        except Exception as e:
            print(f"   ❌ 错误: {e}")
            results.append({
                "file": image_file.name,
                "status": "failed",
                "error": str(e)
            })

    # 打印统计
    success = sum(1 for r in results if r["status"] == "success")
    print(f"\n========== 统计 ==========")
    print(f"总计: {len(results)} 张")
    print(f"成功: {success} 张")
    print(f"失败: {len(results) - success} 张")

    return results


# 使用示例
batch_restore_photos(
    input_dir="old_photos",
    output_dir="restored_photos",
    mask_type="auto"
)

4.4.3 带进度条的批量处理

from tqdm import tqdm
import time

def batch_process_with_progress(input_dir, output_dir, operation="inpaint",
                                 regions=None, model="lama"):
    """
    带进度条的批量处理

    参数:
        input_dir: 输入目录
        output_dir: 输出目录
        operation: 操作类型 ("inpaint", "outpaint", "remove_bg")
        regions: 修复区域
        model: 模型名称
    """
    os.makedirs(output_dir, exist_ok=True)

    input_path = Path(input_dir)
    image_files = [f for f in input_path.glob("*.*") 
                   if f.suffix.lower() in ['.jpg', '.png', '.jpeg']]

    service = IOService()
    config = ModelConfig(model_name=model, device="cuda")

    # 使用 tqdm 显示进度
    with tqdm(image_files, desc=f"批量{operation}") as pbar:
        for image_file in pbar:
            # 更新进度条描述
            pbar.set_description(f"处理: {image_file.name[:15]}...")

            try:
                image = Image.open(image_file).convert("RGB")

                if operation == "inpaint" and regions:
                    # 创建遮罩
                    mask = Image.new("L", image.size, 0)
                    draw = ImageDraw.Draw(mask)
                    for region in regions:
                        draw.rectangle(region, fill=255)

                    result = service.inpaint(image, mask, config)

                elif operation == "remove_bg":
                    from iopaint.api import BackgroundRemover
                    remover = BackgroundRemover(model_name="u2net")
                    result = remover.remove(image)

                else:
                    continue

                result.save(os.path.join(output_dir, image_file.name))

                # 模拟处理延迟(实际不需要)
                time.sleep(0.1)

            except Exception as e:
                pbar.write(f"错误 {image_file.name}: {e}")

    print(f"\n✅ 批量处理完成!结果保存在: {output_dir}")


# 使用示例
batch_process_with_progress(
    input_dir="photos_to_process",
    output_dir="processed_photos",
    operation="inpaint",
    regions=[(100, 100, 200, 200)],
    model="lama"
)

五、常见使用场景

5.1 电商场景

场景一:商品图背景处理

def prepare_product_image(image_path, output_path, bg_color=(255, 255, 255)):
    """
    处理电商商品图:去除背景,添加纯色背景

    适用场景:淘宝、京东、亚马逊等平台商品图
    """
    from iopaint.api import BackgroundRemover

    # 加载图片
    image = Image.open(image_path).convert("RGB")

    # 移除背景
    remover = BackgroundRemover(model_name="u2net")
    no_bg = remover.remove(image)

    # 添加纯色背景
    result = Image.new("RGB", no_bg.size, bg_color)
    result.paste(no_bg, mask=no_bg.split()[3] if no_bg.mode == "RGBA" else None)

    result.save(output_path)
    return result


# 准备商品图
prepare_product_image("watch.jpg", "watch_clean.png", bg_color=(255, 255, 255))

场景二:修复商品瑕疵

def fix_product_defects(image_path, defect_regions, output_path):
    """
    修复商品图片中的瑕疵

    defect_regions: 瑕疵区域列表 [(x, y, w, h), ...]
    """
    image = Image.open(image_path).convert("RGB")

    # 创建遮罩
    mask = Image.new("L", image.size, 0)
    draw = ImageDraw.Draw(mask)
    for x, y, w, h in defect_regions:
        draw.rectangle([x, y, x+w, y+h], fill=255)

    # 修复
    service = IOService()
    config = ModelConfig(model_name="lama", device="cuda")
    result = service.inpaint(image, mask, config)

    result.save(output_path)
    return result


# 修复商品瑕疵
fix_product_defects(
    "phone_case.jpg",
    [(150, 200, 50, 50)],  # 一个瑕疵区域
    "phone_case_fixed.jpg"
)

5.2 摄影后期

场景一:移除照片中的游客

def remove_tourists(photo_path, output_path):
    """
    从旅游照片中移除游客

    技巧:对于游客这种人像,推荐使用较大的画笔涂抹
    """
    image = Image.open(photo_path).convert("RGB")

    # 手动涂抹游客区域(这里用代码模拟)
    mask = Image.new("L", image.size, 0)
    draw = ImageDraw.Draw(mask)

    # 假设游客在以下位置(实际使用时用画笔涂抹)
    tourist_regions = [
        (300, 400, 100, 150),   # 游客A
        (500, 380, 80, 140),    # 游客B
    ]

    for x, y, w, h in tourist_regions:
        # 使用椭圆来更贴合人形
        draw.ellipse([x, y, x+w, y+h], fill=255)

    # 使用 MAT 模型,对人物边缘处理更好
    service = IOService()
    config = ModelConfig(model_name="mat", device="cuda")
    result = service.inpaint(image, mask, config)

    result.save(output_path)
    return result

场景二:修复闭眼的照片

def fix_closed_eyes(photo_path, face_region, output_path):
    """
    修复闭眼的照片

    face_region: 人脸区域 (x, y, w, h)
    """
    image = Image.open(photo_path).convert("RGB")

    # 创建遮罩 - 只覆盖眼睛区域
    x, y, w, h = face_region
    mask = Image.new("L", image.size, 0)
    draw = ImageDraw.Draw(mask)

    # 眼睛通常在脸部上1/3区域
    eye_y = y + h // 6
    eye_h = h // 5
    eye_w = w // 2

    # 左眼
    left_eye_x = x + w // 4 - eye_w // 2
    draw.ellipse([left_eye_x, eye_y, left_eye_x + eye_w, eye_y + eye_h], fill=255)

    # 右眼
    right_eye_x = x + 3 * w // 4 - eye_w // 2
    draw.ellipse([right_eye_x, eye_y, right_eye_x + eye_w, eye_y + eye_h], fill=255)

    # 使用 instruct-pix2pix 模型,可以更好地理解指令
    service = IOService()
    config = ModelConfig(
        model_name="instruct-pix2pix",
        device="cuda",
        prompt="open eyes, natural looking eyes",
        guidance_scale=7.5
    )

    result = service.inpaint(image, mask, config)
    result.save(output_path)

    return result

5.3 创意设计

场景一:无缝图案生成

def generate_seamless_pattern(base_image_path, output_path):
    """
    生成无缝图案

    适用于:布料设计、墙纸、背景图等
    """
    from iopaint.api import IOService

    # 加载基础图案
    base = Image.open(base_image_path).convert("RGB")
    w, h = base.size

    # 创建扩展用的图片(复制并拼接)
    # 2x2 拼贴
    extended = Image.new("RGB", (w * 2, h * 2))
    extended.paste(base, (0, 0))
    extended.paste(base, (w, 0))
    extended.paste(base, (0, h))
    extended.paste(base, (w, h))

    service = IOService()

    # 向右扩展
    config_right = OutpaintConfig(direction="right", pixels=w, model_name="sd1.5")
    step1 = service.outpaint(extended, config_right)

    # 向下扩展
    config_bottom = OutpaintConfig(direction="bottom", pixels=h, model_name="sd1.5")
    result = service.outpaint(step1, config_bottom)

    # 裁剪回原始尺寸
    final = result.crop((0, 0, w, h))

    final.save(output_path)
    return final

场景二:风格化图像扩展

def artistic_expansion(image_path, output_path, style_prompt):
    """
    艺术化图像扩展

    使用 AI 生成风格统一的扩展内容
    """
    image = Image.open(image_path).convert("RGB")

    service = IOService()

    # 设置风格化提示词
    config = OutpaintConfig(
        direction="right",
        pixels=512,
        model_name="sd1.5",
        prompt=style_prompt,
        negative_prompt="low quality, blurry, distorted",
        guidance_scale=15.0,  # 高引导值使风格更明显
        ddim_steps=60
    )

    result = service.outpaint(image, config)
    result.save(output_path)

    return result


# 示例:生成水彩风格的扩展
artistic_expansion(
    "flower.jpg",
    "flower_watercolor.jpg",
    style_prompt="watercolor painting style, soft brush strokes, artistic interpretation"
)

5.4 文档处理

场景:修复扫描文档

def enhance_scanned_document(image_path, output_path):
    """
    增强扫描文档
    - 去除污渍
    - 修复缺失文字
    - 提高清晰度
    """
    image = Image.open(image_path).convert("RGB")

    # 1. 预处理 - 提高对比度和清晰度
    enhanced = ImageEnhance.Contrast(image).enhance(2.0)
    enhanced = ImageEnhance.Sharpness(enhanced).enhance(2.0)

    # 2. 检测文档问题区域
    # 通常文档的边缘和折痕会有问题

    # 转换为灰度检测
    gray = np.array(enhanced.convert("L"))

    # 找出过暗或过亮的区域
    dark_mask = gray < 50
    bright_mask = gray > 200

    # 合并问题区域
    problem_mask = np.logical_or(dark_mask, bright_mask).astype(np.uint8) * 255

    # 形态学处理
    kernel = np.ones((3, 3), np.uint8)
    problem_mask = cv2.morphologyEx(problem_mask, cv2.MORPH_CLOSE, kernel)

    mask = Image.fromarray(problem_mask)

    # 3. 修复
    service = IOService()
    config = ModelConfig(model_name="lama", device="cuda")
    result = service.inpaint(enhanced, mask, config)

    # 4. 二值化处理(如果需要)
    # result_bw = result.convert("L").point(lambda x: 0 if x < 128 else 255)

    result.save(output_path)
    return result

六、技巧与最佳实践

6.1 选择合适的模型

选择指南:

┌─────────────────────────────────────────────────────────┐
│ 任务类型              │ 推荐模型  │ 理由                  │
├─────────────────────────────────────────────────────────┤
│ 快速日常修复          │ LaMa     │ 速度快,效果稳定      │
│ 高清细节保留          │ MAT      │ 边缘和纹理处理更好    │
│ 大面积创意生成        │ SD系列   │ 生成能力强            │
│ 背景移除              │ U2Net    │ 专为抠图设计          │
│ 文本引导编辑          │ Instruct │ 理解自然语言指令      │
│ 图像扩展              │ SD1.5    │ 扩展效果好            │
└─────────────────────────────────────────────────────────┘

6.2 遮罩绘制技巧

遮罩大小选择

# 遮罩绘制原则

"""
1. 不要只覆盖明显的目标区域
2. 周围留出一些边距(10-20像素)
3. 边缘要平滑,不要有锯齿

正确示例:
┌────────────────────┐
│    #####           │  ← 目标区域
│    #####           │
│   #######          │  ← 周围留有余量
│    #####           │
│    #####           │
└────────────────────┘

错误示例:
┌────────────────────┐
│    ###             │  ← 太小,可能留下痕迹
│    ###             │
└────────────────────┘

硬边缘 vs 软边缘

# 硬边缘遮罩(适合规则形状)
hard_mask = Image.new("L", image.size, 0)
draw = ImageDraw.Draw(hard_mask)
draw.rectangle([100, 100, 200, 200], fill=255)

# 软边缘遮罩(适合不规则形状,效果更自然)
from PIL import ImageFilter

def create_soft_mask(image_size, center, radius):
    """创建渐变边缘的遮罩"""
    # 创建一个圆形渐变遮罩
    mask = Image.new("L", image_size, 0)

    # 绘制多个同心圆,从内到外逐渐变淡
    for i in range(radius, 0, -1):
        alpha = int(255 * (i / radius))
        draw = ImageDraw.Draw(mask)
        draw.ellipse(
            [center[0]-i, center[1]-i, center[0]+i, center[1]+i],
            fill=alpha
        )

    # 高斯模糊使边缘更自然
    mask = mask.filter(ImageFilter.GaussianBlur(radius=5))

    return mask

soft_mask = create_soft_mask(image.size, (150, 150), 50)

6.3 提示词工程

有效提示词

# ✅ 好的提示词示例

good_prompts = [
    # 具体的描述
    "a wooden table with natural grain texture",

    # 包含场景背景
    "the same white wall, natural lighting, smooth surface",

    # 指定风格
    "realistic photo, high detail, 8k quality",

    # 包含负面排除
    # (在实际使用时放入 negative_prompt)
    # "blurry, watermark, text, distorted"
]

# ❌ 不好的提示词示例

bad_prompts = [
    # 太模糊
    "something good",

    # 自相矛盾
    "day and night scene",

    # 包含不需要的元素
    "include people"  # 当你想去除人时
]

提示词模板

def build_inpaint_prompt(scene_description, style="realistic", **kwargs):
    """
    构建修复提示词的辅助函数

    参数:
        scene_description: 场景描述
        style: 风格 ("realistic", "artistic", "vintage")
        **kwargs: 其他可选参数
    """
    base_prompts = {
        "realistic": "photorealistic, high detail, natural lighting, 8k",
        "artistic": "artistic interpretation, professional photography, studio lighting",
        "vintage": "vintage style, warm tones, nostalgic atmosphere"
    }

    prompt = f"{scene_description}, {base_prompts.get(style, '')}"

    # 添加额外参数
    if kwargs.get("quality"):
        prompt += f", {kwargs['quality']} quality"
    if kwargs.get("lighting"):
        prompt += f", {kwargs['lighting']} lighting"

    return prompt


# 使用示例
prompt = build_inpaint_prompt(
    scene_description="seamless continuation of the blue sky",
    style="realistic",
    quality="ultra high",
    lighting="natural"
)
print(prompt)
# 输出: seamless continuation of the blue sky, photorealistic, high detail, 
#       natural lighting, 8k, ultra high quality, natural lighting

6.4 参数调优指南

"""
参数调优指南

1. guidance_scale(引导强度)
   - 低值 (1-5): 更多随机性,可能产生意外结果
   - 中值 (7-9): 平衡创意和稳定性,推荐起始值
   - 高值 (10-15): 严格遵循提示词,可能牺牲自然度

2. ddim_steps(采样步数)
   - 少步数 (20-30): 速度快,可能有噪点
   - 中步数 (40-50): 平衡速度和质量的推荐值
   - 多步数 (60-100): 细节更好,速度慢

3. hd_strategy(高清策略)
   - ORIGINAL: 保持原始尺寸
   - CROPPED: 裁剪后处理再拼接
   - RESIZE: 缩放处理再放大

4. l2_zero_thresh(MAT模型专用)
   - 控制修复区域的"干净"程度
   - 低值 (0.3-0.5): 保留更多原始信息
   - 高值 (0.7-1.0): 生成更干净的结果
"""

# 针对不同场景的参数推荐

scenario_params = {
    # 日常照片修复
    "casual_photo": {
        "model": "lama",
        "guidance_scale": 7.5,
        "ddim_steps": 30
    },

    # 高清照片精细修复
    "hd_photo_detail": {
        "model": "mat",
        "guidance_scale": 7.5,
        "ddim_steps": 50,
        "hd_strategy": "ORIGINAL"
    },

    # 创意扩展
    "creative_outpaint": {
        "model": "sd1.5",
        "guidance_scale": 12.0,
        "ddim_steps": 60
    },

    # 文字区域修复
    "text_recovery": {
        "model": "lama",
        "guidance_scale": 5.0,  # 较低值保持文字可读性
        "ddim_steps": 40
    },

    # 大面积缺失
    "large_missing": {
        "model": "sd1.5",
        "guidance_scale": 10.0,
        "ddim_steps": 80,  # 更多步数处理大面积
        "prompt": "natural scene continuation"
    }
}

6.5 性能优化技巧

加速处理

# 性能优化技巧

# 1. 减小输入图片尺寸
def resize_for_processing(image, max_dimension=1024):
    """将图片缩小到合适尺寸,加快处理速度"""
    if max(image.size) > max_dimension:
        ratio = max_dimension / max(image.size)
        new_size = (int(image.size[0] * ratio), int(image.size[1] * ratio))
        return image.resize(new_size, Image.LANCZOS)
    return image


# 2. 批量处理时复用模型
class OptimizedProcessor:
    def __init__(self, model_name="lama"):
        self.service = IOService()
        self.config = ModelConfig(model_name=model_name, device="cuda")
        self._is_model_loaded = False

    def process(self, image, mask):
        """处理单张图片"""
        if not self._is_model_loaded:
            # 模型只在第一次使用时加载
            self.service.load_model(self.config)
            self._is_model_loaded = True

        return self.service.inpaint(image, mask, self.config)


# 3. 使用半精度加速(如果有支持)
config_fp16 = ModelConfig(
    model_name="lama",
    device="cuda",
    dtype="float16"  # 使用半精度,减少显存使用
)

显存不足时的处理

# 显存不足解决方案

# 方案1:减小批处理大小
config_small_batch = ModelConfig(
    model_name="lama",
    device="cuda",
    # 使用更小的处理块
    hd_strategy="CROPPED",
    hd_strategy_crop_size=256  # 减小裁剪大小
)

# 方案2:使用 CPU(作为备选)
config_cpu = ModelConfig(
    model_name="lama",
    device="cpu"  # 虽然慢,但不会显存不足
)

# 方案3:选择更轻量的模型
lightweight_models = ["lama"]  # LaMa 相对轻量

# 方案4:分块处理大图
def process_large_image_in_tiles(image_path, mask_path, output_path, 
                                  tile_size=512, overlap=64):
    """
    分块处理大图,避免显存不足

    参数:
        tile_size: 每块的大小
        overlap: 块之间的重叠(用于平滑拼接)
    """
    image = Image.open(image_path)
    mask = Image.open(mask_path)

    w, h = image.size
    service = IOService()
    config = ModelConfig(model_name="lama", device="cuda")

    # 创建结果图像
    result = Image.new("RGB", (w, h))
    count_map = Image.new("L", (w, h), 0)  # 计数图,用于平均

    step = tile_size - overlap

    for y in range(0, h, step):
        for x in range(0, w, step):
            # 裁剪当前块
            tile = image.crop((x, y, min(x+tile_size, w), min(y+tile_size, h)))
            tile_mask = mask.crop((x, y, min(x+tile_size, w), min(y+tile_size, h)))

            # 处理当前块
            tile_result = service.inpaint(tile, tile_mask, config)

            # 粘贴回结果
            result.paste(tile_result, (x, y))

    result.save(output_path)
    return result

七、常见问题解答

7.1 安装问题

Q: 安装时报错 torch.cuda.is_available() = False

# 解决方案:确认 CUDA 安装

# 1. 检查 NVIDIA 驱动
nvidia-smi

# 2. 安装 CUDA 版本的 PyTorch
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

# 3. 验证安装
python -c "import torch; print(torch.cuda.is_available())"

Q: 提示 No module named 'iopaint'

# 确保在正确的虚拟环境中安装

# 检查当前 Python
which python

# 重新安装
pip install iopaint --force-reinstall

# 或者如果使用开发模式安装
cd IOPaint
pip install -e .

7.2 运行问题

Q: Web 界面无法访问

# 检查 IOPaint 是否正在运行
ps aux | grep iopaint

# 检查端口占用
lsof -i :8080

# 尝试使用其他端口
iopaint run --port 8888

# 检查防火墙设置
# Linux:
sudo ufw allow 8080

# Windows:
# 在防火墙设置中允许 python.exe

Q: 模型下载失败

# 手动下载模型

# 1. 创建模型目录
mkdir -p ~/.cache/torch/hub/models

# 2. 从 HuggingFace 下载
# 访问 https://huggingface.co/<model-name>

# 3. 将模型文件放到正确位置
mv downloaded_model.py ~/.cache/torch/hub/models/

# 4. 或者使用镜像
export HF_ENDPOINT=https://hf-mirror.com

7.3 使用问题

Q: 修复效果不理想,有明显痕迹

可能原因和解决方案:

1. 遮罩边缘不平滑
   → 使用软边缘遮罩,或扩大遮罩范围

2. 修复区域太大
   → 分多次小区域修复

3. 模型选择不当
   → 尝试不同模型(LaMa/MAT/SD)

4. 参数设置不当
   → 调整 guidance_scale 或 steps

5. 提示词不准确
   → 使用更具体、简洁的描述

Q: 显存不足(OOM)

# 解决方案

# 1. 减小图片尺寸
image = image.resize((1024, 1024), Image.LANCZOS)

# 2. 使用更小的模型
config = ModelConfig(model_name="lama")  # 比 MAT 轻量

# 3. 降低高清策略的裁剪大小
config.hd_strategy_crop_size = 256

# 4. 清空 GPU 缓存
import torch
torch.cuda.empty_cache()

Q: 生成的内容不自然

优化建议:

1. 检查原图和生成内容的风格一致性
2. 增加引导强度(guidance_scale)
3. 使用更多采样步数
4. 优化提示词:
   - 添加场景描述(光线、背景)
   - 使用负面提示词排除不需要的元素
5. 尝试使用 MAT 模型(边缘处理更好)

7.4 高级问题

Q: 如何集成到自己的应用?

# 作为 Python 库使用

from iopaint.api import IOService
from iopaint.schema import ModelConfig

# 初始化
service = IOService()

# 处理单张图片
def process_image(image_path, mask_path, output_path):
    image = Image.open(image_path).convert("RGB")
    mask = Image.open(mask_path).convert("L")

    config = ModelConfig(model_name="lama", device="cuda")
    result = service.inpaint(image, mask, config)

    result.save(output_path)

# 作为 REST API 使用
# 启动服务器
iopaint run --api

# 然后通过 HTTP 请求调用
import requests

response = requests.post("http://localhost:8080/inpaint", files={
    "image": open("input.jpg", "rb"),
    "mask": open("mask.png", "rb")
}, data={
    "model": "lama"
})

with open("output.jpg", "wb") as f:
    f.write(response.content)

Q: 如何训练自己的模型?

# IOPaint 支持自定义模型训练(高级功能)

# 1. 准备训练数据
"""
训练数据目录结构:
dataset/
├── images/
│   ├── image1.jpg
│   ├── image2.jpg
│   └── ...
└── masks/
    ├── mask1.png
    ├── mask2.png
    └── ...
"""

# 2. 配置文件
train_config = {
    "model_type": "lama",  # 或 mat, sd
    "dataset_path": "./dataset",
    "batch_size": 4,
    "learning_rate": 0.0001,
    "epochs": 100,
    "output_dir": "./trained_model"
}

# 3. 开始训练(具体命令参考项目文档)
# python -m iopaint.train --config train_config.yaml

八、总结与相关资源

8.1 核心要点回顾

┌─────────────────────────────────────────────────────────────┐
│                    IOPaint 使用要点                          │
├─────────────────────────────────────────────────────────────┤
│  1. 安装简单:pip install iopaint                            │
│  2. 界面友好:Web界面直观易用                                  │
│  3. 模型丰富:40+模型满足各种场景                              │
│  4. 隐私安全:本地处理,图片不上传                             │
│  5. 扩展性强:支持 Python API 和自定义模型                      │
└─────────────────────────────────────────────────────────────┘

推荐使用场景:
✓ 去除照片中的不需要元素
✓ 修复老照片
✓ 智能扩图
✓ 背景移除
✓ 商品图处理
✓ 创意设计

8.2 相关 AI 项目推荐

项目名称 类型 特点
Stable Diffusion 文生图 最流行的开源图像生成模型
ControlNet 条件控制 通过边缘、姿态等控制生成
Segment Anything 分割工具 强大的图像分割模型
CLIP 多模态 图文理解基础模型
Real-ESRGAN 超分辨率 图片清晰度提升
GFPGAN 人脸修复 专业人像修复工具
Denoise Diffusion 去噪模型 图像去噪处理
Lama Cleaner 图像修复 轻量级修复工具

8.3 进阶学习资源

# 推荐学习路径

learning_path = [
    # 基础阶段
    "1. 熟悉 IOPaint Web 界面操作",
    "2. 学习基本的图像修复流程",
    "3. 了解不同模型的特点",

    # 进阶阶段
    "4. 学习 Python API 编程",
    "5. 掌握遮罩绘制技巧",
    "6. 学习提示词工程",
    "7. 参数调优实践",

    # 高级阶段
    "8. 批量处理自动化",
    "9. 自定义模型训练",
    "10. 应用集成开发"
]

for i, step in enumerate(learning_path):
    print(f"{i+1}. {step}")

8.4 项目链接

IOPaint 官方资源:

📦 GitHub 仓库:https://github.com/Sanster/IOPaint
📖 项目文档:https://github.com/Sanster/IOPaint#readme
💬 问题反馈:https://github.com/Sanster/IOPaint/issues
🔧 模型下载:https://huggingface.co/models

8.5 写在最后

IOPaint 是一个非常实用的开源图像修复工具,它将复杂的 AI 模型封装成了简单易用的界面和 API。无论你是设计师、摄影师、电商运营,还是普通的图片爱好者,都能从中受益。

核心优势总结:

免费开源     → 无使用成本,可自由定制
本地处理     → 保护隐私,安全可靠
模型丰富     → 40+ 模型覆盖各种场景
易于集成     → Python API 方便开发
社区活跃     → 持续更新,问题能得到响应

开始使用 IOPaint 的最佳方式:

# 最简单的方式
pip install iopaint
iopaint run

# 然后打开浏览器访问 http://localhost:8080

现在就动手试试吧!无论是修复一张老照片,还是批量处理商品图,IOPaint 都能帮你轻松完成。


祝你玩得开心!如果觉得有用,欢迎给项目点个 Star ⭐

如果内容对您有帮助,欢迎打赏

您的支持是我继续创作的动力

前往打赏页面

评论区

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注