WebカメラとJavaScriptだけで高精度なまばたき検知を実現できた話
 Author: 水卜

概要

ドライバーモニタリングシステムの展示などで睡眠検知のシステムをよく見かけます。

興味があったので自前で実装してみました。

以下のデモサイトでは睡眠検知と書きましたが、やっているのは「まばたき検知」です。

目を瞑っているか、開けているかをWebカメラの映像からリアルタイムに判定します。

これを睡眠検知とするためには、追加で「1〜2秒ほど検知結果を蓄積し、目を瞑っていた割合を見る」というような実装を行う必要がありますが、まばたきさえ正確に取れていれば瑣末な問題です。

デモサイトはPCでご覧ください。

デモはこちら -> https://blink.koatech.info/

試行錯誤

EAR(Eye Aspect Ratio)

初めは以下の記事で紹介されているEAR(Eye Aspect Ratio)という指標が使えそうだったので、それで実装していました。EARは、目尻と目頭の高さの平均と目の横幅の比率です。

https://qiita.com/mogamin/items/a65e2eaa4b27aa0a1c23

しかし、①画面に映っている顔の大きさ、②個人の目の大きさで大きく閾値がブレてしまい、うまくいきませんでした。もっと正確なLandmarksが取得できるようなモデル/顔認識エンジンがあればうまくいくのかもしれませんが、断念しました。

一応実装したものはこちら -> https://blink.koatech.info/ear

瞳の検出

我々は目の大きさ、細さが人によって全く違うにも関わらず、目の前の人が目を瞑っているか閉じているかを瞬時に判断することができます。

なんでだろうとしばらく考えて、「瞳が見えるかどうか」ではないかと仮説を立てました。

そこで思いついたのが、以下の実装です。

  • 目の画像を二値化し、瞳だけが黒くなる状態を作る
  • 目の画像のうち、黒くなっている部分(瞳)の比率で目を瞑っているかどうか判定する

処理の流れ

まず画面左のcanvasにwebカメラの映像を流します。

ユーザーの顔が写っているはずなので、ここで顔認識を走らせます。

顔認識エンジンはface-api.jsを使いました。

https://github.com/justadudewhohacks/face-api.js/

face-api.jsで顔のLandmarks(パーツの位置)が取れますので、左目と右目をそれぞれ画面右のcanvasに写します。

カラーのままでは処理が面倒なので、目を写しているcanvasを二値化します。

すると、目を開けている時は瞳にあたる部分が黒く表示されますが、目を閉じている時は何も表示されません。二値化の閾値によってはたまにまつ毛が映る程度です。

画面右には、隠していますが私の顔が写っています。

  • 目を開けている時
    awakedemo

  • 目を閉じている時
    sleepdemo

これで、私の顔ではほぼ完璧にまばたきを検知することができました。

他の人の顔ではまだ試していないのでわかりませんが、多少閾値をいじる程度で対応可能だと思われます。