要使用 Python 调用 Stable Diffusion API 实现图生图(img2img)功能,核心是向运行中的 Stable Diffusion WebUI 服务发送携带初始图像和提示词(prompt)的 POST 请求。以下是详细的实现步骤和代码示例。
### **1. 环境准备与部署**
首先,你需要一个运行在 API 模式下的 Stable Diffusion WebUI 服务。
**本地部署 Stable Diffusion WebUI 并开启 API:**
```bash
# 克隆项目
git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
cd stable-diffusion-webui
# 启动 WebUI 并开启 API 监听(Linux/macOS)
./webui.sh --api --listen
# Windows 用户
webui.bat --api --listen
```
启动成功后,API 服务默认运行在 `http://127.0.0.1:7860`。[ref_1]
**安装必要的 Python 库:**
```bash
pip install requests Pillow
```
* `requests`: 用于发送 HTTP 请求到 WebUI API。[ref_1]
* `Pillow`: 用于处理图像文件。[ref_1]
### **2. 核心:图生图 API 调用原理**
图生图功能通过 WebUI 的 `/sdapi/v1/img2img` 端点实现。你需要构建一个 JSON 格式的请求体(payload),其中必须包含经过 Base64 编码的初始图像(`init_images`)和文本提示词(`prompt`)。[ref_3]
**关键请求参数说明:**
| 参数 | 类型 | 说明 | 常用值/示例 |
| :--- | :--- | :--- | :--- |
| `init_images` | List[str] | **必需**。Base64 编码的初始图像列表。 | `["data:image/png;base64,iVBORw0KGgoAAA..."]` |
| `prompt` | str | **必需**。描述你希望生成图像的文本。 | `"a cat wearing a hat, cartoon style"` |
| `negative_prompt` | str | 描述不希望出现在图像中的内容。 | `"low quality, blurry"` |
| `denoising_strength` | float | **核心参数**。控制重绘强度,值越高与原始图差异越大。 | `0.75` (推荐范围 0.5-0.8) |
| `steps` | int | 采样步数,影响生成质量和时间。 | `20` |
| `cfg_scale` | float | 提示词相关性,值越高越遵循提示词。 | `7.0` |
| `width` / `height` | int | 生成图像的尺寸。 | `512` |
| `sampler_name` | str | 采样器名称,影响图像风格和细节。 | `"Euler a"`, `"DPM++ 2M Karras"` |
| `seed` | int | 随机种子,-1 表示随机。 | `-1` |
*表:图生图 API 核心参数详解(综合自 [ref_1], [ref_3], [ref_5])*
### **3. 完整代码实现与封装**
以下是一个封装好的 Python 客户端类,它集成了文生图、图生图、局部重绘等多种功能,方便调用。[ref_1]
```python
# sd_img2img_client.py
import requests
import base64
import json
import time
from pathlib import Path
from PIL import Image
import io
from dataclasses import dataclass
from typing import Optional, List
@dataclass
class Img2ImgConfig:
"""图生图配置类 [ref_1]"""
prompt: str = ""
negative_prompt: str = "low quality, blurry, deformed"
denoising_strength: float = 0.75 # 重绘强度 [ref_5]
steps: int = 30
cfg_scale: float = 7.0
sampler_name: str = "DPM++ 2M Karras"
seed: int = -1
width: int = 512
height: int = 512
class StableDiffusionImg2ImgClient:
"""Stable Diffusion 图生图 API 客户端 [ref_1]"""
def __init__(self, base_url: str = "http://127.0.0.1:7860"):
self.base_url = base_url
self.api_url = f"{base_url}/sdapi/v1"
def _image_to_base64(self, image_path: str) -> str:
"""将本地图片文件转换为 Base64 字符串 [ref_1]"""
with open(image_path, "rb") as image_file:
encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
return encoded_string
def _save_base64_image(self, b64_str: str, output_path: str):
"""将 Base64 字符串保存为图片文件 [ref_1]"""
img_data = base64.b64decode(b64_str)
img = Image.open(io.BytesIO(img_data))
img.save(output_path)
print(f"图像已保存至: {output_path}")
def img2img(self, init_image_path: str, config: Img2ImgConfig, output_dir: str = "./output") -> List[str]:
"""
执行图生图操作
:param init_image_path: 初始图片路径
:param config: 图生图配置参数
:param output_dir: 输出目录
:return: 生成图片的保存路径列表
"""
# 1. 准备初始图像 [ref_1]
init_image_b64 = self._image_to_base64(init_image_path)
# 2. 构建请求负载 (Payload) [ref_3]
payload = {
"init_images": [init_image_b64],
"prompt": config.prompt,
"negative_prompt": config.negative_prompt,
"denoising_strength": config.denoising_strength,
"steps": config.steps,
"cfg_scale": config.cfg_scale,
"sampler_name": config.sampler_name,
"seed": config.seed,
"width": config.width,
"height": config.height,
}
# 3. 发送 POST 请求到 img2img 端点 [ref_6]
try:
response = requests.post(url=f"{self.api_url}/img2img", json=payload)
response.raise_for_status() # 检查请求是否成功
except requests.exceptions.RequestException as e:
print(f"API 请求失败: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"错误详情: {e.response.text}")
return []
# 4. 解析响应并保存图像 [ref_1]
result = response.json()
Path(output_dir).mkdir(parents=True, exist_ok=True) # 创建输出目录
saved_paths = []
timestamp = int(time.time())
for i, img_b64 in enumerate(result.get("images", [])):
output_filename = f"img2img_{timestamp}_{i}.png"
output_path = Path(output_dir) / output_filename
self._save_base64_image(img_b64, str(output_path))
saved_paths.append(str(output_path))
return saved_paths
def get_samplers(self) -> List[str]:
"""获取可用的采样器列表 [ref_1]"""
try:
response = requests.get(f"{self.api_url}/samplers")
return [s["name"] for s in response.json()]
except:
return ["Euler a", "DPM++ 2M Karras", "DDIM"] # 返回常用默认值
# ====== 使用示例 ======
if __name__ == "__main__":
# 初始化客户端
client = StableDiffusionImg2ImgClient("http://127.0.0.1:7860") # [ref_1]
# 查看可用采样器
print("可用采样器:", client.get_samplers()[:5]) # [ref_1]
# 配置图生图参数
config = Img2ImgConfig(
prompt="transform the scene into a vibrant cyberpunk city at night, neon lights, raining", # [ref_5]
negative_prompt="lowres, bad anatomy, watermark, signature",
denoising_strength=0.7, # 中等重绘强度
steps=25,
cfg_scale=7.5,
sampler_name="Euler a", # [ref_5]
seed=42, # 固定种子以便复现结果
width=768,
height=512
)
# 执行图生图
# 假设你有一张名为 'input_city_day.jpg' 的日间城市风景图
generated_images = client.img2img(
init_image_path="./input_city_day.jpg", # 你的初始图片路径
config=config,
output_dir="./img2img_results"
)
print(f"生成完成!图像保存在: {generated_images}")
```
### **4. 进阶应用与技巧**
1. **批量处理**:你可以轻松修改上述代码,遍历一个文件夹中的所有图片进行批量风格转换。[ref_1]
2. **参数调优**:
* `denoising_strength` 是关键。值接近 0 时,输出与输入图像高度相似;值接近 1 时,更像文生图,创造性更强。[ref_5]
* 对于人像重绘,`CFG Scale` 建议在 7-10 之间,`Steps` 在 20-30 之间以获得较好细节。
3. **结合 ControlNet**:通过 API 可以集成 ControlNet 插件,实现更精准的图像控制(如姿势、边缘检测)。这需要在 payload 中添加 `alwayson_scripts` 参数,其结构较为复杂,通常需要参考 WebUI 的接口文档或通过浏览器开发者工具捕获实际的 API 请求来构建。[ref_1]
4. **错误处理**:在生产环境中,应增加更完善的错误处理、日志记录以及重试机制,以应对网络波动或 API 服务暂时不可用的情况。
### **5. 云端 API 作为替代方案**
如果你没有本地 GPU 资源,也可以使用云服务商提供的 Stable Diffusion API,如 **Stability AI** 或 **Replicate**。其调用方式类似,但需要 API Key 并遵循服务商特定的参数格式。[ref_1]
```python
# 以 Stability AI 为例的云端调用简示
import requests
api_key = "YOUR_API_KEY"
response = requests.post(
f"https://api.stability.ai/v2beta/stable-image/generate/sd3",
headers={"Authorization": f"Bearer {api_key}"},
files={"none": ""},
data={
"prompt": "your prompt",
"image": open("input.jpg", "rb"), # 图生图需上传文件
"mode": "image-to-image", # 指定模式
"strength": 0.7 # 类似 denoising_strength
}
)
```
通过上述步骤和代码,你可以灵活地使用 Python 将 Stable Diffusion 强大的图生图功能集成到自己的应用程序或工作流中,实现图像风格的迁移、内容修改、质量增强等多种创意任务。核心在于正确构建包含 `init_images` 和 `prompt` 的 JSON 请求,并发送至正确的 API 端点。