MediaPipe: バーチャル ヒューマンをよりリアルに

7月 10, 2023
Daniel Ta QA Test Team

KDDI αU の XR 開発チームによるゲスト投稿です

以下の投稿で言及されている情報、用途、応用方法は、ゲスト投稿者である KDDI に帰属するものであることにご留意ください。

kddi1
KDDI は、バーチャル ヒューマン「メタコ」に、テキスト読み上げ機能とクラウド レンダリング技術を統合しています

VTuber(バーチャル YouTuber)は、コンピュータ グラフィックスによって生成されたバーチャル アバターを使用するオンライン エンターテイナーです。このデジタル トレンドは 2010 年代半ばに日本で生まれ、オンラインにおける世界的な現象となりました。VTuber の大半は、アバターのデザインを使用する YouTuber またはライブ ストリーマーで、英語と日本語を話します。

KDDI は、4,000 万人以上の顧客を持つ日本の通信事業者です。自社の 5G ネットワーク向けに構築したさまざまなテクノロジーをテストしたいと考えていた KDDI ですが、微妙な所作や人間らしい表情をリアルタイムで表現することは難しい課題でした。

リアルタイムでバーチャル ヒューマンを作成する

5 月の Google I/O 2023 で発表された MediaPipe フェイス ランドマーカー ソリューションは、顔のランドマークを検出し、ブレンドシェイプ スコアを出力して、ユーザーの表情を反映する 3D の顔モデルをレンダリングします。MediaPipe フェイス ランドマーカー ソリューションにより、KDDI と Google パートナー イノベーション チームは、アバターにリアルさを与えることに成功しました。

技術的な実装

KDDI のデベロッパーは、Mediapipe の強力で効率的な Python パッケージを使用して、人の顔の特徴を検出し、52 個のブレンドシェイプをリアルタイムで抽出することができました。

import mediapipe as mp
from mediapipe.tasks import python as mp_python
 
MP_TASK_FILE = "face_landmarker_with_blendshapes.task"
 
class FaceMeshDetector:
 
    def __init__(self):
        with open(MP_TASK_FILE, mode="rb") as f:
            f_buffer = f.read()
        base_options = mp_python.BaseOptions(model_asset_buffer=f_buffer)
        options = mp_python.vision.FaceLandmarkerOptions(
            base_options=base_options,
            output_face_blendshapes=True,
            output_facial_transformation_matrixes=True,
            running_mode=mp.tasks.vision.RunningMode.LIVE_STREAM,
            num_faces=1,
            result_callback=self.mp_callback)
        self.model = mp_python.vision.FaceLandmarker.create_from_options(
            options)
 
        self.landmarks = None
        self.blendshapes = None
        self.latest_time_ms = 0
 
    def mp_callback(self, mp_result, output_image, timestamp_ms: int):
        if len(mp_result.face_landmarks) >= 1 and len(
                mp_result.face_blendshapes) >= 1:
 
            self.landmarks = mp_result.face_landmarks[0]
            self.blendshapes = [b.score for b in mp_result.face_blendshapes[0]]
 
    def update(self, frame):
        t_ms = int(time.time() * 1000)
        if t_ms <= self.latest_time_ms:
            return
 
        frame_mp = mp.Image(image_format=mp.ImageFormat.SRGB, data=frame)
        self.model.detect_async(frame_mp, t_ms)
        self.latest_time_ms = t_ms
 
    def get_results(self):
        return self.landmarks, self.blendshapes

Firebase Realtime Database には、52 個のブレンドシェイプの浮動小数点数値が格納されています。各行は特定のブレンドシェイプに対応しており、順番に表示されます。

_neutral, 
browDownLeft, 
browDownRight, 
browInnerUp,
browOuterUpLeft,
...

これらのブレンドシェイプの値は、カメラが起動して FaceMesh モデルが実行されている間、リアルタイムで継続的に更新されます。データベースは、フレームごとにブレンドシェイプの最新の値を反映し、FaceMesh モデルによって検出された顔の表情の動的な変化をキャプチャします。

kddi2

ブレンドシェイプのデータを抽出したら、次のステップとして、そのデータを Firebase Realtime Database に送信します。この高度なデータベース システムを活用することで、リアルタイム データがシームレスにクライアントに送信されます。これにより、サーバーのスケーラビリティに関する懸念が解消され、KDDI は、ユーザー エクスペリエンスを合理化することに集中できます。

import concurrent.futures
import time
 
import cv2
import firebase_admin
import mediapipe as mp
import numpy as np
from firebase_admin import credentials, db
 
pool = concurrent.futures.ThreadPoolExecutor(max_workers=4)
 
cred = credentials.Certificate('your-certificate.json')
firebase_admin.initialize_app(
    cred, {
        'databaseURL': 'https://your-project.firebasedatabase.app/'
    })
ref = db.reference('projects/1234/blendshapes')
 
def main():
    facemesh_detector = FaceMeshDetector()
    cap = cv2.VideoCapture(0)
 
    while True:
        ret, frame = cap.read()
 
        facemesh_detector.update(frame)
        landmarks, blendshapes = facemesh_detector.get_results()
        if (landmarks is None) or (blendshapes is None):
            continue
 
        blendshapes_dict = {k: v for k, v in enumerate(blendshapes)}
        exe = pool.submit(ref.set, blendshapes_dict)
 
        cv2.imshow('frame', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
 
    cap.release()
    cv2.destroyAllWindows()
    exit()

さらにデベロッパーは、ブレンドシェイプのデータを Firebase Realtime Database から Google Cloud の Immersive Stream for XR インスタンスにリアルタイムでシームレスに送信します。Google Cloud の Immersive Stream for XR は、Unreal Engine プロジェクトをクラウドで実行し、写真のようにリアルで没入感のある 3D と拡張現実(AR)のエクスペリエンスをレンダリングし、スマートフォンやブラウザにリアルタイムでストリーミングするマネージド サービスです。

この統合によって KDDI は、キャラクターの顔のアニメーションを制御し、フェイシャル アニメーションを最小限のレイテンシでリアルタイムにストリーミングできるようになり、ユーザー エクスペリエンスが没入感の高いものになりました。

Immersive Stream for XR によって実行される Unreal Engine 側では、Firebase C++ SDK を使用して Firebase からデータをシームレスに受信します。データベース リスナーを確立することで、Firebase Realtime Database のテーブルで更新が発生したら、即座にブレンドシェイプの値を取得できます。この統合により、最新のブレンドシェイプのデータにリアルタイムでアクセスできるようになり、Unreal Engine プロジェクトにおいて動的で応答性の高いフェイシャル アニメーションを構築することが可能になります。

kddi5

Firebase SDK からブレンドシェイプの値を取得したら、アニメーション ブループリントの「Modify Curve」ノードを使用して、Unreal Engine で顔のアニメーションを制御することができます。各ブレンドシェイプ値はフレームごとにキャラクターに割り当てられるため、キャラクターの顔の表情を正確かつリアルタイムに制御できます。

kddi6

Unreal Engine にリアルタイムのデータベース リスナーを実装する際の効果的なアプローチの一つは、代替のシングルトン パターンとして GameInstance Subsystem を利用することです。これにより、バックグラウンドでデータベースの接続、認証、継続的なデータ受信を処理する専用の BlendshapesReceiver インスタンスを作成できます。

GameInstance Subsystem を活用することで、BlendshapesReceiver インスタンスを生成し、それをゲーム セッション全体にわたって維持することができます。これにより、受信したブレンドシェイプのデータからアニメーション ブループリントが顔のアニメーションを読み取って制御している間、永続的なデータベース接続が確保されます。

KDDI は、MediaPipe を実行するローカル PC 1 台のみで、実際の人の表情と動きをキャプチャし、質の高い 3D リターゲット アニメーションをリアルタイムで作成することに成功しました。


KDDI は、株式会社アダストリアなどのメタバースにおけるアニメ ファッションのデベロッパーと提携しています。

スタートガイド

詳細については、Google I/O 2023 のセッション、MediaPipe を使った簡単なオンデバイス機械学習機械学習と MediaPipe でウェブアプリを強化する機械学習の新機能をご覧ください。また、developers.google.com/mediapipe で公式ドキュメントもご確認ください。

次のステップ

この MediaPipe の統合は、リアルとバーチャルの境界をなくし、音楽ライブやアートの鑑賞、友人との会話、ショッピングなどの日常体験をいつでもどこでも楽しめるようにする、KDDI の取り組みの一例です。 

KDDI の αU は、メタバース、ライブ配信、バーチャル ショッピングなど、Web3 時代のサービスを提供し、誰もがクリエイターになれるエコシステムを形成して、リアルとバーチャルを自在に行き来する新世代のユーザーをサポートしています。