LoginSignup
26
12

More than 1 year has passed since last update.

【うわっ...私の表情、硬すぎ...?】face-api.jsで顔検出して感情と年齢を判定する

Posted at

はじめに

コロナ禍が収まってきたとはいえ、オンラインでミーティングする機会は多いですね。
ZOOMやGoogleMeetでミーティングを行う際、自分の顔を写している人も多いのではないでしょうか?

ミーティング中、画面に映される自分の無表情の顔。
なんか疲れてない?
hyoujou_shinda_me_woman.png

ミーティング中、相槌を打ちながら微笑む自分の顔。
なんかうまく笑えてなくない?
nihil_smile_man.png

そもそも自分の顔。
なんか老けてない?
pose_unzari_woman.png

「無表情でいるつもりでも他人からしたら怒って見えているかも。。。」
「笑っているつもりでも他人から見たら変な顔に見えてるかも。。。」
そんなことを考え始めると自分の表情が他人にどう見えているのか気になって夜も眠れません。

そこで考えました。
自分の顔をAIに認識させてどんな感情かを判定してもらえば面白いのでは?
ついでに年齢も何歳に見えるか判定してもらえば良いのでは?

今回のこの記事ではface-api.jsを利用して、PCのインカメラで撮影した自分の顔を解析してもらいます。

最終的に作成したものがこちらになります↓
https://merry-paprenjak-7d004b.netlify.app/

共同執筆者: @sarahlovesplum @ymmt1089

そもそもface-api.jsって何?

face-api.js は、顔検出・顔認識を行うためのJavaScriptAPIです。
コア部分はtensorflow.js(tensorflow/tfjs-core)上に実装されています。
公式のデモページ

手順

プロジェクトのディレクトリ構成

📂project
├ 📂models(学習モデル)
├ 📄face-api.mim.js(face-apiライブラリ)
├ 📄index.html
└ 📄script.js

学習モデルのダウンロード

まず、fase-api のGithubから学習モデルをダウンロードしておきます。
以下リンクからモデルをダウンロードしてmodels配下に配置します。
https://github.com/justadudewhohacks/face-api.js/tree/master/weights

学習モデルの種類と説明

ダウンロードした学習モデルについて説明します。
画像は公式から引用: https://justadudewhohacks.github.io/face-api.js/docs/index.html

  • ssdMobilenetv
    1.gif
    精度が高い顔検出。バウンディングボックスと精度を取得。

  • tinyFaceDetector
    detectSingleFace()で検出した顔の中で、もっとも信頼度が高い顔を1つだけ検出します。複数人を検出したい場合は、tinyFaceDetectorのdetectAllFaces()で検出可能です。
    推論が高速な顔検出。バウンディングボックスと精度を取得。

  • faceLandmark68Net
    2.jpeg
    顔ランドマークを検出。68個の顔のポイントを取得。

  • faceRecognitionNet
    5.gif
    2つの顔の類似性を判断。

  • faceExpressionNet
    3.png
    顔の表情の分類。以下の表情で分類されます。
    neutral, happy, sad, angry, fearful, disgusted, surprised

  • ageGenderNet
    4.jpeg
    年齢と性別を推定。

face-api.min.jsのダウンロード

face-api.jsのライブラリ本体もダウンロードしておきます。
以下のリンクからface-api.min.jsをダウンロードしてprojectファイル直下に配置します。
https://github.com/justadudewhohacks/face-api.js/tree/master/dist

index.htmlの作成

index.htmlを作成します。
必要なscriptを読み込んで、bodyにvideoタグを追加します。

index.html
<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <script defer src="face-api.min.js"></script>
    <script defer src="script.js"></script>
    <style>
      body {
        margin: 0;
        padding: 0;
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: yellow;
      }

      canvas {
        position: absolute;
      }
    </style>
  </head>
  <body>
    <video id="video" width="720" height="560" autoplay muted></video>
  </body>
</html>

script.jsの作成

scriptで使用したい学習モデルを読み込んで、実際に使用しています。
簡単な説明をコードの横に記載しています。

script.js
const video = document.getElementById("video");

Promise.all([
  faceapi.nets.tinyFaceDetector.loadFromUri("./models"), //カメラの中の顔を探すmodule
  faceapi.nets.faceLandmark68Net.loadFromUri("./models"), //目、鼻、口を探すmodule
  faceapi.nets.faceRecognitionNet.loadFromUri("./models"), //顔付きボックス
  faceapi.nets.faceExpressionNet.loadFromUri("./models"), //表情を判断するmodule
  faceapi.nets.ageGenderNet.loadFromUri("./models"), //年齢性別を判断するmodule
]).then(startVideo);

function startVideo() {
  navigator.mediaDevices
    .getUserMedia({ video: true })
    .then(function (stream) {
      video.srcObject = stream;
    })
    .catch(function (err) {
      console.error(err);
    });
}

video.addEventListener("play", () => {
  const canvas = faceapi.createCanvasFromMedia(video);
  document.body.append(canvas);
  const displaySize = { width: video.width, height: video.height };
  faceapi.matchDimensions(canvas, displaySize);
  setInterval(async () => {
    const detections = await faceapi
      .detectAllFaces(video, new faceapi.TinyFaceDetectorOptions()) //カメラの中にいる顔をすべて認識
      .withFaceLandmarks() //目、鼻、口を探す
      .withFaceExpressions() ////表情を判断する
      .withAgeAndGender(); //年齢性別を判断する
    const resizedDetections = faceapi.resizeResults(detections, displaySize);
    canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); //顔に付いて回るボックス
    faceapi.draw.drawDetections(canvas, resizedDetections); //顔に箱付きの表現
    faceapi.draw.drawFaceLandmarks(canvas, resizedDetections); //目鼻口点線表現
    faceapi.draw.drawFaceExpressions(canvas, resizedDetections); //感情情報表現
    resizedDetections.forEach((detection) => {
      //年齢、性別表現ボックス
      const box = detection.detection.box;
      const drawBox = new faceapi.draw.DrawBox(box, {
        label: Math.round(detection.age) + " year old " + detection.gender,
      });
      drawBox.draw(canvas);
    });
  }, 100);
});

VSCodeで動作確認するために便利な拡張機能

動作確認するためにはローカルサーバーを立ち上げる必要がありますが、VSCodeの場合は拡張機能のLiveServerを活用することで、ワンクリックでローカルサーバーを立ち上げることができます。

使用方法は以下参照
https://webdesign-trends.net/entry/14461

動作確認

demo.gif

実際に動かしてみると、顔を青枠で認識して、枠上部に年齢、枠下部に感情とパーセンテージが表示されます。  
しっかり顔を検出できていますね。

happy
happy.png

angry
angry.png

disgusted
disgusted.png

suprised
suprised.png

おわりに

face-api.jsのライブラリを読み込ませるだけで顔認識から表情た年齢を割り出すことができました。
これで他人からみて自分の表情がどう見えているかがわかりますね。これで夜も安心して眠れそうです。
しかも検出された年齢が実年齢より低めなのもいいですね。テンション上がります。
年齢が低めに表示されるのは、大元の学習モデルにアジア系の学習データが少ないからかもしれません(アジア系の人は欧米系の人より年齢が若く見られるみたいなので)

今回は動画から顔を検出して感情や年齢を出しましたが、画像から検出したり他の学習モデルを追加することで色々なことができそうです。

参考

26
12
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
26
12