こちらのリリースノートにある ControlNet を複数使う Mutil-ControlNet で、 バッテンポーズをする美少女を作りたいと思います。
使用するモデル
モデルは Meina/MeinaMix_V11 を使用させていただきます。
元画像
元画像は 写真AC の バツのポーズをするサラリーマン の画像を使わせていただきます。
ControlNet で使用する画像を準備する
OpenPose
OpenPose の ControlNet は以前に上記の記事で試しています。ご参考まで。
from diffusers.utils import load_image from controlnet_aux import OpenposeDetector # 投入画像の準備 init_image_url = "./753215_s.jpg" init_image = load_image(init_image_url).resize((512, 512)) # コントロールイメージ作成 processor = OpenposeDetector.from_pretrained('lllyasviel/ControlNet') control_image = processor(init_image) control_image
元画像が 640 x 480 でしたが、アスペクト比気にせず 512x512 にリサイズしておきます。
OpenPose は無加工で使うので、そのまま変数に保持してても、ファイル出力しても良いかなと思います。
※本記事では1回ダウンロードしておきます。(Canny の方は加工するためにダウンロードするので手順を合わせるため)
Canny
Canny の ControlNet は以前に上記の記事で試しています。ご参考まで。
import cv2 from diffusers.utils import load_image import numpy as np from PIL import Image # 投入画像の準備 init_image_url = "./753215_s.jpg" init_image = load_image(init_image_url).resize((512, 512)) # コントロールイメージを作成するメソッド 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) control_image = make_canny_condition(init_image, 100, 200) control_image
加工するためにダウンロードします。
Canny の方は加工します
ControlNet を使用する
事前準備
OpenPose のコントロール画像、及び、Canny のコントロール画像を Google Colab アップロードします。
それぞれ control_image_openpose.png
, control_image_canny.png
とします。
まずは OpenPose の ControlNet のみで
import torch from diffusers import ControlNetModel, StableDiffusionControlNetPipeline, DPMSolverMultistepScheduler # OpenControlNet の準備 controlnet = ControlNetModel.from_pretrained( "lllyasviel/control_v11p_sd15_openpose", torch_dtype=torch.float16 ) # Pipeline の準備 pipe = StableDiffusionControlNetPipeline.from_pretrained( "Meina/MeinaMix_V11", torch_dtype=torch.float16, controlnet=controlnet ).to("cuda") pipe.enable_model_cpu_offload() # スケジューラーの設定 pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config, use_karras_sigmas=True)
from diffusers.utils import load_image # コントロール画像をロードする openpose_control_image = load_image("./openpose_control_image.png") # パイプライン実行 prompt = "good fingers, good hands, best quality, masterpiece, super fine illustration, anime style, 1 girl, cute, school uniform, standing" negative_prompt = "bad fingers, bad hands, missing fingers, worst quality,ugly,bad anatomy,jpeg artifacts" image = pipe( prompt, negative_prompt=negative_prompt, guidance_scale=7, num_inference_steps=30, image=openpose_control_image ).images[0] image
best quality, masterpiece (品質)
super fine illustration, anime style (スタイル)
1 girl, cute, school uniform (女の子)
standing (寝転がってる画像がよく出てしまったので)
worst quality,ugly,bad anatomy,jpeg artifacts (低品質が出力されないように)
プロンプトには細かいポーズは指定していません。
なかなか良き。
あとは手がバッテンポーズになって欲しいです。
いよいよ Multi-ControlNet
import torch from diffusers import ControlNetModel, StableDiffusionControlNetPipeline, DPMSolverMultistepScheduler # OpenPose の ControlNet の準備 controlnet_openpose = ControlNetModel.from_pretrained( "lllyasviel/control_v11p_sd15_openpose", torch_dtype=torch.float16 ) # Canny の ControlNet の準備 controlnet_canny = ControlNetModel.from_pretrained( "lllyasviel/control_v11p_sd15_canny", torch_dtype=torch.float16 ) # Pipeline の準備 pipe = StableDiffusionControlNetPipeline.from_pretrained( "Meina/MeinaMix_V11", torch_dtype=torch.float16, controlnet=[controlnet_openpose, controlnet_canny] ).to("cuda") pipe.enable_model_cpu_offload() # スケジューラーの設定 pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config, use_karras_sigmas=True)
from diffusers.utils import load_image # コントロール画像をロードする control_image_openpose = load_image("./openpose_control_image.png") control_image_canny = load_image("./canny_control_image.png") # パイプラインを実行 prompt = "good fingers, good hands, best quality, masterpiece, super fine illustration, anime style, 1 girl, cute, school uniform, standing" negative_prompt = "bad fingers, bad hands, missing fingers, worst quality,ugly,bad anatomy,jpeg artifacts" image = pipe( prompt, negative_prompt=negative_prompt, guidance_scale=7, num_inference_steps=30, generator=generator, image=[control_image_openpose, control_image_canny] ).images[0] image
しかし、期待通りのポーズを生成することができました。
まとめ
結構、狙い通りのポーズを生成することができました。
手の品質については、Canny の線画が雑なのであのような感じなのでしょう。
もっと、詳細に綺麗な手の線画を用意すればもっと綺麗な絵が出来上がりそうです。