Diffusers documentation

アウトペインティング

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は、画像を元の境界を超えて拡張する技術であり、元の画像を保持したまま、画像内の視覚要素を追加、置換、または変更できます。Inpaintingと同様に、元の画像(黒ピクセルのマスクで表されます)を維持しながら、白い領域(この場合は元の画像の外側)を新しい視覚要素で埋めたいです。Outpaintingにはいくつかの方法があり、ControlNetやDifferential Diffusionなどがあります。

このガイドでは、インペインティングモデル、ControlNet、およびZoeDepth推定器を使用してアウトペインティングを行う方法を紹介します。

開始する前に、ZoeDepth 推定器を使用できるように、controlnet_aux ライブラリがインストールされていることを確認してください。

!pip install -q controlnet_aux

画像の準備

アウトペイントに使用する画像を選択し、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

画像の準備が整ったら、インペインティング用に学習された SDXL ControlNet である controlnet-inpaint-dreamer-sdxl を使用して、靴の周囲の白い領域にコンテンツを生成できます。

インペインティング用の ControlNet、ZoeDepth モデル、VAE を読み込み、StableDiffusionXLControlNetPipeline に渡します。その後、初期画像をアウトペイントするための任意の generate_image 関数(利便性のため)を作成できます。

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