feature image

2022年9月6日 | ブログ記事

【MediaPipe + KalidoKit】ブラウザでリアルタイム顔認識して遊ぶ

こんにちは、@d_etteiu8383です。この記事は夏のブログリレー 2022年 28日目の記事です。

概要

本記事ではMediaPipeのFaceMeshKalidoKitを利用して、ブラウザ上でリアルタイムに顔認識を行う方法について説明します。

イントロ

突然ですが本日9月6日が何の日だかご存じでしょうか?そうです、真中のんさんの誕生日ですね。

彼女はアニメ『プリパラ』の登場人物の一人ですが、このアニメは3DCGを利用したライブシーンが特徴的ですよね。3Dと言えば<!-- ここにこじつけ理由を書く -->というわけで本記事ではMediaPipeのFaceMeshKalidoKitを利用した、ブラウザ上でのリアルタイム顔認識について説明します。

MediaPipe Face Mesh

overview: https://google.github.io/mediapipe/solutions/face_mesh.html
GitHub: https://github.com/google/mediapipe

MediaPipe Face Mesh is a solution that estimates 468 3D face landmarks in real-time even on mobile devices. It employs machine learning (ML) to infer the 3D facial surface, requiring only a single camera input without the need for a dedicated depth sensor. Utilizing lightweight model architectures together with GPU acceleration throughout the pipeline, the solution delivers real-time performance critical for live experiences.
https://google.github.io/mediapipe/solutions/face_mesh.html

MediaPipe Face Meshは、機械学習を用いてカメラ入力からリアルタイムに3D顔表面位置を推定することができるライブラリです。

↓公式ページで紹介されているデモ動画(https://google.github.io/mediapipe/solutions/face_mesh#face-detection-model)↓

女性の顔を認識してランドマーク位置を表示しているデモ動画

このデモでは、眉や虹彩、口の位置など計468個の"ランドマーク(目印となる点, 特徴点)"の位置を推定し、推定結果を描画しています。

↓MediaPipe Face Meshで得られる推定データの例↓

{
    "image": {
        中略
    },
    "multiFaceGeometry": [],
    "multiFaceLandmarks": [
        [
            {
                "x": 0.5204985737800598,
                "y": 0.6729813814163208,
                "z": -0.05491212010383606
            },
            {
                "x": 0.5279504656791687,
                "y": 0.589737594127655,
                "z": -0.10225235670804977
            },
            中略
            {
                "x": 0.6175460815429688,
                "y": 0.4767884314060211,
                "z": 0.014705833978950977
            }
        ]
    ]
}

KalidoKit

GitHub:https://github.com/yeemachine/kalidokit

Kalidokit is a blendshape and kinematics solver for Mediapipe/Tensorflow.js face, eyes, pose, and hand tracking models, compatible with Facemesh, Blazepose, Handpose, and Holistic. It takes predicted 3D landmarks and calculates simple euler rotations and blendshape face values.
https://github.com/yeemachine/kalidokit#face-pose-and-hand-tracking-calculator

MediaPipe Face Meshによる推定で得られるのは顔表面のランドマークの位置(="空間上の座標"の配列)であり、そのままでは扱いづらい形式となっています。顔認識を利用したい場面で求められるのは、たいていの場合"口角がどの程度上がっているか"や"目をどれぐらい閉じているか"、"どこを向いているか"といった情報です。このような情報は、ランドマーク間の位置関係から"うまく計算して"求める必要があります。今回、この計算をKalidoKitで行います。

KalidoKitは3DのVRMモデルとLive2Dアバターを動かすために必要なデータを得ることに特化して設計されており、いわゆる"Vtuber"的なことがしたいときに用いることが想定されています。Live2DやVRMを利用するサンプルコードがGlitchで公開されています。

MediaPipe Face Meshで推定したランドマーク位置をKalidoKitのソルバ("上手く計算して"くれる子)に渡してあげると、以下のような結果が得られます(https://github.com/yeemachine/kalidokit#outputs)。

// Kalidokit.Face.solve()
// Head rotations in radians
// Degrees and normalized rotations also available
{
    eye: {l: 1,r: 1},
    mouth: {
        x: 0,
        y: 0,
        shape: {A:0, E:0, I:0, O:0, U:0}
    },
    head: {
        x: 0,
        y: 0,
        z: 0,
        width: 0.3,
        height: 0.6,
        position: {x: 0.5, y: 0.5, z: 0}
    },
    brow: 0,
    pupil: {x: 0, y: 0}
}

xyは座標や回転、mouth.shapeは口の形がどの母音の状態に近いかのパラメータ、eye.leye.rは目が明いているか閉じているか、などを表しています。

このように、ランドマークの座標データから、扱いやすいパラメータに変換することができます。

最終的に作れるもの

上手くいろいろすると下記ツイートのようなものが作れます。

ブラウザで顔認識してアイコン動かすテスト pic.twitter.com/GYo1vTvzZ2

— でっていう (@d_etteiu8383) July 20, 2022

上記のデモはhttps://you.eyemono.moeでお使いのブラウザから試すことができます。

you.svg - 四十物さんは見ている
あなたの顔を眺めるページ

手順

今回はVite + TypeScriptを利用した最低限のデモを作成します。

最低限のコードでの例であり、VueやReactなどのフレームワーク・ライブラリは利用していません。基本的には公式のドキュメントに従っているので前述した公式ページを見たほうがわかりやすいかも。

環境

準備

viteの準備です(f7ca8f2)。

npm create vite@latest face-detect-example -- --template vanilla-ts
cd face-detect-example
npm install
npm run dev

準備できたら一旦不要部分を全部削除しましょう(75c2b6a)。

MediaPipe Face Mesh

インストール

本体である@mediapipe/face_meshに加え、カメラを簡単に扱うための@mediapipe/camera_utilsと、推定結果をきれいに描画するための@mediapipe/drawing_utilsも同時にインストールします。

npm i @mediapipe/face_mesh @mediapipe/camera_utils @mediapipe/drawing_utils

カメラの起動 + 顔認識・推定 + 推定結果描画

JSでの使用例が公式で紹介されている(https://google.github.io/mediapipe/solutions/face_mesh#javascript-solution-api)ため、これをまるまるTSで書きなおしました(d3a8226)。

簡単のため1ファイルにまとめています。

これだけで、下の動画のようにランドマークの検出ができます。便利~

demo_01_optimize

内容を簡単に説明すると、

  1. video要素とcanvas要素の準備(21-27行目)
  2. faceMeshインスタンスの作成(67-72行目)
  3. faceMeshの設定(74-81行目)
  4. faceMeshによる推定が完了したときに実行するコールバック関数(onResults)の登録(84行目)
    • onResults内ではcanvasに検出結果を描画する処理を記述している(31-64行目)
  5. cameraインスタンスの作成(86-93行目)
  6. カメラスタート(95行目)

といった感じです。

このデモではvideo要素にカメラ映像を表示し、canvasに推定結果を描画しています。CSSでvideoとcanvasが重なるようにし、videoにはぼかしを入れています(https://github.com/detteiu8383/face-detect-example/blob/d3a82261c200844178dfb31cadac4c944f939abc/src/style.css)。

Kalidokit

インストール

npm i kalidokit

ソルバでの計算

READMEにある通り、Kalidokit.Face.solve()にMediaPipe Face Meshの推定結果を渡すだけです(0c597a3)。簡単すぎ~

↓出力の例↓

{
    "head": {
        "y": -0.11274997287705743,
        "x": -0.2229431972868542,
        "z": 0.07574746454444863,
        "width": 160.17577586460894,
        "height": 120.18492581986624,
        "position": {
            "x": 208.53217542171478,
            "y": 224.71441328525543,
            "z": 48.97199869155884
        },
        "normalized": {
            "y": -0.035889431033721636,
            "x": -0.07096502375382895,
            "z": 0.024111166817854163
        },
        "degrees": {
            "y": -6.460097586069894,
            "x": -12.77370427568921,
            "z": 4.340010027213749
        }
    },
    "eye": {
        "l": 1,
        "r": 1
    },
    "brow": 0,
    "pupil": {
        "x": -0.25158695791085445,
        "y": -0.4272811294357963
    },
    "mouth": {
        "x": -0.6,
        "y": 0,
        "shape": {
            "A": 0,
            "E": 0,
            "I": 0,
            "O": 0,
            "U": 0
        }
    }
}

この例では計算結果をそのままコンソールに表示していますが、実際に使用する場合はこの値を用いてコンテンツを動的に変化させましょう。

応用例

数字を算出しただけでは何も面白くないので、何か動くモノを作ってみましょう。

で、作ったのが冒頭にも挙げたhttps://you.eyemono.moeです(GitHub:https://github.com/detteiu8383/svg-face)。

you.svg - 四十物さんは見ている
あなたの顔を眺めるページ
GitHub - detteiu8383/svg-face
Contribute to detteiu8383/svg-face development by creating an account on GitHub.

このページでは、Kalidokitで算出したパラメータを用いてSVGをアニメーションさせています。

https://github.com/detteiu8383/svg-face/blob/main/src/components/face/Face.tsxhttps://github.com/detteiu8383/svg-face/blob/main/src/utils/animateFace.tsを見るとわかるのですが、SVGのtransform属性を用いたり、複数のパスの頂点や制御点を線形補完したりして無理やり動かしてます...

head.degrees.zの値を使って顔を傾けたり、shape.eye.l/shape.eye.rの値(目の開き具合)の値を使って"閉じた状態の目"と"開いた状態の目"の制御点位置をブレンドしたりしています。

まとめ

以上、MediaPipeとKalidoKitを利用したリアルタイム顔認識方法の紹介でした。

キャラクターイラスト/3Dモデルを動かすことに縛られず、柔軟な発想でいろいろやってみたいですね。覗き込むように顔を動かさないと見えない文章とか、目を閉じてるときにだけこっそり表示される画像とか。皆さんもぜひ活用してみてはいかがでしょうか?

最後までお読みいただきありがとうございました。夏のブログリレー 明日の担当者は@inutamago_dogeggさんです!楽しみ~

d_etteiu8383 icon
この記事を書いた人
d_etteiu8383

19の"でっていう"です グラフィック班とゲーム班所属 3DCGメインでいろいろ活動しています Vtuberっぽいこともしてたりしてなかったり

この記事をシェア

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

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
2022年9月26日
競プロしかシラン人間が web アプリ QK Judge を作った話
tqk icon tqk
2022年9月16日
5日でゲームを作った #tararira
Komichi icon Komichi
2023年3月13日
GoでWebSocketのテスト書く
Ras icon Ras
2022年8月29日
ケモナー向け VRChatの始め方、歩き方。VR無くてもできる!
pikachu icon pikachu
記事一覧 タグ一覧 Google アナリティクスについて