なんと、ブラウザで顔認識ができる時代になりました。
試したのはChrome 70.0.3530.0(Official Build)canary (64 ビット)で。
仕様
Accelerated Shape Detection in Images なる仕様らしく、大きく2つのAPIが定義されてる。
顔認識と、バーコードの認識ができる。
今回の記事で試したのは、顔認識のほう。
FaceDetector
APIとしてはシンプルで、このように。
const faceDetector = new window.FaceDetector(options);
オプションで指定できるのは2つ。
interface FaceDetectorOptions { fastMode: boolean; maxDetectedFaces: number; }
`fastMode`は速度優先なら`true`、精度優先なら`false`にする。
手元で試した感じだと実行速度が倍くらい変わる・・!
`maxDetectedFaces`は、検出する顔の数のMAXを決められる風なことが書いてあるけど、`1`に設定してもいっぱい検出するし、逆に大きい値を指定しても最大で8しか検出できなかった。
FaceDetectorが持ってるのは`detect()`のみ。
この`detect()`に`ImageBitmapSource`を渡すとPromiseで認識結果が返ってくる。
async function main() { const faceDetector = new window.FaceDetector(); const $img = document.querySelector('img'); const faces = await faceDetector.detect($img).catch(console.error); for (const face of faces) { // face: DetectedFace } }
DetectedFace
認識された結果は配列で返ってくる(1つだけでも)ので、それをよしなに使う。
interface DetectedFace { boundingBox: DOMRectReadOnly; landmarks: Landmark[]; }
`boundingBox`は、`getBoundingClientRect()`で得られるのと同じで、矩形の情報が入ってる。
`x`, `y`, `top`, `left`, `witdh`などなど。
`landmarks`は、`landmarks.type`で目・鼻・口がどこにあったかが返ってくる。
今は`landmarks.locations`が単一座標になってて中心点だけが取れるけど、仕様には周囲を囲う座標的なことも書いてあるので、そのうち変わりそう。
デモつくった
任意の画像から顔を検出
https://leader22.github.io/face-detection-api-example/image/index.html
画像をアップするか、ダミーの(仕様にくっついてたデモに入ってた)画像に対して、顔認識できる。
カメラからリアルタイムに検出
https://leader22.github.io/face-detection-api-example/stream/index.html
`getUserMedia()`したストリームに対して、顔認識してみるデモ。
メインのとこだけコード抜粋。
const options = getFaceDetectorOptions($radio, $number); const faceDetector = new window.FaceDetector(options); const imageCapture = new window.ImageCapture($video.srcObject.getVideoTracks()[0]); detect(); async function detect() { requestAnimationFrame(detect); let img; try { img = await imageCapture.grabFrame(); } catch { // Sometimes this throws with message `undefined`... return; } const faces = await faceDetector.detect(img).catch(console.error); drawImageToCanvas(img, $canvas); drawFaceRectToCanvas(faces, $canvas); }
`video`から画像を切り出すの、最近ではImageCapture APIが使える環境だとそれが一番楽ですね。
rAFで回すとなんか謎のエラーを吐くタイミングがあって謎やったけど・・。