Node-REDで簡単に顔検出してみる

この記事で使用しているnode-red-node-ui-webcamは、WebRTCをサポートしたNode-REDのDashboard機能の一つです。
HTML5のWebRTCを実装したWebブラウザにカメラが利用できる環境であれば、Node-REDが動作する環境にカメラなどを用意する必要がないため、顔認証などを行うシステムを非常に簡便に構築することが出来ます。

## 動作環境について

Node-RED環境を用意します。httpsによるアクセスを有効にしてください。
パレットメニューより、ノードの追加で以下のノードを追加します。
node-red-dashboard
node-red-node-base64
node-red-node-ui-webcam
node-red-contrib-face-recognition

## テスト環境について

webcamより取り込んだ画像から顔検出を行ってみました。
![face-api.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316451/0de8f8af-0009-a7ce-9fcc-9194d5b7623a.jpeg)

この処理は以下の様な極めてシンプルな構成で行っています。
![face-api-nodered.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316451/a8f70e6b-b280-9099-c0f0-d2c59c0a7d3a.jpeg)

ダッシュボードメニューのWebcamからは、jpegイメージのバイナリデータが出力されます。
face apiへは、msg.payloadから出力されたjpegのバイナリデータをそのまま入力します。
faceapiのノードの設定により得られる情報は変わりますが、出力にはそれぞれのパラメータおよびそれぞれのパラメータを付加した画像がJSON形式で出力されます。
wabcamからのデータおよび、検出結果のデータはjpegイメージのバイナリデータとなりますので、base64ノードで展開して、テンプレートノードによりダッシュボード表示しています。

サンプルのフローを以下に

```
[{"id":"a33ed927.6f9888","type":"change","z":"8c800a7.bed71f8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload[\"face-api-compute\"].image","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":140,"wires":[["45a658cb.1014f8"]]},{"id":"8c3c0205.30fe7","type":"debug","z":"8c800a7.bed71f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":770,"y":80,"wires":[]},{"id":"bff66af1.359f28","type":"ui_template","z":"8c800a7.bed71f8","group":"438d1ff6.c6274","name":"HTMLインライン画像の表示","order":1,"width":0,"height":0,"format":"<div style=\"height: 240px; width: 320px\">\n<img src=\"data:image/low;base64,{{msg.payload}}\"\n width='320'\n height='240'\n id='img'\n alt='getting image'\n />\n </div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":360,"y":240,"wires":[[]]},{"id":"8f36b725.c232f8","type":"ui_template","z":"8c800a7.bed71f8","group":"438d1ff6.c6274","name":"HTMLインライン画像の表示","order":2,"width":0,"height":0,"format":"<div style=\"height: 480px; width: 640px\">\n<img src=\"data:image/low;base64,{{msg.payload}}\"\n width='640'\n height='480'\n id='img'\n alt='getting image'\n />\n </div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":780,"y":240,"wires":[[]]},{"id":"c70b7138.ebfc7","type":"base64","z":"8c800a7.bed71f8","name":"","action":"","property":"payload","x":300,"y":140,"wires":[["bff66af1.359f28"]]},{"id":"45a658cb.1014f8","type":"base64","z":"8c800a7.bed71f8","name":"","action":"","property":"payload","x":760,"y":140,"wires":[["8f36b725.c232f8"]]},{"id":"4b06232c.8e1dfc","type":"ui_webcam","z":"8c800a7.bed71f8","name":"","group":"82a62f87.98d31","order":1,"width":6,"height":5,"countdown":false,"autoStart":false,"hideCaptureButton":false,"showImage":"2","mirror":true,"format":"png","x":140,"y":80,"wires":[["c70b7138.ebfc7","75806a6d.7a55b4"]]},{"id":"75806a6d.7a55b4","type":"face-api-input","z":"8c800a7.bed71f8","name":"Find Faces","numNodes":1,"computeNode1":"7036a75e.c08048","computeNode2":"","computeNode3":"","computeNode4":"","computeNode5":"","computeNode6":"","computeNode7":"","computeNode8":"","computeNode9":"","computeNode10":"","x":450,"y":80,"wires":[["a33ed927.6f9888","8c3c0205.30fe7"]]},{"id":"438d1ff6.c6274","type":"ui_group","name":"face api","tab":"1a1a693e.9db8d7","order":2,"disp":true,"width":12,"collapse":false},{"id":"82a62f87.98d31","type":"ui_group","name":"Webcam","tab":"1a1a693e.9db8d7","order":1,"disp":true,"width":"6","collapse":false},{"id":"7036a75e.c08048","type":"face-api-compute","name":"face-api-compute","childHost":true,"recognitionType":"SSD","multipleFaces":"Multiple Faces","confidence":"50","inputSize":"416","landmarks":true,"expressions":true,"ageGender":true,"recognition":false,"labelName":"known","recognitionMetric":"Mean Squared Error","recognitionConfidence":"","file":""},{"id":"1a1a693e.9db8d7","type":"ui_tab","name":"ホーム","icon":"dashboard","disabled":false,"hidden":false}]
```

## ということで
とりあえず、AzureのFaceとかにも入れてみましたが公開されているノードではシンプルな枠の検出のみでした。詳細なリクエストパラメータをfunctionノードなどで記述してhttpアクセスすれば、様々な情報が取れるはずです。
今回はこの機能でWebcamからの入力処理が簡単に出来るよね、というだけのメモです。