LoginSignup
18
16

More than 1 year has passed since last update.

face-api.jsを使って「トラニナル」

Last updated at Posted at 2022-01-21

はじめに

昨年の年末に「うちの会社っぽい年賀状なんかない?」ということで
「”顔”になんやかんやできる年賀状」を作ってみよう!と、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に変更しました
image.png

  • モデルの読み込み

顔検出や顔認識を行うためには、「顔モデル」を読み込む必要があります
モデルのロードに必要なmanifestファイルとshardsファイルが提供されているので
こちらもクローンしてきたリポジトリ内からweightsディレクトリを自分のプロジェクトにコピーしました
分かりやすいようにディレクトリ名はweights⇒modelsに変更しました
image.png

使ってみる

  • まず、顔モデルを読み込みます。

今回「顔を検出」して「顔のパーツを識別して」その上に「画像を乗っけ」よう、と考えたので
以下の2つのモデルを使いました
顔を検出:faceapi.nets.ssdMobilenetv1
顔パーツの検出:faceapi.nets.faceLandmark68Net

faceapi.nets.ssdMobilenetv1.load('./models'),
faceapi.nets.faceLandmark68Net.load('./models'),
  • 次に、顔パーツの検出を実行します

顔のパーツを認識するために、顔ランドマークと呼ばれる顔の特徴点を検出して利用します
(画像はface-api.jsから引用)

image.png

今回は、「映っている中で最も信頼度の高い顔を検出する」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);
}

トラになった!

image.png
色んなパーツを乗せてみました
これは静止画ですが、顔検出のソースをvideoにすることもできます

おわりに

こんなんできるんじゃ?とプロトタイプを実装したのち
デザイナーさんに素敵なデザインをつけてもらいAR年賀状としてリリースしました

  • 顔検出が動くまでが遅い(重い)
  • 1人しかトラになれない
  • 横画面非対応

等…
まだまだ課題はありますが
face-api.jsの顔モデルを変更したら改善できる部分もあるのかな?
と思っています

時間を見つけて試していきたいです

18
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
16