はじめに
SadTalkerについてはこちらを見て下さい。touch-sp.hatenablog.com
今回は設定をいろいろいじってみました。
用意する顔写真
どうせなら顔写真も生成AIに作らせようということでBRAV5(Beautiful Realistic Asians V5)を使って用意しました。作った時の設定は記事の後半にのせておきます。BRAV5すごいです。結果
本当は音声があるのですがGIFに変換してブログに載せているので画像だけになっています。動画を参照する場合
--enhancer gfpgan
--enhancer RestoreFormer
一番右が参照動画です。こちらから使わせて頂きました。
左から1番目:参照なし
左から2番目:「--ref_eyeblink」を指定
左から3番目:「--ref_pose」を指定
左から2番目:「--ref_eyeblink」と「--ref_pose」の両方を指定
顔の動きを指定する場合(動画参照なし)
yaw
pitch
roll
Appendix 1(動画を参照してSadTalkerを実行)
python inference.py \ --driven_audio sample.mp3 \ --source_image face512.png \ --ref_eyeblink sample.mp4 \ --ref_pose sample.mp4 \ --enhancer gfpgan
python inference.py \ --driven_audio sample.mp3 \ --source_image face512.png \ --ref_eyeblink sample.mp4 \ --ref_pose sample.mp4 \ --enhancer RestoreFormer
「--ref_eyeblink」「--ref_pose」はオプションです。今回はそれらの有無で結果がどう変わるかを調べました。
Appendix 2(顔の動きを指定してSadTalkerを実行)
python inference.py \ --driven_audio sample.mp3 \ --source_image trim512.png \ --input_yaw 0 -20 20 0 \ --enhancer gfpgan
python inference.py \ --driven_audio sample.mp3 \ --source_image trim512.png \ --input_pitch 0 -20 20 0 \ --enhancer gfpgan
python inference.py \ --driven_audio sample.mp3 \ --source_image trim512.png \ --input_roll 0 -20 20 0 \ --enhancer gfpgan
Appendix 3(顔写真の作り方)
DiffusersからBRAV5を使用しました。最後にGFPGANでレストレーションしています。Pythonスクリプトと実行方法をのせておきますので再現できると思います。プロンプトを長々と書くのは苦手なので簡潔になっています。一人目
from diffusers import DiffusionPipeline, EulerAncestralDiscreteScheduler import torch import argparse parser = argparse.ArgumentParser() parser.add_argument( '--seed', type=int, default=20000, help='the seed (for reproducible sampling)', ) parser.add_argument( '--n_samples', type=int, default=5, help='how many samples to produce for each given prompt', ) parser.add_argument( '--steps', type=int, default=25, help='num_inference_steps', ) args = parser.parse_args() seed = args.seed steps = args.steps scale = 7.0 model_id = "./BRAV5" pipe = DiffusionPipeline.from_pretrained( model_id, custom_pipeline="lpw_stable_diffusion", safety_checker=None, torch_dtype=torch.float16) pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config) pipe.to("cuda") prompt = "(Best quality, 8k, 32k, Masterpiece, UHD:1.2), Photo of Pretty Japanese woman" negative_prompt = "(Worst Quality:2.0)" for i in range(args.n_samples): temp_seed = seed + i * 100 generator = torch.Generator(device="cuda").manual_seed(temp_seed) image = pipe( prompt, negative_prompt=negative_prompt, generator=generator, num_inference_steps=steps, guidance_scale=scale, max_embeddings_multiples=3).images[0] image.save(f"./step{steps}_seed{temp_seed}.png")
python txt2img.py --seed 21800 --n_samples 1 --steps 28
二人目
from diffusers import DiffusionPipeline, EulerAncestralDiscreteScheduler import torch import argparse parser = argparse.ArgumentParser() parser.add_argument( '--seed', type=int, default=20000, help='the seed (for reproducible sampling)', ) parser.add_argument( '--n_samples', type=int, default=5, help='how many samples to produce for each given prompt', ) parser.add_argument( '--steps', type=int, default=25, help='num_inference_steps', ) args = parser.parse_args() seed = args.seed steps = args.steps scale = 7.0 model_id = "./BRAV5" pipe = DiffusionPipeline.from_pretrained( model_id, custom_pipeline="lpw_stable_diffusion", safety_checker=None, torch_dtype=torch.float16) pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config) pipe.load_textual_inversion("embeddings/EasyNegative.safetensors", token="EasyNegative") pipe.load_textual_inversion("embeddings/ng_deepnegative_v1_75t.pt", token="ng_deepnegative_v1_75t") pipe.to("cuda") prompt = "(masterpiece:1.3), (8k, photorealistic, RAW photo, best quality: 1.4), absurdres, attractive, ultra high res, ultra realistic, highly detailed, golden ratio, photo of pretty Japanese woman, short hair" negative_prompt = "EasyNegative, ng_deepnegative_v1_75t, (Worst Quality:2.0)" for i in range(args.n_samples): temp_seed = seed + i * 100 generator = torch.Generator(device="cuda").manual_seed(temp_seed) image = pipe( prompt, negative_prompt=negative_prompt, generator=generator, num_inference_steps=steps, guidance_scale=scale, max_embeddings_multiples=3, width=768, height=768, ).images[0] image.save(f"./step{steps}_seed{temp_seed}.png")
python txt2img.py --seed 20700 --n_samples 1 --steps 25