[Wav2Lip] AIで任意の動画を任意の音声に合わせて喋らせる

2023年1月20日金曜日

Artificial Intelligence

本記事では、Wav2Lipと呼ばれる機械学習手法を用いて任意の動画の人物の唇の動きを、任意の音声に合わせて動かす方法をご紹介します。

アイキャッチ

Wav2Lip

概要

Wav2Lipは、任意のビデオに映る人物の唇の動きを、ターゲットの音声に一致させるlip-syncing技術です。

従来のリップシンクでは、動的で制約のない会話中の顔のビデオでは、唇の動きを正確にモーフィングすることができず、ビデオが上手く音声と同期しないという問題がありました。

Wav2Lipでは、事前に十分に訓練されたPre-trained Lip-Sync Expertから学習することによって正確なリップシンクを生成します。また同様に事前訓練されたDiscriminatorを用いてリップシンクエラーを検出することで視覚品質を向上させています。

Architecture
出典: A Lip Sync Expert Is All You Need for Speech to Lip Generation In The Wild

詳細はこちらの論文をご参照ください。

本記事では上記手法を用いて、任意の動画に映る人物の唇の動きを、任意の音声に同期させていきます。

デモ(Colaboratory)

それでは、実際に動かしながらリップシンクを行っていきます。
ソースコードは本記事にも記載していますが、下記のGitHubでも取得可能です。
GitHub - Colaboratory demo

また、下記から直接Google Colaboratoryで開くこともできます。
Open In Colab

なお、このデモはPythonで実装しています。
Pythonの実装に不安がある方、Pythonを使った機械学習について詳しく勉強したい方は、以下の書籍やオンライン講座などがおすすめです。

取り扱いに関する免責事項

これからご紹介する技術はあくまでご自身の顔画像処理技術の理解を深めるためにのみご活用ください。本記事を参考にして生じたいかなる損害に関しても当ブログは責任を負いません。

環境セットアップ

それではセットアップしていきます。 Colaboratoryを開いたら下記を設定しGPUを使用するようにしてください。

「ランタイムのタイプを変更」→「ハードウェアアクセラレータ」をGPUに変更

初めにGithubからソースコードを取得します。

%cd /content

!git clone https://github.com/zabique/Wav2Lip

# Commits on Aug 10, 2021使用
%cd /content/Wav2Lip
!git checkout b9759a3467cb1b7519f1a3b91f5a84cb4bc1ae4a

次にライブラリをインストールします。

%cd /content/Wav2Lip

!pip install -r requirements.txt
!pip install moviepy==0.2.3.5 imageio==2.4.1
!pip install yt-dlp
!pip install -U librosa==0.8.1

最後にライブラリをインポートします。

%cd /content/Wav2Lip

from yt_dlp import YoutubeDL
from moviepy.video.fx.resize import resize
from moviepy.editor import VideoFileClip
from IPython.display import Audio, display

以上で環境セットアップは完了です。

学習済みモデルのセットアップ

続いて、論文発表元が公開する学習済みモデルをロードします。

%cd /content/Wav2Lip

#download the pretrained model
!wget -c https://iiitaphyd-my.sharepoint.com/personal/radrabha_m_research_iiit_ac_in/_layouts/15/download.aspx?share=EdjI7bZlgApMqsVoEUUXpLsBxqXbn5z8VTmoxp55YNDcIA \
      -O ./checkpoints/wav2lip_gan.pth
!wget -c https://iiitaphyd-my.sharepoint.com/:u:/g/personal/radrabha_m_research_iiit_ac_in/Eb3LEzbfuKlJiR600lQWRxgBIY27JZg80f7V9jtMfbNDaQ?e=TBFBVW \
      -O ./checkpoints/wav2lip.pth
!pip install https://raw.githubusercontent.com/AwaleSajil/ghc/master/ghc-1.0-py3-none-any.whl

#download pretrained model for face detection
!wget -c https://www.adrianbulat.com/downloads/python-fan/s3fd-619a316812.pth \
      -O ./face_detection/detection/sfd/s3fd.pth

入力動画・音声のセットアップ

Youtubeから入力動画と音声をダウンロードします。
まず、人物の顔が映る動画をダウンロードします。

video_url = 'https://www.youtube.com/watch?v=-Xvpo0A5X6g' #@param {type:"string"}

#@markdown 動画の切り抜き範囲(秒)を指定してください。\
#@markdown 30秒以上の場合OOM発生の可能性が高いため注意
start_sec =  30#@param {type:"integer"}
end_sec =  35#@param {type:"integer"}

(start_pt, end_pt) = (start_sec, end_sec)

!mkdir input_video

download_resolution = 720
full_video_path = './input_video/full_video.mp4'
input_clip_path = './input_video/clip_video.mp4'

# 動画ダウンロード
ydl_opts = {'format': f'best[height<={download_resolution}]', 'overwrites': True, 'outtmpl': full_video_path}
with YoutubeDL(ydl_opts) as ydl:
    ydl.download([video_url])

# 指定区間切り抜き
with VideoFileClip(full_video_path) as video:
    subclip = video.subclip(start_pt, end_pt)
    subclip.write_videofile(input_clip_path)

続いて動画をダウンロードし、音声を抽出します。

video_url = 'https://www.youtube.com/watch?v=fD-yyMzF8lI' #@param {type:"string"}

#@markdown 動画の切り抜き範囲(秒)を指定してください。\
#@markdown 30秒以上の場合OOM発生の可能性が高いため注意
start_sec =  63#@param {type:"integer"}
end_sec =  68#@param {type:"integer"}

(start_pt, end_pt) = (start_sec, end_sec)

!mkdir input_audio

download_resolution = 720
full_video_path = './input_audio/full_video_en.mp4'
input_clip_path = './input_audio/clip_video_en.mp4'
input_audio_path = './input_audio/audio.mp3'

# 動画ダウンロード
ydl_opts = {'format': f'best[height<={download_resolution}]', 'overwrites': True, 'outtmpl': full_video_path}
with YoutubeDL(ydl_opts) as ydl:
    ydl.download([video_url])

# 指定区間切り抜き
with VideoFileClip(full_video_path) as video:
    subclip = video.subclip(start_pt, end_pt)
    subclip.write_videofile(input_clip_path)

# 音声抽出
videoclip = VideoFileClip(input_clip_path)
audioclip = videoclip.audio
audioclip.write_audiofile(input_audio_path)

Wav2Lip

動画と音声が揃ったので、リップシンクを実行します。

%cd /content/Wav2Lip

!python inference.py \
  --checkpoint_path checkpoints/wav2lip_gan.pth \
  --face ./input_video/clip_video.mp4 \
  --audio ./input_audio/audio.mp3

出力結果は以下の通りです。

まとめ

本記事では、Wav2Lipを用いて、任意の動画でリップシンクを用いる方法をご紹介しました。

また本記事では、機械学習を動かすことにフォーカスしてご紹介しました。
もう少し学術的に体系立てて学びたいという方には以下の書籍などがお勧めです。ぜひご一読下さい。


また動かせるだけから理解して応用できるエンジニアの足掛かりに下記のUdemyなどもお勧めです。

参考文献

1.  論文 - A Lip Sync Expert Is All You Need for Speech to Lip Generation In The Wild

2. GitHub - Rudrabha/Wav2Lip

AIで副業ならココから!

まずは無料会員登録

プロフィール

メーカーで研究開発を行う現役エンジニア
組み込み機器開発や機会学習モデル開発に従事しています

本ブログでは最新AI技術を中心にソースコード付きでご紹介します


Twitter

カテゴリ

このブログを検索

ブログ アーカイブ

TeDokology