# Outpainting

Outpainting extiende una imagen más allá de sus límites originales, lo que permite añadir, reemplazar o modificar elementos visuales en una imagen mientras se preserva la imagen original. Al igual que con [inpainting](../using-diffusers/inpaint), se desea rellenar el área blanca (en este caso, el área exterior de la imagen original) con nuevos elementos visuales manteniendo la imagen original (representada por una máscara de píxeles negros). Hay varias formas de realizar outpainting, como con [ControlNet](https://hf.co/blog/OzzyGT/outpainting-controlnet) o con [Differential Diffusion](https://hf.co/blog/OzzyGT/outpainting-differential-diffusion).

Esta guía te mostrará cómo hacer outpainting con un modelo de inpainting, ControlNet y un estimador de ZoeDepth.

Antes de comenzar, asegúrate de tener instalada la biblioteca [controlnet_aux](https://github.com/huggingface/controlnet_aux) para poder usar el estimador ZoeDepth.

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

## Preparación de imágenes

Comience seleccionando una imagen para ampliar y elimine el fondo con un Space como [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"
>

Por ejemplo, elimina el fondo de esta imagen de un par de zapatos.

  
    
    imagen original
  
  
    
    fondo eliminado
  

Los modelos de [Stable Diffusion XL (SDXL)](../api/pipelines/stable_diffusion/stable_diffusion_xl) funcionan mejor con imágenes de 1024x1024, pero puedes redimensionar la imagen a cualquier tamaño siempre que tu hardware tenga suficiente memoria para soportarlo. El fondo transparente de la imagen también debe reemplazarse por un fondo blanco. Crea una función (como la siguiente) que escale la imagen y la pegue sobre un fondo blanco.

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

Para evitar añadir detalles no deseados, utilice el estimador ZoeDepth para proporcionar orientación adicional durante la generación y garantizar que los zapatos se mantengan consistentes con la imagen original.

```py
zoe = ZoeDetector.from_pretrained("lllyasviel/Annotators")
image_zoe = zoe(white_bg_image, detect_resolution=512, image_resolution=1024)
image_zoe
```

    

## Outpaint

Una vez que tu imagen esté lista, puedes generar contenido en el área blanca alrededor de los zapatos con [controlnet-inpaint-dreamer-sdxl](https://hf.co/destitech/controlnet-inpaint-dreamer-sdxl), un ControlNet de SDXL entrenado para inpainting.

Carga el ControlNet de inpainting, el modelo ZoeDepth y el VAE, y pásalos a [StableDiffusionXLControlNetPipeline](/docs/diffusers/main/es/api/pipelines/controlnet_sdxl#diffusers.StableDiffusionXLControlNetPipeline). Después, puedes crear una función opcional `generate_image` (por comodidad) para hacer outpainting de una imagen inicial.

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

Pega la imagen original sobre la imagen inicial extendida. Mejorarás el fondo extendido en un paso posterior.

```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]
> Ahora es un buen momento para liberar algo de memoria si te estás quedando sin espacio.
>
> ```py
> pipeline=None
> torch.cuda.empty_cache()
> ```

Ahora que tienes una imagen inicial extendida, carga el [StableDiffusionXLInpaintPipeline](/docs/diffusers/main/es/api/pipelines/stable_diffusion/stable_diffusion_xl#diffusers.StableDiffusionXLInpaintPipeline) con el modelo [RealVisXL](https://hf.co/SG161222/RealVisXL_V4.0) para generar la imagen final extendida con una mejor calidad.

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

Prepara una máscara para la imagen final generada por outpainting. Para crear una transición más natural entre la imagen original y el fondo generado, difumina la máscara para que se integre mejor.

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

    

Cree un mejor prompt y páselo a la función `generate_outpaint` para generar la imagen final outpainted. Vuelva a pegar la imagen original sobre el fondo outpainted final.

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

    

