Diffusers 文档 (Diffusers documentation)
外绘 (Outpainting)
并获得增强的文档体验 (and get access to the augmented documentation experience)
开始使用 (to get started)
外绘 (Outpainting)
外绘将图像扩展到其原始边界之外,允许您在保留原始图像的同时,在图像中添加、替换或修改视觉元素。与图像修复 (inpainting)类似,您希望用新的视觉元素填充白色区域(在本例中为原始图像外部的区域),同时保留原始图像(用黑色像素的蒙版表示)。有几种外绘方法,例如使用 ControlNet 或使用 Differential Diffusion。
本指南将向您展示如何使用图像修复模型、ControlNet 和 ZoeDepth 估计器进行外绘。
在开始之前,请确保您已安装 controlnet_aux 库,以便您可以使用 ZoeDepth 估计器。
!pip install -q controlnet_aux
图像准备 (Image preparation)
首先选择要进行外绘的图像,并使用类似 BRIA-RMBG-1.4 的 Space 删除背景。
例如,从此鞋子图像中删除背景。


Stable Diffusion XL (SDXL) 模型最适合 1024x1024 图像,但您可以将图像调整为任何大小,只要您的硬件有足够的内存来支持它。图像中的透明背景也应替换为白色背景。创建一个函数(如下所示),将图像缩放并粘贴到白色背景上。
import random
import requests
import torch
from controlnet_aux import ZoeDetector
from PIL import Image, ImageOps
from diffusers import (
AutoencoderKL,
ControlNetModel,
StableDiffusionXLControlNetPipeline,
StableDiffusionXLInpaintPipeline,
)
def scale_and_paste(original_image):
aspect_ratio = original_image.width / original_image.height
if original_image.width > original_image.height:
new_width = 1024
new_height = round(new_width / aspect_ratio)
else:
new_height = 1024
new_width = round(new_height * aspect_ratio)
resized_original = original_image.resize((new_width, new_height), Image.LANCZOS)
white_background = Image.new("RGBA", (1024, 1024), "white")
x = (1024 - new_width) // 2
y = (1024 - new_height) // 2
white_background.paste(resized_original, (x, y), resized_original)
return resized_original, white_background
original_image = Image.open(
requests.get(
"https://huggingface.co/datasets/stevhliu/testing-images/resolve/main/no-background-jordan.png",
stream=True,
).raw
).convert("RGBA")
resized_img, white_bg_image = scale_and_paste(original_image)
为了避免添加不必要的额外细节,请使用 ZoeDepth 估计器在生成过程中提供额外的指导,并确保鞋子与原始图像保持一致。
zoe = ZoeDetector.from_pretrained("lllyasviel/Annotators")
image_zoe = zoe(white_bg_image, detect_resolution=512, image_resolution=1024)
image_zoe

外绘 (Outpaint)
一旦您的图像准备就绪,您可以使用 controlnet-inpaint-dreamer-sdxl(一个为图像修复训练的 SDXL ControlNet)在鞋子周围的白色区域生成内容。
加载图像修复 ControlNet、ZoeDepth 模型、VAE 并将它们传递给 StableDiffusionXLControlNetPipeline。然后您可以创建一个可选的 generate_image
函数(为了方便起见)来外绘初始图像。
controlnets = [
ControlNetModel.from_pretrained(
"destitech/controlnet-inpaint-dreamer-sdxl", torch_dtype=torch.float16, variant="fp16"
),
ControlNetModel.from_pretrained(
"diffusers/controlnet-zoe-depth-sdxl-1.0", torch_dtype=torch.float16
),
]
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16).to("cuda")
pipeline = StableDiffusionXLControlNetPipeline.from_pretrained(
"SG161222/RealVisXL_V4.0", torch_dtype=torch.float16, variant="fp16", controlnet=controlnets, vae=vae
).to("cuda")
def generate_image(prompt, negative_prompt, inpaint_image, zoe_image, seed: int = None):
if seed is None:
seed = random.randint(0, 2**32 - 1)
generator = torch.Generator(device="cpu").manual_seed(seed)
image = pipeline(
prompt,
negative_prompt=negative_prompt,
image=[inpaint_image, zoe_image],
guidance_scale=6.5,
num_inference_steps=25,
generator=generator,
controlnet_conditioning_scale=[0.5, 0.8],
control_guidance_end=[0.9, 0.6],
).images[0]
return image
prompt = "nike air jordans on a basketball court"
negative_prompt = ""
temp_image = generate_image(prompt, negative_prompt, white_bg_image, image_zoe, 908097)
将原始图像粘贴到初始外绘图像上。您将在稍后的步骤中改进外绘背景。
x = (1024 - resized_img.width) // 2
y = (1024 - resized_img.height) // 2
temp_image.paste(resized_img, (x, y), resized_img)
temp_image

如果您内存不足,现在是释放一些内存的好时机!
pipeline=None
torch.cuda.empty_cache()
现在您有了初始外绘图像,加载带有 RealVisXL 模型的 StableDiffusionXLInpaintPipeline,以生成质量更好的最终外绘图像。
pipeline = StableDiffusionXLInpaintPipeline.from_pretrained(
"OzzyGT/RealVisXL_V4.0_inpainting",
torch_dtype=torch.float16,
variant="fp16",
vae=vae,
).to("cuda")
为最终外绘图像准备一个蒙版。为了在原始图像和外绘背景之间创建更自然的过渡,模糊蒙版以帮助其更好地融合。
mask = Image.new("L", temp_image.size)
mask.paste(resized_img.split()[3], (x, y))
mask = ImageOps.invert(mask)
final_mask = mask.point(lambda p: p > 128 and 255)
mask_blurred = pipeline.mask_processor.blur(final_mask, blur_factor=20)
mask_blurred

创建一个更好的 prompt 并将其传递给 generate_outpaint
函数以生成最终的外绘图像。再次,将原始图像粘贴到最终外绘背景上。
def generate_outpaint(prompt, negative_prompt, image, mask, seed: int = None):
if seed is None:
seed = random.randint(0, 2**32 - 1)
generator = torch.Generator(device="cpu").manual_seed(seed)
image = pipeline(
prompt,
negative_prompt=negative_prompt,
image=image,
mask_image=mask,
guidance_scale=10.0,
strength=0.8,
num_inference_steps=30,
generator=generator,
).images[0]
return image
prompt = "high quality photo of nike air jordans on a basketball court, highly detailed"
negative_prompt = ""
final_image = generate_outpaint(prompt, negative_prompt, temp_image, mask_blurred, 7688778)
x = (1024 - resized_img.width) // 2
y = (1024 - resized_img.height) // 2
final_image.paste(resized_img, (x, y), resized_img)
final_image
