Raspberry Pi & Node-REDのface-api-inputノード（顔検出・顔認識）を試してみる

この記事は[Node-RED Advent Calendar 2020](https://qiita.com/advent-calendar/2020/node-red) 19日目の記事です。

# はじめに
今回はいろんなノードを見ている中で気になったものを試してみました。
その中で顔検出・顔認識に興味があったのでnode-red-contrib-face-recognitionを試してみました。

<img width="300px" alt="2020-12-17 21.48.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171737/2056ba11-7830-7c28-d046-671bb90a1b97.png">

# 利用するデバイス
- Raspberry Pi 3 (2019-12-13-raspbian-stretch をインストール）

# 使用したノード
node-red 1.2.6
node-red-contrib-face-recognition 1.3.3
node-red-node-base64 0.2.1
node-red-contrib-image-output 0.6.2

# face-api-inputノードに使われているface-api.jsはどういうものか
face-api.jsは、顔検出・顔認識のための「JavaScript API」です。tensorflow.js（tensorflow/tfjs-core）上に実装されています。
face-api.jsでは、顔検出、顔のランドマーク検出、顔認識、表情認識、年齢推定、性別認識といったモデルが利用できるみたいです

[詳細は、face-api.jsのgithubを参照してみてね](https://github.com/justadudewhohacks/face-api.js#running-the-examples)

# フローの全体は次の通りです。（公式のサンプルを使用）
![スクリーンショット 2020-12-17 20.41.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171737/7bf40aa7-4094-a8f4-0ad3-09c6b12bfb79.png)

「Find Faces」の名前のノード箇所がface-api-inputノードになります。
<img width="260px" alt="a12812c8-9967-d873-3fda-4717ea635246.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171737/a12812c8-9967-d873-3fda-4717ea635246.png">

動作の流れはこんな感じです。
- inputノードのボタンをクリックすることで実行します。
- httpノードに設定されたurlの画像をもとに顔検出を行います。
- 検出した結果を「Set Payload to Image」（changeノード）のノードにて結果の画像を取得します。

# 実行する前に、node-canvasが必要なので以下のものをインストールします
```bash
$ sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
```
# 実行するとこのような結果になります
![スクリーンショット 2020-12-17 20.33.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171737/7488b8e9-ce70-62b0-f64b-4a9e2e22472f.png)

 実は、結果がでるまでcomputingのまま....
![スクリーンショット 2020-12-16 19.24.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171737/5c33905f-a909-3830-5124-ac02c1cde45a.png)


 私のラズパイで３分弱で結果がでました :grin:

## そこでOptionのTensorFlow.jsをインストールします。今回は、公式に書かれている1.2.11[^1]をインストールしました。
```bash
$ cd .node-red/
$ npm install @tensorflow/tfjs-node@1.2.11
```
[^1]: 最新のものをインストールしたらface-api-inputノードが表示できなくてなったのでバージョンを指定しました

3分弱で結果がでたのが8秒ぐらいで結果でましたー！！（顔検出の内容は同じ結果）

# 別な画像でも試してみました。
新垣結衣＆星野源「逃げ恥」の当時の画像で実行し、年齢を見てみると、
星野源さんは42歳で判定（当時39歳）、新垣結衣さんは40歳（当時32歳）でした :grin:
女性の年齢判定は、顔の表情とかで変わってしまうかもしれないです。 :grin:

みなさんもいろんな画像で試してはいかがでしょうか？
今度は、Webカメラでできるかどうか試してみたいと思います

# フローのソースコードです。
```json-doc
[{"id":"8c800a7.bed71f8","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"5c9785ae.c524dc","type":"inject","z":"8c800a7.bed71f8","name":"Input","repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"","payloadType":"date","x":170,"y":300,"wires":[["bb3493cb.b73e2"]]},{"id":"beebc96a.133208","type":"change","z":"8c800a7.bed71f8","name":"Set Payload to Image","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload[\"TBB Faces\"].image","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":360,"wires":[["2bdf00a.e8771"]]},{"id":"e0664c84.eb4f5","type":"debug","z":"8c800a7.bed71f8","name":"Debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":300,"wires":[]},{"id":"bb3493cb.b73e2","type":"http request","z":"8c800a7.bed71f8","name":"Get Image","method":"GET","ret":"bin","paytoqs":false,"url":"https://thumbor.forbes.com/thumbor/960x0/https%3A%2F%2Fblogs-images.forbes.com%2Fmaddieberg%2Ffiles%2F2017%2F09%2Fbigbangtheorytv_s05e01_05-_h_2017.jpg","tls":"","proxy":"","authType":"basic","x":330,"y":300,"wires":[["c70b7138.ebfc7","75806a6d.7a55b4"]]},{"id":"75806a6d.7a55b4","type":"face-api-input","z":"8c800a7.bed71f8","name":"Find Faces","numNodes":1,"computeNode1":"5adfec11.8f4ef4","computeNode2":"","computeNode3":"","computeNode4":"","computeNode5":"","computeNode6":"","computeNode7":"","computeNode8":"","computeNode9":"","computeNode10":"","x":510,"y":300,"wires":[["e0664c84.eb4f5","beebc96a.133208"]]},{"id":"c70b7138.ebfc7","type":"base64","z":"8c800a7.bed71f8","name":"","action":"","property":"payload","x":180,"y":360,"wires":[["16eacc92.6a4173"]]},{"id":"2bdf00a.e8771","type":"image","z":"8c800a7.bed71f8","name":"Labeled Image","width":"640","data":"payload","dataType":"msg","thumbnail":false,"pass":false,"outputs":0,"x":760,"y":400,"wires":[]},{"id":"16eacc92.6a4173","type":"image","z":"8c800a7.bed71f8","name":"Input Image","width":"640","data":"payload","dataType":"msg","thumbnail":false,"pass":false,"outputs":0,"x":190,"y":400,"wires":[]},{"id":"5adfec11.8f4ef4","type":"face-api-compute","name":"TBB Faces","childHost":true,"recognitionType":"SSD","multipleFaces":"Multiple Faces","confidence":"50","inputSize":"416","landmarks":true,"expressions":true,"ageGender":true,"recognition":false,"labelName":"known","file":""}]
```