扩散模型进阶:ControlNet、IP-Adapter 与图像编辑
1. 引言
Stable Diffusion 的文生图能力已经非常强大,但"纯文字"控制往往不够精确。ControlNet 和 IP-Adapter 让我们能用边缘图、姿态图、参考图像来精确控制生成结果。
控制方式对比:
| Text-to-Image | 文字 | 低 | 创意生成 |
| ControlNet | 结构图 | 高 | 建筑/姿态/深度 |
| IP-Adapter | 参考图像 | 中 | 风格/角色一致性 |
| Inpainting | 局部遮罩 | 高 | 局部编辑 |
2. ControlNet
2.1 原理
ControlNet 在 UNet 的编码器上添加旁路分支:
原始 UNet 编码器 → 下采样特征
↓
ControlNet 旁路 → 条件特征(边缘/深度/姿态)
↓
零卷积融合 → UNet 解码器
2.2 支持的控制类型
CONTROL_TYPES = {
"canny": "边缘检测图",
"depth": "深度图",
"pose": "人体姿态(OpenPose)",
"scribble": "涂鸦/草图",
"lineart": "线稿",
"mlsd": "直线检测(建筑)",
"normal": "法线图",
"seg": "语义分割图",
"shuffle": "内容随机打乱",
"tile": "超分辨率/细节增强",
"inpaint": "局部重绘",
"ip2p": "指令编辑",
"reference": "参考图",
}
2.3 使用 ControlNet
from diffusers import (
StableDiffusionXLControlNetPipeline,
ControlNetModel,
UniPCMultistepScheduler,
)
from controlnet_aux import CannyDetector
from PIL import Image
import torch
# 加载 ControlNet
controlnet = ControlNetModel.from_pretrained(
"diffusers/controlnet-canny-sdxl-1.0",
torch_dtype=torch.float16,
)
# 加载 Pipeline
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
controlnet=controlnet,
torch_dtype=torch.float16,
).to("cuda")
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
# 提取控制图
canny = CannyDetector()
image = Image.open("input.jpg")
control_image = canny(image, low_threshold=100, high_threshold=200)
# 生成
result = pipe(
prompt="a beautiful modern building, professional photography",
image=control_image,
num_inference_steps=30,
controlnet_conditioning_scale=0.7,
guidance_scale=7.5,
).images[0]
result.save("controlnet_output.jpg")
2.4 多 ControlNet 组合
# 同时使用 Canny + Depth
controlnet_canny = ControlNetModel.from_pretrained(
"diffusers/controlnet-canny-sdxl-1.0", torch_dtype=torch.float16
)
controlnet_depth = ControlNetModel.from_pretrained(
"diffusers/controlnet-depth-sdxl-1.0", torch_dtype=torch.float16
)
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
controlnet=[controlnet_canny, controlnet_depth],
torch_dtype=torch.float16,
).to("cuda")
result = pipe(
prompt="a modern living room",
image=[canny_image, depth_image],
controlnet_conditioning_scale=[0.5, 0.3], # 各自的权重
).images[0]
3. IP-Adapter
3.1 原理
IP-Adapter 将参考图像的特征注入到 UNet 的交叉注意力中:
参考图像 → CLIP 图像编码器 → 图像特征
↓
UNet 交叉注意力 = Text特征 × Q + Image特征 × K' × V'
3.2 使用 IP-Adapter
from diffusers import StableDiffusionXLPipeline
from diffusers.utils import load_image
from ip_adapter import IPAdapterXL
# 加载
pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
).to("cuda")
ip_adapter = IPAdapterXL(
pipe,
image_encoder_path="models/image_encoder",
ip_ckpt="models/ip-adapter_sdxl_vit-h.bin",
device="cuda",
)
# 参考图像
reference_image = load_image("character.jpg")
# 生成
result = ip_adapter.generate(
prompt="a girl in a park, sunny day",
pil_image=reference_image,
num_samples=1,
num_inference_steps=30,
scale=0.6, # IP-Adapter 强度
)[0]
result.save("ip_adapter_output.jpg")
3.3 IP-Adapter 强度控制
# scale 参数控制参考图像的影响程度
# 0.0 = 完全忽略参考图
# 1.0 = 强烈参考参考图
# 0.4-0.7 = 通常效果最好
for scale in [0.3, 0.5, 0.7, 0.9]:
result = ip_adapter.generate(
prompt="a man in a suit",
pil_image=reference_image,
scale=scale,
)[0]
result.save(f"scale_{scale}.jpg")
4. 图像编辑
4.1 Inpainting(局部重绘)
from diffusers import StableDiffusionXLInpaintPipeline
pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
).to("cuda")
# 原图和遮罩
image = Image.open("original.jpg")
mask = Image.open("mask.png") # 白色区域=重绘区域
result = pipe(
prompt="a red sports car",
image=image,
mask_image=mask,
num_inference_steps=30,
strength=0.8, # 重绘强度
).images[0]
4.2 图像到图像(Img2Img)
from diffusers import StableDiffusionXLImg2ImgPipeline
pipe = StableDiffusionXLImg2ImgPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
).to("cuda")
original = Image.open("sketch.jpg")
result = pipe(
prompt="a detailed architectural rendering",
image=original,
strength=0.75, # 0=不变, 1=完全重绘
guidance_scale=7.5,
).images[0]
4.3 指令编辑(InstructPix2Pix)
from diffusers import StableDiffusionInstructPix2PixPipeline
pipe = StableDiffusionInstructPix2PixPipeline.from_pretrained(
"timothybrooks/instruct-pix2pix",
torch_dtype=torch.float16,
).to("cuda")
image = Image.open("photo.jpg")
# 用自然语言描述编辑操作
result = pipe(
prompt="make the sky sunset",
image=image,
image_guidance_scale=1.5, # 保持原图的程度
guidance_scale=7.5,
).images[0]
5. 一致性模型(Consistency Model)
5.1 原理
传统扩散模型:需要 20-50 步去噪
一致性模型:1-4 步即可生成
核心思想:学习一个函数,直接将噪声映射到干净图像
5.2 使用
from diffusers import ConsistencyModelPipeline
pipe = ConsistencyModelPipeline.from_pretrained(
"openai/diffusion-model-sdxl-1.0",
torch_dtype=torch.float16,
).to("cuda")
# 1-4 步生成
result = pipe(
prompt="a cat sitting on a windowsill",
num_inference_steps=4,
).images[0]
6. 总结
扩散模型进阶的核心技术:

