# Outpainting

L’outpainting étend une image au-delà de ses limites d’origine, vous permettant d’ajouter, de remplacer ou de modifier des éléments visuels tout en préservant l’image initiale. Tout comme pour l’[inpainting](../using-diffusers/inpaint), l’objectif est de combler la zone blanche (ici, la zone située à l’extérieur de l’image d’origine) avec de nouveaux éléments visuels, tout en conservant l’image d’origine (représentée par un masque de pixels noirs). Il existe plusieurs méthodes pour réaliser un outpainting, par exemple à l’aide d’un [ControlNet](https://hf.co/blog/OzzyGT/outpainting-controlnet) ou de la [Differential Diffusion](https://hf.co/blog/OzzyGT/outpainting-differential-diffusion).

Ce guide vous montre comment effectuer un outpainting avec un modèle d'inpainting, ControlNet et un estimateur ZoeDepth.

Avant de commencer, assurez-vous d'avoir installé la bibliothèque [controlnet_aux](https://github.com/huggingface/controlnet_aux) afin de pouvoir utiliser l'estimateur ZoeDepth.

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

## Préparation des images

Commencez par choisir une image à outpainter et supprimez son arrière-plan à l'aide d'un Space comme [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"
>

Par exemple, supprimez l'arrière-plan de cette image d'une paire de chaussures.

  
    
    image d'origine
  
  
    
    fond supprimé
  

Les modèles [Stable Diffusion XL (SDXL)](../api/pipelines/stable_diffusion/stable_diffusion_xl) fonctionnent de manière optimale avec des images de 1024x1024, mais vous pouvez redimensionner l’image à n’importe quelle taille, à condition que votre matériel dispose de mémoire suffisante pour le supporter. Le fond transparent de l’image doit également être remplacé par un fond blanc. Créez une fonction (comme celle ci-dessous) qui met à l’échelle et colle l’image sur un fond blanc.

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

Pour éviter d’ajouter des détails superflus, utilisez l’estimateur ZoeDepth pour fournir des indications supplémentaires lors de la génération et vous assurer que les chaussures restent cohérentes avec l’image d’origine.

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

    

## Outpaint

Une fois votre image prête, vous pouvez générer du contenu dans la zone blanche autour des chaussures avec [controlnet-inpaint-dreamer-sdxl](https://hf.co/destitech/controlnet-inpaint-dreamer-sdxl), un ControlNet SDXL entraîné pour l'inpainting.

Chargez le ControlNet d'inpainting, le modèle ZoeDepth et le VAE, puis transmettez-les à [StableDiffusionXLControlNetPipeline](/docs/diffusers/main/fr/api/pipelines/controlnet_sdxl#diffusers.StableDiffusionXLControlNetPipeline). Vous pouvez ensuite créer une fonction optionnelle `generate_image` (pour plus de commodité) afin d'outpaint une image initiale.

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

Collez l'image d'origine sur l'image initialement outpaintée. Vous améliorerez l'arrière-plan outpainté à une étape ultérieure.

```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]
> C'est le bon moment pour libérer de la mémoire si vous êtes à court !
>
> ```py
> pipeline=None
> torch.cuda.empty_cache()
> ```

Maintenant que vous disposez d'une image outpaintée initiale, chargez le [StableDiffusionXLInpaintPipeline](/docs/diffusers/main/fr/api/pipelines/stable_diffusion/stable_diffusion_xl#diffusers.StableDiffusionXLInpaintPipeline) avec le modèle [RealVisXL](https://hf.co/SG161222/RealVisXL_V4.0) pour générer l'image outpaintée finale avec une meilleure qualité.

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

Préparez un masque pour l'image finale après outpainting. Pour créer une transition plus naturelle entre l'image d'origine et l'arrière-plan généré, appliquez un flou au masque afin de faciliter son intégration.

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

    

Créez un meilleur prompt et transmettez-le à la fonction `generate_outpaint` pour générer l'image finale outpaintée. De nouveau, superposez l'image originale sur le fond outpainté 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
```

    

