👏
[Next.js] tensorflow.js + WebCameraで顔の頂点情報を取得
はじめに
顔検出を実装する機会があったのシェアさせていただきます。
環境
electron + next.js + typescript
node-version 16.0.0
tensorflow.js
import
yarn add @tensorflow/tfjs
yarn add @tensorflow-models/face-landmarks-detection
code
FaceTrack.ts
import React, { useRef, useEffect } from "react";
import * as tf from "@tensorflow/tfjs";
import * as faceLandmarksDetection from '@tensorflow-models/face-landmarks-detection';
export default function FaceTrack() {
const videoRef = useRef(null)
let video;
let detector;
useEffect(() => {
init();
}, []);
const init = async () => {
const width = 640
const height = 360
video = videoRef.current
video.id = 'video';
video.width = width;
video.height = height;
video.autoplay = true;
let media = navigator.mediaDevices.getUserMedia({
audio: false,
video: {
width: { ideal: width },
height: { ideal: height }
}
}).then(async(stream) =>{
video.srcObject = stream;
const model = faceLandmarksDetection.SupportedModels.MediaPipeFaceMesh;
const detectorConfig = {
runtime: 'tfjs', // or 'tfjs'
refineLandmarks: true,
solutionPath: 'https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh',
}
detector = await faceLandmarksDetection.createDetector(model, detectorConfig as faceLandmarksDetection.MediaPipeFaceMeshMediaPipeModelConfig);
tf.setBackend("webgl")
update()
});
};
const update = async () => {
const faces = await detector.estimateFaces(video);
console.log(faces) // 顔の頂点情報
window.requestAnimationFrame(update)
}
return (
<div>
<video ref={videoRef}/>
</div>
);
}
※簡略化のためにupdateという名前の関数でasync,awaitしていますが、他に更新する処理がある場合、別で処理を走らせて更新処理に影響が出ないようにしてください。
webカメラ映像をvideoタグに反映
ビデオタグの各種設定
video = videoRef.current
video.id = 'video';
video.width = width;
video.height = height;
video.autoplay = true;
カメラ映像を、ビデオタグに反映
let media = navigator.mediaDevices.getUserMedia({
audio: false,
video: {
width: { ideal: width },
height: { ideal: height }
}
}).then(async(stream) =>{
// videoタグに反映
video.srcObject = stream;
});
カメラが複数ある場合、解像度がidealから最も近いものが選択されます。
今回はカメラの解像度と表示するサイズが近いものになるように設定してます。
顔の頂点を取得
ライブラリをimport
import * as facemesh from '@tensorflow-models/facemesh';
import * as faceLandmarksDetection from '@tensorflow-models/face-landmarks-detection';
モデルをロード
const model = faceLandmarksDetection.SupportedModels.MediaPipeFaceMesh;
const detectorConfig = {
runtime: 'tfjs',
refineLandmarks: true,
solutionPath: 'https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh',
}
detector = await faceLandmarksDetection.createDetector(model, detectorConfig as faceLandmarksDetection.MediaPipeFaceMeshMediaPipeModelConfig);
tf.setBackend("webgl")
webglが選択されないときがないように、明示的に選択
頂点を取得
const update = async () => {
const faces = await detector.estimateFaces(video);
console.log(faces)
window.requestAnimationFrame(update)
}
detector.estimateFacesにソースを渡すことで、ユーザーごとの顔の頂点情報を配列で返却してくれます。
返却される数値はピクセルになります。
(1000px, 500pxの動画を読み込ませたときに、ちょうど中心の位置が返却された場合
[x: 500, y: 250, z: ? ]が返却されます。)
consoleで取得できる情報
window.requestAnimationFrameで次の再線画タイミングで、再度頂点を取得するように要求します。
フレッシュレートの高い画面では速く実行されるため、端末によって更新タイミングが異なります。
それぞれの頂点がどの位置を指しているかはgithubから参照してください。
参考
最後に
使ってみるとすごい便利...
爆速ですね。
なにかあれば、コメントいただけますと幸いです。
Discussion