Diffusers documentation

Outpainting

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.42.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Outpainting

Outpainting расширяет изображение за пределы его исходных границ, позволяя добавлять, заменять или изменять визуальные элементы, сохраняя при этом исходное изображение. Как и в случае с inpainting, вам нужно заполнить белую область (в данном случае — область за пределами исходного изображения) новыми визуальными элементами, сохранив исходное изображение (представленное маской из чёрных пикселей). Существует несколько способов outpainting, например, с помощью ControlNet или Differential Diffusion.

В этом руководстве показано, как выполнять outpainting с помощью модели inpainting, ControlNet и оценщика глубины ZoeDepth.

Перед началом убедитесь, что библиотека controlnet_aux установлена, чтобы вы могли использовать оценщик ZoeDepth.

!pip install -q controlnet_aux

Подготовка изображений

Начните с выбора изображения для outpainting и удалите фон с помощью Space, например BRIA-RMBG-1.4.

Например, удалите фон с этого изображения пары обуви.

original image
фон удален

Модели 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, обученного для inpainting.

Загрузите ControlNet для inpainting, модель ZoeDepth и VAE и передайте их в StableDiffusionXLControlNetPipeline. Затем вы можете создать необязательную функцию generate_image (для удобства), чтобы выполнить outpainting исходного изображения.

controlnets = [
    ControlNetModel.from_pretrained(
        "destitech/controlnet-inpaint-dreamer-sdxl", dtype=torch.float16, variant="fp16"
    ),
    ControlNetModel.from_pretrained(
        "diffusers/controlnet-zoe-depth-sdxl-1.0", dtype=torch.float16
    ),
]
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", dtype=torch.float16).to("cuda")  # or "mps", "xpu", "cpu"
pipeline = StableDiffusionXLControlNetPipeline.from_pretrained(
    "SG161222/RealVisXL_V4.0", 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()

Теперь, когда у вас есть начальное изображение с расширенной областью, загрузите StableDiffusionXLInpaintPipeline с моделью RealVisXL, чтобы сгенерировать финальное изображение с расширенной областью более высокого качества.

pipeline = StableDiffusionXLInpaintPipeline.from_pretrained(
    "OzzyGT/RealVisXL_V4.0_inpainting",
    dtype=torch.float16,
    variant="fp16",
    vae=vae,
).to("cuda")  # or "mps", "xpu", "cpu"

Подготовьте маску для итогового изображения после аутпейнта. Чтобы создать более естественный переход между исходным изображением и аутпейнт-фоном, размойте маску, чтобы она лучше сливалась с изображением.

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

Создайте более качественный промпт и передайте его в функцию 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
Update on GitHub