この記事は KDDI Alpha-U の XR 開発チームによる Google Developers Blog のゲスト記事 " MediaPipe: Enhancing Virtual Humans to be more realistic" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。


以下の記事に記載されている情報、用途、およびアプリケーションは、すべてゲスト著者の KDDI に帰属するものであることをご了承ください。

KDDI はバーチャル ヒューマン『メタコ』にテキスト読み上げ機能とクラウド レンダリング技術を統合


VTuber(バーチャル YouTuber)は、コンピュータ グラフィックスによって生成されたバーチャル アバターを使用するオンライン エンターテイナーです。このデジタル トレンドは 2010 年代半ばに日本で始まり、オンラインで国際的に活動する現象が起こりました。ほとんどの VTuber は、アバターのデザインを使用した YouTuber またはライブ配信者で、英語と日本語の両方を話します。


KDDI は、4,000 万人以上の顧客を持つ日本の通信事業者です。5G ネットワーク上に構築されたさまざまなテクノロジーの実験を通じて、VTuber のさらなる進化を支援したいと考えていましたが、正確な動きや人間らしい表情をリアルタイムで表現することは困難な課題でした。


リアルタイムでバーチャル ヒューマンを生成する
5 月の Google I/O 2023 で発表された MediaPipe のフェイス ランドマーカー (英語) ソリューションは、顔のランドマークを検出し、ブレンドシェイプ スコアを出力して、ユーザーの行動に即した 3D の顔モデルをレンダリングするものです。KDDI は、Google パートナー イノベーション チームと共同で MediaPipe フェイス ランドマーカー ソリューションを使用してテストを実施し、バーチャル ヒューマンに現実感をもたらすことに成功しました。


技術実装

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 個のブレンドシェイプに関する float 値のコレクションが格納されます。各行は、順番にリストされたブレンドシェイプに対応しています。 

_neutral, 

browDownLeft, 

browDownRight, 

browInnerUp,

browOuterUpLeft,

...


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



ブレンドシェイプ データを抽出したら、次のステップではそのデータを 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 プロジェクトにおいて動的で応答性の高いフェイシャル アニメーションを実現できます。



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



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


GameInstance サブシステムを利用すると、BlendshapesReceiver インスタンスを作成して、ゲーム セッションの存続期間全体で維持できます。これにより、受信したブレンドシェイプ データを使用してアニメーション ブループリントがフェイシャル アニメーションを読み取って実施している間、永続的なデータベース接続が確保されます。


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




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

はじめに

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

次のステップ
この MediaPipe 統合は、誰もがクリエイターになりうるエコシステムを構築し、現実と仮想を軽やかに行き来する新世代のユーザーに寄り添うための KDDI の取り組みの一例です。KDDI の αU は、メタバース、ライブ配信、バーチャル ショッピングなど Web3 時代のサービスを提供します。


Reviewed by Bryan Tanaka - Program Manager, Google Partner Innovation