# Outpainting

Outpainting расширяет изображение за пределы его исходных границ, позволяя добавлять, заменять или изменять визуальные элементы, сохраняя при этом исходное изображение. Как и в случае с [inpainting](../using-diffusers/inpaint), вам нужно заполнить белую область (в данном случае — область за пределами исходного изображения) новыми визуальными элементами, сохранив исходное изображение (представленное маской из чёрных пикселей). Существует несколько способов outpainting, например, с помощью [ControlNet](https://hf.co/blog/OzzyGT/outpainting-controlnet) или [Differential Diffusion](https://hf.co/blog/OzzyGT/outpainting-differential-diffusion).

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

Перед началом убедитесь, что библиотека [controlnet_aux](https://github.com/huggingface/controlnet_aux) установлена, чтобы вы могли использовать оценщик ZoeDepth.

```py
!pip install -q controlnet_aux
```

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

Начните с выбора изображения для outpainting и удалите фон с помощью Space, например [BRIA-RMBG-1.4](https://hf.co/spaces/briaai/BRIA-RMBG-1.4).

<iframe src="https://briaai-bria-rmbg-1-4.hf.space" frameborder="0" width="850" height="450"
>

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

  
    
    original image
  
  
    
    фон удален
  

Модели [Stable Diffusion XL (SDXL)](../api/pipelines/stable_diffusion/stable_diffusion_xl) лучше всего работают с изображениями размером 1024x1024, но вы можете изменить размер изображения до любого значения, если вашей аппаратной части достаточно памяти для этого. Прозрачный фон на изображении также следует заменить на белый. Создайте функцию (например, такую, как приведена ниже), которая масштабирует изображение и наклеивает его на белый фон.

```py
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 для предоставления дополнительных ориентиров при генерации и обеспечения согласованности обуви с исходным изображением.

```py
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](https://hf.co/destitech/controlnet-inpaint-dreamer-sdxl), SDXL ControlNet, обученного для inpainting.

Загрузите ControlNet для inpainting, модель ZoeDepth и VAE и передайте их в [StableDiffusionXLControlNetPipeline](/docs/diffusers/v0.43.0/ru/api/pipelines/controlnet_sdxl#diffusers.StableDiffusionXLControlNetPipeline). Затем вы можете создать необязательную функцию `generate_image` (для удобства), чтобы выполнить outpainting исходного изображения.

```py
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)
```

Наложите исходное изображение на первоначальное изображение с расширенным фоном. Вы улучшите расширенный фон на следующем шаге.

```py
x = (1024 - resized_img.width) // 2
y = (1024 - resized_img.height) // 2
temp_image.paste(resized_img, (x, y), resized_img)
temp_image
```

    

> [!TIP]
> Сейчас самое время освободить память, если её осталось мало!
>
> ```py
> pipeline=None
> torch.cuda.empty_cache()
> ```

Теперь, когда у вас есть начальное изображение с расширенной областью, загрузите [StableDiffusionXLInpaintPipeline](/docs/diffusers/v0.43.0/ru/api/pipelines/stable_diffusion/stable_diffusion_xl#diffusers.StableDiffusionXLInpaintPipeline) с моделью [RealVisXL](https://hf.co/SG161222/RealVisXL_V4.0), чтобы сгенерировать финальное изображение с расширенной областью более высокого качества.

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

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

```py
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`, чтобы сгенерировать итоговое изображение с расширенным фоном. Снова наложите исходное изображение на итоговый фон.

```py
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
```

    

