顔認識をするChrome拡張を実装したので、その紹介と技術的解説

顔認識をするChrome拡張を実装したので、その紹介と技術的解説
カテゴリ
技術
タグ
Chrome拡張
Vite
Typescript

はじめに

子どもを幼稚園に通わせていると、各種イベントの写真がアルバムサイトにアップされることがあります。
今どき多くのサイトでは顔写真検索機能があったりすることも多いのですが、無い所もあって、そういう場合のために自作してしまおうと思ったのがこのChrome拡張を作成した背景です。
実際のChrome拡張: Family Photo Finder

Chrome拡張の機能概要

  • 集合写真やアルバムサイトで家族の姿を見逃さないためのツール。
  • 家族や友人の顔画像を事前に登録し、任意のWebページで同じ人物が写っている写真を見つけて枠で囲って表示する。
  • 機械学習による顔認識なので精度は100%ではなく、検知漏れや誤検知があることをご了承ください。
    • 残念なことに、子どもの顔は精度が低いことが多いです。

使用方法

  1. Chrome拡張をインストールします。

ここから「Chromeに追加」でインストールできます。
2. 探したい人物の顔画像を登録。(初回のみ) 右上にある拡張アイコンをクリックして、ポップアップを開きます。
すると下記のように、表示する「名前」「枠の色」そして「対象人物の顔画像」を登録してください。1人につき3画像登録でき、多く登録するほど検知精度が上がります。
popup
ちなみにこの登録情報はGoogleアカウントで同期されるので、複数のPCで同じ情報が共有されます。
3. 任意のWebページを開きます。 画像に登録した人物が写っている場合、自動で枠が表示されます。 例: sample


技術的な解説

Githubリポジトリはこちら。https://github.com/nisioka/face-api-on-chrome-extention

前提1: 使用ライブラリ

1{
2  "devDependencies": {
3    "@crxjs/vite-plugin": "2.0.0-beta.23",
4    "@types/chrome": "^0.0.268",
5    "typescript": "^5.5.4",
6    "vite": "^5.3.5"
7  },
8  "dependencies": {
9    "@extend-chrome/storage": "^1.5.0",
10    "@vladmandic/face-api": "^1.7.13"
11  }
12}
13

特筆しておくと、

  • @crxjs/vite-pluginはChrome拡張のビルドを行うためのViteプラグインです。マニフェストをTypescriptで型を持ちつつかけたり、いい感じにbuildしてくれたりで、Chrome拡張開発には最適でした。
  • @extend-chrome/storageはChromeのストレージを使うためのラッパーライブラリで、無くてもそこまで困りませんが、async/awaitが使えて楽に綺麗に書きやすかったです。
  • @vladmandic/face-apiはface-api.jsのラッパーライブラリで、TypeScriptで書かれているため、型がしっかりしていて使いやすかったです。

前提2: face-api.jsの紹介

本Chrome拡張では、顔認識機能を実装するためにface-api.jsを使用しています。
face-api.jsとは、ブラウザ上で動作する顔認識用のJavaScriptライブラリです。TensorFlow.jsをベースにしており、高度な顔認識機能を簡単に利用できるように設計されています。
以下はface-api.jsの主な特徴と機能についての説明です。

ブラウザ対応

ブラウザ上で動作するため、クライアントサイドで顔認識を行え、Chrome拡張での利用にも適しています。 サーバーとの通信が不要なため、プライバシー保護にも寄与します。

高精度の顔認識

ディープラーニング技術を使用しており、高精度な顔認識が可能です。 事前に学習されたモデルを利用することで、すぐに顔認識機能を実装できます。

多機能

顔検出、特徴点の抽出、顔のランドマークの検出、顔の特徴ベクトルの取得など、様々な顔認識機能を提供しています。 本Chrome拡張では、顔検出と特徴点の抽出、枠の描画機能も使っていたりします。そのため下記3つのモデルをロードしています。 1つ目は顔検出のために必要、2つ目はランドマーク検出に必要でこれは軽量(tiny)版もありましたが精度が悪く感じたので無印版を、3つ目は顔の特徴ベクトルを取得するために必要です。

  1. ssd_mobilenetv1.weights
  2. face_landmark_68_model.weights
  3. face_recognition_model.weights

ちなみにこれらのモデルデータは、ここから取得しました。

参考

前提3: Chrome拡張マニフェストV3を使用

拡張機能プラットフォームの最新バージョンであるマニフェストV3を使用しています。マニフェストV2は段階的に廃止されています。 スクリプトの実行箇所としては、Webページでの動作のcontent_scriptsと、バックグラウンドで動くservice_workerがありますが、前者のみを使用しています。 後者はマニフェストV3からの物で、これで動かそうとしましたが、face-api.jsが上手く起動されませんでした。 getEnvに失敗した旨のエラーが出ており、こちらのissueの議論を参考にも見ましたが、WebWorker環境での適切な設定がわからず断念しました。

処理詳細説明

1. popup.ts

顔画像の登録としてChromeのストレージに保存、設定値の表示を行うためのものです。
popup.htmlは空っぽで、Chromeストレージから現設定値を初期値として取得し、それを元にゴリゴリとDOMを動的に生成しています。
正直汚くレスポンスも遅いのですが、勢いで書いてしまっています。
ここでユーザが顔写真を登録すると、face-api.jsで顔検出ならびに顔特徴ベクトル(face descriptor)を取得し、それをChromeのsyncストレージに保存しています。
画像自体はChromeのlocalストレージに保存しています。syncには容量の関係で保存が難しいですが、同一端末だけでも画像が見れたほうがいいかと思っての仕様です。

※注: ここで「ストレージ」といっているのは、chrome.storageのことで、一般的なWebブラウザのローカルストレージとかではないです。

2. content_script.ts

各Webページで動作するスクリプトです。
Webページ読み込み時に、当該ページの「imgタグ」と「CSSでbackground-imageを持つもの」を対象に処理を行います。
face-api.jsを使って、顔検出を行いその全てに足して、登録した顔画像と顔特徴ベクトルが近いかどうかを判定し、一致する場合は強調のための枠を描画します。 canvasを用いて描画していて、そのデータURLを、元の画像URLに差し替えることで、表示しています。

まとめ

以上のように、face-api.jsを用いてChrome拡張機能を実装してみました。
Chrome拡張が故に制約が多くて苦労したところも多かったですが、face-api.jsという強力な機械学習ライブラリがブラウザ上で動くことに感動する気持ちが大きかったです。



関連記事