Diffusers documentation
アウトペインティング
アウトペインティング
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