ジャコ Lab

プログラミング関連のメモ帳的ブログです

T2I-Adapter をもっと色々使ってみる (SD 1.4)

うなぎ

zako-lab929.hatenablog.com

前回の記事で T2I-Adapter というものを使ってみました。この記事では、ControlNet と比較しながらもっと色々な T2I-Adapter を使ってみようと思います。

ControlNet のときは1つ1つ丁寧に書いたけど、また1つ1つやるのは面倒なので一気にやりました!でも、SD 1.4 のやつだけで結構たいへんだったので SD 1.5 向けは次回がんばります。

Color Adapter (SD 1.4)

huggingface.co

これは前回の記事でやったやつですが、まとめ記事ということで掲載しておきます。

スクリプト全体

スクリプト全体 (折りたたみ)

投入画像の準備
from diffusers.utils import load_image
from PIL import Image

# 元画像
init_image_url = "https://huggingface.co/datasets/diffusers/docs-images/resolve/main/t2i-adapter/color_ref.png"
init_image = load_image(init_image_url)

# カラーパレット画像
input_image = init_image.resize((8, 8))
input_image = input_image.resize((512, 512), resample=Image.Resampling.NEAREST)
Adapter, Pipeline の準備
import torch
from diffusers import StableDiffusionAdapterPipeline, T2IAdapter

adapter = T2IAdapter.from_pretrained(
    "TencentARC/t2iadapter_color_sd14v1",
    torch_dtype=torch.float16
)
pipe = StableDiffusionAdapterPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    adapter=adapter,
    torch_dtype=torch.float16,
).to("cuda")
パイプラインの実行
from diffusers.utils import make_image_grid

image = pipe(
    "At night, glowing cubes in front of the beach",
    image=input_image,
    generator=torch.Generator("cuda").manual_seed(7),
).images[0]

make_image_grid([init_image, input_image, image], rows=1, cols=3)

実行結果

(左) カラーパレット 画像 | (右) Color Adapter での出力結果

Canny Adapter (SD 1.4)

huggingface.co

スクリプト全体

スクリプト全体 (折りたたみ)

事前定義
# Canny Edge を抽出するメソッド
def make_canny_condition(image, low_threshold, high_threshold):
    image = np.array(image)
    image = cv2.Canny(image, low_threshold, high_threshold)
    # image = image[:, :, None]
    # image = np.concatenate([image, image, image], axis=2)
    return Image.fromarray(image)
投入画像の準備
import cv2
import numpy as np
from diffusers.utils import load_image
from PIL import Image

# 元画像の準備
init_image_url = "https://huggingface.co/TencentARC/t2iadapter_canny_sd14v1/resolve/main/images/canny_input.png"
init_image = load_image(init_image_url)

# Canny Edge 画像
canny_image = make_canny_condition(init_image, 100, 200)
Adapter, Pipeline の準備
import torch
from diffusers import T2IAdapter, StableDiffusionAdapterPipeline

# アダプターの準備
adapter = T2IAdapter.from_pretrained(
    "TencentARC/t2iadapter_canny_sd14v1",
    torch_dtype=torch.float16
)

# パイプラインの準備
pipe = StableDiffusionAdapterPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    adapter=adapter,
    torch_dtype=torch.float16,
).to("cuda")
パイプラインの実行
from diffusers.utils import make_image_grid

# パイプラインの実行
prompt = "a rabbit wearing glasses"
image = pipe(
    prompt,
    image=canny_image,
    generator=torch.Generator("cuda").manual_seed(0),
).images[0]

# 出力結果
make_image_grid([init_image, canny_image, image], rows=1, cols=3)

実行結果

(左) Canny 画像 | (右) Canny Adapter での出力結果

T2I-Adapter vs ControlNet

(左) T2I-Adapter (Canny) | (右) ControlNet (Canny)

T2I-Adapter ControlNet
50/50 [00:13<00:00, 4.00it/s] 50/50 [00:20<00:00, 2.90it/s]

※T2I-Adapter は SD 1.4、ControlNet は SD 1.5 です。

Sketch Adapter (SD 1.4)

huggingface.co

Sketch Adapter は、インプット画像を作成するために PidiNetDetector を使用しているので、 ControlNet で言うところの SoftEdge に該当しそうです。

スクリプト全体

スクリプト全体 (折りたたみ)

投入画像の準備
from controlnet_aux import PidiNetDetector
from diffusers.utils import load_image

# 元画像の準備
init_image_url = "https://huggingface.co/TencentARC/t2iadapter_sketch_sd14v1/resolve/main/images/sketch_in.png"
init_image = load_image(init_image_url)

# Sketch 画像
detector = PidiNetDetector.from_pretrained('lllyasviel/Annotators')
sketch_image = detector(init_image)
Adapter, Pipeline の準備
import torch
from diffusers import T2IAdapter, StableDiffusionAdapterPipeline

# アダプターの準備
adapter = T2IAdapter.from_pretrained(
    "TencentARC/t2iadapter_zoedepth_sd15v1",
    torch_dtype=torch.float16
)

# パイプラインの準備
pipe = StableDiffusionAdapterPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    adapter=adapter,
    safety_checker=None,
    torch_dtype=torch.float16,
    variant="fp16"
).to('cuda')
パイプラインの実行
import torch
from diffusers.utils import make_image_grid

# パイプラインの実行
prompt = "royal chamber with fancy bed"
image = pipe(
    prompt,
    image=sketch_image,
    generator=torch.Generator().manual_seed(0)
).images[0]

# 出力結果
make_image_grid([init_image, sketch_image, image], rows=1, cols=3)

実行結果

(左) Sketch 画像 | (右) Sketch Adapter での出力結果

T2I-Adapter vs ControlNet

(左) T2I-Adapter (Sketch) | (右) ControlNet (SoftEdge)

T2I-Adapter ControlNet
50/50 [00:10<00:00, 5.08it/s] 50/50 [00:15<00:00, 3.68it/s]

※T2I-Adapter は SD 1.4、ControlNet は SD 1.5 です。

Depth Adapter (SD 1.4)

huggingface.co

スクリプト全体

スクリプト全体 (折りたたみ)

投入画像の準備
from controlnet_aux import MidasDetector
from diffusers.utils import load_image

# 元画像の準備
init_image_url = "https://huggingface.co/TencentARC/t2iadapter_depth_sd14v1/resolve/main/images/depth_input.png"
init_image = load_image(init_image_url)

# Depth 画像
detector = MidasDetector.from_pretrained("lllyasviel/Annotators")
depth_image = detector(init_image)
Adapter, Pipeline の準備
import torch
from diffusers import T2IAdapter, StableDiffusionAdapterPipeline

# アダプターの準備
adapter = T2IAdapter.from_pretrained(
    "TencentARC/t2iadapter_depth_sd14v1",
    torch_dtype=torch.float16
)

# パイプラインの準備
pipe = StableDiffusionAdapterPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    adapter=adapter,
    safety_checker=None,
    torch_dtype=torch.float16,
    variant="fp16"
).to('cuda')
パイプラインの実行
import torch
from diffusers.utils import make_image_grid

# パイプラインの実行
prompt = "storm trooper giving a speech"
image = pipe(
    prompt,
    image=depth_image,
    generator=torch.Generator().manual_seed(1)
).images[0]

# 出力結果
make_image_grid([init_image, depth_image, image], rows=1, cols=3)

実行結果

(左) Depth 画像 | (右) Depth Adapter での出力結果

T2I-Adapter vs ControlNet

(左) T2I-Adapter (Depth) | (右) ControlNet (Depth)

T2I-Adapter ControlNet
50/50 [00:07<00:00, 7.36it/s] 50/50 [00:12<00:00, 4.99it/s]

※T2I-Adapter は SD 1.4、ControlNet は SD 1.5 です。

OpenPose Adapter (SD 1.4)

huggingface.co

スクリプト全体

スクリプト全体 (折りたたみ)

投入画像の準備
from controlnet_aux import OpenposeDetector
from diffusers.utils import load_image

# 元画像の準備
init_image_url = "https://huggingface.co/TencentARC/t2iadapter_openpose_sd14v1/resolve/main/images/openpose_input.png"
init_image = load_image(init_image_url)

# OpenPose 画像
detector = OpenposeDetector.from_pretrained('lllyasviel/ControlNet')
openpose_image = detector(init_image)
Adapter, Pipeline の準備
import torch
from diffusers import T2IAdapter, StableDiffusionAdapterPipeline

# アダプターの準備
adapter = T2IAdapter.from_pretrained(
    "TencentARC/t2iadapter_openpose_sd14v1",
    torch_dtype=torch.float16
)

# パイプラインの準備
pipe = StableDiffusionAdapterPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    adapter=adapter,
    safety_checker=None,
    torch_dtype=torch.float16,
    variant="fp16"
).to('cuda')
パイプラインの実行
import torch
from diffusers.utils import make_image_grid

# パイプラインの実行
prompt="iron man flying"
image = pipe(
    prompt,
    image=openpose_image,
    generator=torch.Generator().manual_seed(1)
).images[0]

# 出力結果
make_image_grid([init_image, openpose_image, image], rows=1, cols=3)

実行結果

(左) OpenPose 画像 | (右) OpenPose Adapter での出力結果

T2I-Adapter vs ControlNet

(左) T2I-Adapter (OpenPose) | (右) ControlNet (OpenPose)

T2I-Adapter ControlNet
50/50 [00:12<00:00, 4.52it/s] 50/50 [00:18<00:00, 3.10it/s]

※T2I-Adapter は SD 1.4、ControlNet は SD 1.5 です。

KeyPose Adapter (SD 1.4)

KeyPose Adapter というものもあるらしいですが、モデルカードが空っぽだったので詳細は不明です

huggingface.co

Seg Adapter (SD 1.4)

huggingface.co

スクリプト全体

スクリプト全体 (折りたたみ)

事前定義
import torch
import numpy as np
from transformers import AutoImageProcessor, UperNetForSemanticSegmentation
from PIL import Image

ada_palette = np.asarray([
    [0, 0, 0],
    [120, 120, 120],
    [180, 120, 120],
    [6, 230, 230],
    [80, 50, 50],
    [4, 200, 3],
    [120, 120, 80],
    [140, 140, 140],
    [204, 5, 255],
    [230, 230, 230],
    [4, 250, 7],
    [224, 5, 255],
    [235, 255, 7],
    [150, 5, 61],
    [120, 120, 70],
    [8, 255, 51],
    [255, 6, 82],
    [143, 255, 140],
    [204, 255, 4],
    [255, 51, 7],
    [204, 70, 3],
    [0, 102, 200],
    [61, 230, 250],
    [255, 6, 51],
    [11, 102, 255],
    [255, 7, 71],
    [255, 9, 224],
    [9, 7, 230],
    [220, 220, 220],
    [255, 9, 92],
    [112, 9, 255],
    [8, 255, 214],
    [7, 255, 224],
    [255, 184, 6],
    [10, 255, 71],
    [255, 41, 10],
    [7, 255, 255],
    [224, 255, 8],
    [102, 8, 255],
    [255, 61, 6],
    [255, 194, 7],
    [255, 122, 8],
    [0, 255, 20],
    [255, 8, 41],
    [255, 5, 153],
    [6, 51, 255],
    [235, 12, 255],
    [160, 150, 20],
    [0, 163, 255],
    [140, 140, 140],
    [250, 10, 15],
    [20, 255, 0],
    [31, 255, 0],
    [255, 31, 0],
    [255, 224, 0],
    [153, 255, 0],
    [0, 0, 255],
    [255, 71, 0],
    [0, 235, 255],
    [0, 173, 255],
    [31, 0, 255],
    [11, 200, 200],
    [255, 82, 0],
    [0, 255, 245],
    [0, 61, 255],
    [0, 255, 112],
    [0, 255, 133],
    [255, 0, 0],
    [255, 163, 0],
    [255, 102, 0],
    [194, 255, 0],
    [0, 143, 255],
    [51, 255, 0],
    [0, 82, 255],
    [0, 255, 41],
    [0, 255, 173],
    [10, 0, 255],
    [173, 255, 0],
    [0, 255, 153],
    [255, 92, 0],
    [255, 0, 255],
    [255, 0, 245],
    [255, 0, 102],
    [255, 173, 0],
    [255, 0, 20],
    [255, 184, 184],
    [0, 31, 255],
    [0, 255, 61],
    [0, 71, 255],
    [255, 0, 204],
    [0, 255, 194],
    [0, 255, 82],
    [0, 10, 255],
    [0, 112, 255],
    [51, 0, 255],
    [0, 194, 255],
    [0, 122, 255],
    [0, 255, 163],
    [255, 153, 0],
    [0, 255, 10],
    [255, 112, 0],
    [143, 255, 0],
    [82, 0, 255],
    [163, 255, 0],
    [255, 235, 0],
    [8, 184, 170],
    [133, 0, 255],
    [0, 255, 92],
    [184, 0, 255],
    [255, 0, 31],
    [0, 184, 255],
    [0, 214, 255],
    [255, 0, 112],
    [92, 255, 0],
    [0, 224, 255],
    [112, 224, 255],
    [70, 184, 160],
    [163, 0, 255],
    [153, 0, 255],
    [71, 255, 0],
    [255, 0, 163],
    [255, 204, 0],
    [255, 0, 143],
    [0, 255, 235],
    [133, 255, 0],
    [255, 0, 235],
    [245, 0, 255],
    [255, 0, 122],
    [255, 245, 0],
    [10, 190, 212],
    [214, 255, 0],
    [0, 204, 255],
    [20, 0, 255],
    [255, 255, 0],
    [0, 153, 255],
    [0, 41, 255],
    [0, 255, 204],
    [41, 0, 255],
    [41, 255, 0],
    [173, 0, 255],
    [0, 245, 255],
    [71, 0, 255],
    [122, 0, 255],
    [0, 255, 184],
    [0, 92, 255],
    [184, 255, 0],
    [0, 133, 255],
    [255, 214, 0],
    [25, 194, 194],
    [102, 255, 0],
    [92, 0, 255],
])

# Seg を抽出するメソッド
def make_seg_condition(image):
    image_processor = AutoImageProcessor.from_pretrained("openmmlab/upernet-convnext-small")

    pixel_values = image_processor(init_image, return_tensors="pt").pixel_values
    with torch.no_grad():
        image_segmentor = UperNetForSemanticSegmentation.from_pretrained("openmmlab/upernet-convnext-small")
        outputs = image_segmentor(pixel_values)

    seg = image_processor.post_process_semantic_segmentation(outputs, target_sizes=[image.size[::-1]])[0]
    color_seg = np.zeros((seg.shape[0], seg.shape[1], 3), dtype=np.uint8) # height, width, 3

    for label, color in enumerate(ada_palette):
        color_seg[seg == label, :] = color
    color_seg = color_seg.astype(np.uint8)

    return Image.fromarray(color_seg)
投入画像の準備
from diffusers.utils import load_image

# 元画像の準備
init_image_url = "https://huggingface.co/TencentARC/t2iadapter_seg_sd14v1/resolve/main/images/seg_input.jpeg"
init_image = load_image(init_image_url)

# Seg 画像
seg_image = make_seg_condition(init_image)
Adapter, Pipeline の準備
import torch
from diffusers import T2IAdapter, StableDiffusionAdapterPipeline

# アダプターの準備
adapter = T2IAdapter.from_pretrained(
    "TencentARC/t2iadapter_seg_sd14v1",
    torch_dtype=torch.float16
)

# パイプラインの準備
pipe = StableDiffusionAdapterPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    adapter=adapter,
    safety_checker=None,
    torch_dtype=torch.float16,
    variant="fp16"
).to('cuda')
パイプラインの実行
import torch
from diffusers.utils import make_image_grid

prompt = "motorcycles driving"
image = pipe(
    prompt,
    image=seg_image,
    generator=torch.Generator().manual_seed(0)
).images[0]


# 出力結果
make_image_grid([init_image, seg_image, image], rows=1, cols=3)

実行結果

(左) Seg 画像 | (右) Seg Adapter での出力結果

T2I-Adapter vs ControlNet

(左) T2I-Adapter (Seg) | (右) ControlNet (Seg)

T2I-Adapter ControlNet
50/50 [00:08<00:00, 6.19it/s] 50/50 [00:14<00:00, 4.16it/s]

※T2I-Adapter は SD 1.4、ControlNet は SD 1.5 です。