#はじめに
昨年の年末に「うちの会社っぽい年賀状なんかない?」ということで
「”顔”になんやかんやできる年賀状」を作ってみよう!と、face-api.jsを使ってみました
#face-api.jsってなぁに
ブラウザで顔検出と顔認識ができるJavaScript APIです
機械学習用のライブラリTensorFlow.jsが利用されています
face-api.js
- 顔検出:face detection、人の顔を自動的に見つける
- 顔認識:face recognition、個人を識別する
です
今回は「顔検出」の範囲になります
#face-api.jsを使う準備
Getting Startedの記述を参考に作業します
- dist /face-api.jsの最新のスクリプトを含める
または、npm経由でインストール
と記載があったので、前者を選択しました
GitHub からリポジトリをクローンしてdistディレクトリを自分のプロジェクトにコピーしました
分かりやすいようにディレクトリ名はdist⇒jsに変更しました
- モデルの読み込み
顔検出や顔認識を行うためには、「顔モデル」を読み込む必要があります
モデルのロードに必要なmanifestファイルとshardsファイルが提供されているので
こちらもクローンしてきたリポジトリ内からweightsディレクトリを自分のプロジェクトにコピーしました
分かりやすいようにディレクトリ名はweights⇒modelsに変更しました
#使ってみる
- まず、顔モデルを読み込みます。
今回「顔を検出」して「顔のパーツを識別して」その上に「画像を乗っけ」よう、と考えたので
以下の2つのモデルを使いました
顔を検出:faceapi.nets.ssdMobilenetv1
顔パーツの検出:faceapi.nets.faceLandmark68Net
faceapi.nets.ssdMobilenetv1.load('./models'),
faceapi.nets.faceLandmark68Net.load('./models'),
- 次に、顔パーツの検出を実行します
顔のパーツを認識するために、顔ランドマークと呼ばれる顔の特徴点を検出して利用します
(画像はface-api.jsから引用)
今回は、「映っている中で最も信頼度の高い顔を検出する」detectSingleFaceを使用しました
const detection = await faceapi.detectSingleFace(input)
顔検出後に、withFaceLandmarksを実行することで検出された各顔の顔のランドマークを予測できます
const detectionWithLandmarks = await faceapi.detectSingleFace(input).withFaceLandmarks()
顔ランドマークの座標を取得できます
const landmarkPositions = landmarks.positions
const nose = landmarks.getNose()
const mouth = landmarks.getMouth()
const leftEye = landmarks.getLeftEye()
const rightEye = landmarks.getRightEye()
const leftEyeBbrow = landmarks.getLeftEyeBrow()
const rightEyeBrow = landmarks.getRightEyeBrow()
landmarkPositionsには68個の(x,y)座標が含まれています
getnose()
getMouth()
等をつかうと、パーツの座標が取れますが
今回は上に画像を重畳するのが目的なので使用せず、
「右頬(向かって左頬)の特徴点を起点に頬画像パーツを乗せる」
というような計算をしました
function drawStamp(){
ctx.clearRect(0, 0, cvs.width, cvs.height);
let positions = detectionWithLandmarks.landmarks.positions;
// スタンプの計算例です
let cheekRight = 2;
let cheekLeft = 14;
let faceWidth = positions[cheekLeft].x - positions[cheekRight].x;
let dw = stampCheek.width * faceWidth / stampCheek.width;
let dh = stampCheek.height * faceWidth / stampCheek.width;
let dx = positions[cheekRight].x;
let dy = positions[cheekRight].y - dh / 2;
ctx.drawImage(stampCheek, dx, dy, dw, dh);
}
#トラになった!
色んなパーツを乗せてみました
これは静止画ですが、顔検出のソースをvideoにすることもできます
#おわりに
こんなんできるんじゃ?とプロトタイプを実装したのち
デザイナーさんに素敵なデザインをつけてもらいAR年賀状としてリリースしました
- 顔検出が動くまでが遅い(重い)
- 1人しかトラになれない
- 横画面非対応
等…
まだまだ課題はありますが
face-api.jsの顔モデルを変更したら改善できる部分もあるのかな?
と思っています
時間を見つけて試していきたいです