Actcast α の顔認識機能で取得した画像をGASでGoogle Driveに保存する

この記事を見て自分もやりたくなったので、今回はバックエンドとしてGASを使ってみることにしました。
https://qiita.com/revsystem/items/d8413c179bcc3f4726e8

尚、GAS自体の説明はしません。

## スプレッドシートの作成

自分のGoogleアカウントでログイン後に適当に新規にスプレッドシートを作成してください。
ブラウザで https://sheet.new にアクセスすれば作成できます。

## GASの作成

ツール>スクリプトエディタをクリックで作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/0b71a7ab-0cf5-a67d-7b98-8be708552c0a.png)

## GASのソースコードを記述

```js
function writeFile(data) {
  var drive = DriveApp.getFolderById('AAAAAAAA....'); // 後述する自分が作成したGoogle DriveのフォルダのID
  var fileName = 'sample.png';
  var contentType = 'image/png';
  var decoded = Utilities.base64Decode(data);
  var blob = Utilities.newBlob(decoded, contentType, fileName)
  drive.createFile(blob);
}

function doPost(e) {
  var params = JSON.parse(e.postData.getDataAsString());
  writeFile(params.face_image);
  return ContentService.createTextOutput("ok");
}
```

## Google Driveでフォルダを作成

https://drive.google.com/drive

Driveのページの「新規」ボタンから新しくフォルダを作成してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/1d86a593-2035-7e3f-cf49-22c5578dafb6.png)

作成したフォルダに移動してURLの `/folders/` よりあとのランダムな文字列がIDです。
これを先程記述したGASの `getFolderById` の引数部分に記述してください。

## GASの実行の承認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/cd42853f-294d-1887-0f01-ff7ec6df3a9c.png)

この記事のままやっている場合は、functionのプルダウンに2つの関数が選択可能になっているので、それぞれ選択した後に「▶」ボタンを押して実行してください。承認を求められるので適当に承認してください。

## GASをAPIとして公開する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/797a2eed-6306-07ad-8875-92878ed6acfb.png)

公開＞ウェブアプリケーションとして導入…

より公開設定を行います。以下の様に設定してください。

- 「次のユーザーとしてアプリケーションを実行:」→自分
- 「アプリケーションにアクセスできるユーザー:」→全員（匿名ユーザーを含む）

こうすることで、検知した画像を受け取れるようになります。

決定するとURLが手に入るので、今度はそれをactcast側の管理画面で入力してあげます。
このままだと誰からのPOSTも許すことになるので、URLの管理には注意してください。

## actcast側の設定

すでにFace Trackingができることを前提にしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/aaf441f2-7138-a364-d6d8-41087aac41c4.png)

castを選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/01187740-165c-531a-da4b-c8677667e49c.png)

Conditionsの部分でActionの発火条件を決められます。一旦動作を確認したいのでprobabilityが0より大きいと設定しましたが、あとから必要に応じて調整してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/c6636051-09ea-c78b-2e21-dd3b30cefed5.png)

次にActionを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/8e236673-a4c7-2fe5-b8b1-a77b9853b166.png)

Webhookを選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/88ab9002-71b0-63cd-94b6-7dbe3426c72c.png)

URL部分に先程のGASのURLを、Bodyの部分に以下を記述してください。

```json
{"face_image": "{{ data.face }}", "prob": "{{ data.prob }}", "timestamp": "{{ data.timestamp }}"}
```

`data.face` 部分に検出した顔部分だけをcripした画像をbase64エンコードした文字列が入ります。
先程記述したGASでは、それを受け取り元の画像の形式に戻しています。

終わったら「Finish」を押して完了してください。

## 実際の動作を確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/60fcad07-9411-34c7-08e7-96592488e158.png)

※スクショは画像の全体が見えないようにあえて上の部分だけを切り取ってます

カメラを顔に向けてちょっと待つとDriveに画像がアップされていきます。
発火自体は一回認識した顔がカメラから外れて再度現れたときみたいなので、体を揺らしてカメラの枠から外れてください。傍から見るとシュールです。

## 画像の精度について

α版だから、DEMOだからという前置きが必要ですが、めちゃくちゃぶれてます。
HDMIでカメラつないで映像を見ている分には普通に顔だと認識できるのですが、
CASTで送られてくる画像だけぶれまくってます。

おそらく顔だと認識するのが早すぎるのかなと思いますが、唯一いじれるprobabilityを変えても特に変化なし。
顔だと認識したあとちょっと待ってくれれば、カメラに映る映像も安定するので、それを使ってほしいですが、一旦こちらからはいじれないので、そういう調整はできないですね。

この辺は中の人に教えてもらえばすぐ改善する系の話かもですが、次のβ版ではデフォでいい感じに動くように改善していてほしいかも。

## 最後に

Face Tracking以外にも色々遊べるので、別に画像自体を使わなくて以下のことができます。

- 席についたら「おかえりなさい」と通知
- 顔の位置が下がったら「姿勢悪いぞ！」と通知
- 顔年齢が上がったら「老け顔になってるよ？」と通知

ソースコードも実質10行くらいだし、難しいサーバーの設定とかもいらないので、個人利用で速度とか考えないなら、GASを利用するのが1番コスパいい方法かなと思いました。GASなら受け取ったあと様々なことができるので。

こちらからは以上です。