InsightFaceの顔検出結果をブラウザ上で動画にオーバーレイ表示してみた
目次
- InsightFaceとFastAPIで顔検出サーバを作ってみた
- InsightFaceの顔検出結果をNext.jsで可視化してみた
- InsightFaceで顔認証(特徴量抽出、比較)してみた
- InsightFaceをGPUで動かしてみた
- InsightFaceを使って動画から顔検出してみた
- InsightFaceの顔検出結果をブラウザ上で動画にオーバーレイ表示してみた(本記事)
初めに
前回の記事では、InsightFaceによる顔検出の結果をOpenCVを使って可視化(オーバーレイ表示)し、動画ファイルとして出力しました。
今回は、ウェブブラウザ上で動画にオーバーレイ表示してみたいと思います。
デモ
今回もできあがったデモの動画からご覧ください。
上記はアニメーションGIFなのでカクカクしていますが、実際にはウェブブラウザ上でリアルタイムにレンダリングされた認識結果がヌルヌル動きます。
また、上部のチェックボックスをON/OFFすることで表示内容を切り替えることができます。ウェブブラウザ上で描画しているからこそできる機能ですね。
ビルド&実行
コード全体はGitHub上のリポジトリ「202107-face-detector」にあります。
この記事に対応するタグは20210814a
です。
ビルド、実行例は以下の通りです。
# リポジトリを取得する
git clone https://github.com/nayutaya/202107-face-detector.git
cd 202107-face-detector
# タグをチェックアウトする
git checkout 20210814a
# video-overlayサービスのイメージをビルドする
docker-compose build video-overlay
# video-overlayサービスのコンテナをバックグラウンドで起動する
docker-compose up -d video-overlay
# ブラウザで下記のURLを開く
open http://localhost:8002/
# (試したあとに)Dockerコンテナを停止する
docker-compose down
OpenCVによるオーバーレイ表示
動画の各フレームに対して顔検出などの物体検出を行い、その結果をオーバーレイ表示したいケースはよくあると思います。
手軽な方法の1つとして、前回の記事で行ったように、OpenCVでオーバーレイ表示を行い、動画ファイルとして出力する方法があります。
この方法には、以下のメリット、デメリットがあります。
メリット:
- OpenCVだけで手軽に実現できる。
- フレーム単位で正確な結果を描画できる。(時間方向の正確性が高い)
- 表示の処理負荷が低い。
デメリット:
- 動画ファイルを生成する必要がある。(容量が増え、管理が大変)
- OpenCVで凝った描画を行うのが面倒。
- 表示内容を再生時に変更できない。(生成時に決定する必要がある)
ウェブブラウザ+SVGによるオーバーレイ表示
前述の通り、OpenCVによるオーバーレイ表示は動画ファイルの生成が必要で容量が増え、管理が面倒です。
そこで、ウェブブラウザ上でリアルタイムにオーバーレイ表示する処理を実装してみました。
具体的には、ウェブブラウザ上のvideo
要素で動画を再生しつつ、その前面に配置したsvg
要素でオーバーレイ表示を行っています。
この方法には、以下のメリット、デメリットがあります。
メリット:
- 動画ファイルを生成する必要がない。(元の動画ファイルのみ管理すればよい)
- SVGによる凝った描画を行うことができる。
- 表示内容を再生時に変更できる。
デメリット:
- フレームが前後する可能性がある。(時間方向の正確性が低い)
- 顔検出を行うPythonコードとは別に、JavaScriptで可視化処理を実装する必要がある。
- 表示の処理負荷が高い。
svg
要素を使う方法以外にも、canvas
要素とdrawImage
メソッドを使い、video
要素からフレーム画像を転送した上で結果の描画を行う方法も思いつきます。
ただし、drawImage
メソッドはオリジンによる制約を受けるため、クロスオリジンを考慮する必要があります。(svg
要素による描画を行う場合、オリジンによる制約は受けません)
また、宣言的な記述を行うReact.jsと相性が良かったため、svg
要素を使って描画を行いました。
ちなみに、処理負荷は動画再生に比べて高くはありますが、MacBook Pro上のGoogle Chromeの他、iPad Pro、Android端末(Xperia 1 II)でも問題なく再生できました。
実装のポイント
詳細はソースコードを読んで頂くとして、実装のポイントは以下の通りです。
-
video
要素とsvg
要素を重ねる -
video
要素から再生位置を頻繁に読み出す - 動画のメタ情報は予め取得しておく
video
要素とsvg
要素を重ねる
前述の通り、動画へのオーバーレイ表示は、video
要素とsvg
要素を同じ場所に重ねることで実現しています。
video
要素をそのまま使用しているため、再生、停止、音量などのコントロールは、ブラウザ標準のインターフェースをそのまま使うことができ、独自に実装する必要がありません。
ただ、video
要素にsvg
要素を重ねると、マウスイベントはsvg
要素が受け取ってしまいます。
そのため、CSSのpointer-events
プロパティをnone
に設定することで、video
要素にマウスイベントが渡るようにしています。
video
要素から再生位置を頻繁に読み出す
video
要素で再生を行っている間、再生位置の更新を知らせるtimeupdate
イベントが定期的に発生します。
ただこのイベントは、(システムに依存しますが)1秒に1回ほどの頻度でしか発生せず、オーバーレイ表示を更新するには頻度が足りません。
そのため、動画の再生時には別途タイマを起動し、30fpsでオーバーレイ表示を更新するため、33ミリ秒毎に再生位置(currentTime
)を取得し、オーバーレイ表示を更新しています。
動画のメタ情報は予め取得しておく
video
要素から取得できるのは再生位置(単位は秒)だけで、フレーム番号を取得できません。
そのため、再生位置とフレームレート(fps)からフレーム番号を計算し、オーバーレイ表示を行っています。
video
要素からはフレームレートを取得できないため、予め動画のメタ情報(幅、高さ、フレームレート)を取得し、ウェブブラウザに渡しています。
その他の補足
今回はデモが目的だったため、動画からの顔検出は別途実施し、変換済みのJSONファイルを配置しています。
再生時に参照されるファイルは、以下の3ファイルです。
-
video-overlay/app/public/pixabay_76889_960x540.mp4
- 動画ファイルの本体。
- 動画はPixabayからお借りしました。
-
video-overlay/app/public/pixabay_76889_960x540.mp4.meta.json
- 動画ファイルのメタ情報を記録したJSONファイル。
- 手作業で作成しました。
-
video-overlay/app/public/pixabay_76889_960x540.mp4.data.json
- 顔検出の結果をコンパクトに格納したJSONファイル。
-
video-analyzer/src/convert.py
を使って生成しました。
最後に
動画を入力してInsightFaceによる顔検出を行い、その結果をウェブブラウザ上でリアルタイムにオーバーレイ表示することができました。
次回は、「動画のアップロード」→「顔検出」→「結果の表示」の一通りの流れを行えるウェブアプリを実装してみたいと思っています。
Discussion