SadTalkerの設定をいろいろいじってみる(1枚の顔写真からしゃべっている動画を作成)

はじめに

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





このエントリーをはてなブックマークに追加