はじめに
「顔認識をWebアプリに組み込みたいけれど、サーバーに画像を送るのは気が引ける」——そう思ったことはありませんか。画像を外部APIに送信する方式は、実装は簡単でも通信のたびに個人の顔写真が飛んでいくことになり、プライバシーの観点で不安が残ります。
face-api.jsは、この問題をブラウザ内完結で解決するJavaScriptライブラリです。TensorFlow.jsの上に構築されており、顔検出・顔ランドマーク検出・表情認識・年齢や性別の推定・顔認識(本人特定)までを、すべてクライアントサイドのJavaScriptだけで処理できます。画像は一度もサーバーに送られません。
とはいえ、説明よりも実際に動いているところを見た方が早いと思います。ブラウザ上でface-api.jsが顔を検出する様子を、まず動かしてみましょう。
face-api.jsとは
face-api.jsは、tensorflow/tfjs-core上に実装された、ブラウザとNode.jsの両方で動く顔認識APIです。作者のvincent muhler氏が、顔検出・顔ランドマーク検出・顔認識・年齢推定・性別推定・表情認識という複数のディープラーニングモデルを1つのライブラリにまとめ、統一されたAPIで扱えるようにしています。
主な特徴
- サーバー不要 - 顔検出から特徴抽出まですべてブラウザ内のJavaScriptで完結し、画像データを外部に送信する必要がありません
- 複数の検出モデルを選択可能 - 精度重視の
SsdMobilenetv1、速度重視のTinyFaceDetector、高精度なMTCNNなど、用途に応じてモデルを切り替えられます - 豊富な機能 - 顔検出だけでなく、68点の顔ランドマーク検出、表情認識(happy・sad・angry等)、年齢・性別推定、顔認識(本人特定)までを1つのAPIで提供します
- WebGLアクセラレーション - 内部で使われるTensorFlow.jsがWebGLバックエンドを利用するため、CPUのみの実装より高速に動作します
インストール
npmやyarnでインストールできます。
npm install face-api.js
yarn add face-api.js
CDN経由で直接読み込むことも可能です。
<script src="https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js"></script>
face-api.jsのサンプルを動かす
このサンプルでは、faceapi.nets.tinyFaceDetectorで顔検出モデルを読み込み、faceapi.detectAllFaces()を使って画像内の顔を検出し、検出結果をキャンバス上に矩形とスコアで描画しています。デフォルトではサンプル画像を使って検出しますが、「画像を選択」ボタンから手元の写真をアップロードして試すこともできます。
face-api.jsの基本的な流れは、モデルの読み込み → 検出関数の呼び出し → 結果の描画、というシンプルな3ステップです。
// モデル読み込み(非同期)
await faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL)
// 顔検出(非同期・複数人にも対応)
const detections = await faceapi.detectAllFaces(
imgElement,
new faceapi.TinyFaceDetectorOptions()
)
// 検出結果をキャンバスに描画
faceapi.matchDimensions(canvas, imgElement)
const resized = faceapi.resizeResults(detections, imgElement)
faceapi.draw.drawDetections(canvas, resized)
実際に動かせるサンプルが下です。画像を差し替えると、その場で顔検出の結果が変わります。人が写っていない画像を選ぶと矩形が表示されず「顔が検出されませんでした」と出るので、成功・失敗どちらの挙動も確認できます。
TinyFaceDetectorOptionsにはコンストラクタでinputSize(検出精度と速度のトレードオフ)やscoreThreshold(検出の閾値)を渡せます。数値を大きくするほど精度は上がりますが処理は遅くなるため、リアルタイム処理か高精度重視かで使い分けるのがポイントです。
基本的な使い方
face-api.jsを使う際の最小構成のコードは、次のようになります。画像要素(<img>または<video>)に対してモデルを読み込んでから検出関数を呼び出す、という順序を守ることが重要です。
import * as faceapi from 'face-api.js'
async function run() {
// 使用するモデルを読み込む(重みファイルは/modelsに配置)
await faceapi.nets.tinyFaceDetector.loadFromUri('/models')
const imgElement = document.getElementById('myImage')
// 単一の顔だけを検出する場合
const detection = await faceapi.detectSingleFace(
imgElement,
new faceapi.TinyFaceDetectorOptions()
)
if (detection) {
console.log('顔を検出:', detection.box)
}
}
run()
モデルの重みファイルは、GitHubリポジトリのweightsディレクトリから取得し、自分のプロジェクトの静的配信ディレクトリ(public/modelsなど)に配置するのが一般的です。
実践的なユースケース
顔検出だけでなく、face-api.jsは他のモデルと組み合わせることで様々な用途に対応できます。ここでは3つの代表的なパターンを紹介します。
顔ランドマーク検出でパーツの位置を取得する
輪郭・眉・目・鼻・口など、顔の68点のランドマーク座標を取得したい場合は.withFaceLandmarks()を検出チェーンに追加します。目の開閉判定や表情アニメーション、ARフィルターの位置合わせなど、パーツ単位の座標が必要な場面で使えます。
detection.landmarks.getLeftEye()や.getMouth()のように、パーツごとの座標配列を個別に取り出すメソッドも用意されているので、目や口の位置だけをピンポイントで使いたい場合にも便利です。
表情認識で感情のスコアを取り出す
.withFaceExpressions()を追加すると、happy・sad・angry・surprised・disgusted・fearful・neutralの7種類の表情それぞれについて、0〜1のスコアが得られます。表情に応じてUIの反応を変えたり、アンケートの回答時の反応を分析したりする用途に使えます。
サンプル画像を差し替えて笑顔の写真と真顔の写真を見比べると、happyやneutralのスコアが大きく変化するのが分かります。asSortedArray()を使うと最もスコアの高い表情を簡単に取り出せます。
年齢・性別推定で属性を取得する
.withAgeAndGender()を追加すると、推定年齢(数値)と性別(male/femaleとその確信度)が取得できます。デジタルサイネージの属性分析や、年齢層に応じたコンテンツ出し分けなどに応用できます。
推定年齢はあくまで見た目からの統計的な推定値なので誤差はありますが、複数フレームの平均を取るなどの工夫をすると実用的な精度に近づけられます。.withFaceLandmarks()・.withFaceExpressions()・.withAgeAndGender()はメソッドチェーンで自由に組み合わせられるため、必要な情報だけをまとめて1回の検出で取得することも可能です。
まとめ
face-api.jsを使うと、顔検出・ランドマーク検出・表情認識・年齢や性別の推定といった複数のディープラーニング処理を、外部サーバーに一切画像を送ることなくブラウザ内だけで完結させられます。faceapi.netsでモデルを読み込み、detectAllFaces()に.withFaceLandmarks()のようなメソッドをチェーンしていくだけというシンプルなAPI設計も魅力です。
まずはTinyFaceDetectorで顔検出を試し、必要に応じて.withFaceExpressions()や.withAgeAndGender()を組み合わせて、自分のプロジェクトに合った顔認識機能を組み立ててみてください。
