【構築編】RaspberryPi + 物体検出 で室内の人数を slack へ可視化

## 概要
部屋に何人いるかを可視化するシステムを作ります．
カメラで部屋を写し，そこに何人の人間がいるかを検出して，その情報を slack の専用チャンネルに定期投稿します．

こんな風に（大学のゼミ室に設置した例）．
![スクリーンショット 2019-05-28 20.59.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286106/0d4f04e0-5e3c-d8ed-7e42-a788b025e0ad.png)

## 用意したもの
- Raspberry Pi 2 Model B
- microSD (64GB)
- ラズパイ用の電源一式
- LANケーブル
- Logicool C270（UVCに対応していればよい）

## 扱うソフトウェア
- raspbian (2019-04-08-raspbian-stretch-lite)
- uvccapture version 0.4
- [darknet](https://github.com/pjreddie/darknet) commit: 61c9d02

## 手順
### ラズパイのセットアップ
microSD に書き込んで， ssh 接続できるようにします．

### 時刻合わせ
JSTになっていない場合はJSTにしておきます．

```shell-session
$ date
Wed 29 May 02:17:03 BST 2019
```

ファイルを念のためバックアップし，タイムゾーンを変更します．

```shell-session
$ sudo cp /etc/localtime /etc/localtime.org
$ sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ date
Wed 29 May 10:17:49 JST 2019
```

参考：[【Linux】タイムゾーン(Timezone)の変更](https://qiita.com/azusanakano/items/b39bd22504313884a7c3)

### microSDの論理破損対策
[Raspberry PiのSDカードが壊れた！寿命を延ばす方法 5+1選!【運用編を追加】](https://iot-plus.net/make/raspi/extend-sdcard-lifetime-5plus1/)をやれるだけやります．

### ssh接続の設定
`passwd`コマンドで，piとrootのパスワードを変更します．
公開鍵を`.ssh/authorized_keys`に追記．
以下を変更して公開鍵認証を強制します．

```shell:/etc/ssh/sshd_config
PasswordAuthentication no
ChallengeResponseAuthentication no
```

参考：[ssh公開鍵認証設定まとめ](https://qiita.com/ir-yk/items/af8550fea92b5c5f7fca)

ついでにIPアドレスを固定しておきます．

```shell-session:/etc/dhcpcd.conf
interface インタフェース名
static ip_address=アドレス(CIDR表記可）
static routers=アドレス
static domain_name_servers=アドレス
```

参考：[Raspberry Pi 2 (Raspbian: jessie) でIPアドレスを固定する](https://qiita.com/ykog/items/a6dbba1c09e870f8f702)

### カメラでの撮影
`uvccapture`を用います．

```shell-session
$ sudo apt -y install uvccapture
```

`uvccapture -oファイル名`で撮影できますが，そのままでは色味がおかしく，サイズも小さいです．
また，画像は一度検出するためにしか使用しないので，microSDではなく，RAMディスク上の一時領域に書きたいです．
実際には，次のコマンド及びオプションで撮影します．
色味や明るさのパラメータは環境に合わせて要調整です．

```shell-session
$ uvccapture -m -v -B-3 -C20 -S9 -G-15 -q100 -x1280 -y720 -o/tmp/ファイル名
```

参考：[uvccaptureで画像取得](https://tomono.tokyo/2012/10/06/3308/)
参考：[RaspbianでWebカメラを使ってみる（uvccaptureとかmotion）](http://nc30mtd.oops.jp/blog/2015/05/raspbianwebuvccapturemotion.html)

### darknetの用意
部屋に何人の人がいるか検出するために， darknet を使用します．
まずは拾ってきてコンパイルします．

```shell-session:
~ $ git clone https://github.com/pjreddie/darknet
~ $ cd darknet
~/darknet $ make
```

学習済みパラメータを入手します．

```shell-session
~/darknet $ wget http://pjreddie.com/media/files/yolo.weights
```

### 静止画認識の方法
darknet （実行ファイル）を，次のようなオプションで実行します．

```shell-session
~/darknet $ ./darknet detect cfg/yolov2.cfg yolo.weights 読み込ませる画像
```

`cfg` ディレクトリにはいくつかのコンフィグファイルらしきものが見当たりますが，いろいろ試して適切なものを選びます．今回はyolov2を選びました．

また，実行後に検出結果として`Predict.jpg`というファイルが作成されますが，これは利用しません．
標準出力にも検出結果が出るため，画像内に"People"がいくつ検出できたかを知るにはこれで十分だからです．

次のコマンドで，ある画像内の"People"の数を得ます．

```shell
$ /home/pi/darknet/darknet detect cfg/yolov2.cfg yolo.weights (読み込ませる画像) \
| grep "People" | wc -l
```

参考：[【Darknet】リアルタイムオブジェクト認識 YOLOをTensorflowで試す](https://qiita.com/tttttt/items/a33bc8297c9a03b38c74)


### slack にメッセージを投稿する
Incoming Webhooks を利用します．
あらかじめ， slack に専用のチャンネルを作っておくことを推奨します．

https://slack.com/services/new/incoming-webhook にアクセスして，先ほど作成したチャンネルを選び，インテグレーションの追加をします．
そうすると， Webhook URL が割り当てられます．

この Webhook URL に所定の形式でデータを送れば，slackに投稿することができます．簡単な例を次に示します．

```shell-session
$ curl -X POST --data-urlencode 'payload={"text":"これはテストです．"}' 与えられたURL
```

参考：[SlackのIncoming Webhooksを使い倒す](https://qiita.com/ik-fib/items/b4a502d173a22b3947a0)

### 一連の操作を行うシェルスクリプトを作成する．
作成しました．

```shell:~/darknet/watcher.sh
#!/bin/sh

uvccapture -m -v -B-3 -C20 -S9 -G-15 -q100 -x1280 -y720 -o/tmp/cam1.jpg
cd /home/pi/darknet/
res=`./darknet detect cfg/yolov2.cfg yolo.weights /tmp/cam1.jpg | grep person | wc -l`
text="\"現在部屋には ${res}名います．\""
content="payload={\"text\":${text}}"
curl -X POST --data-urlencode "$content" アドレス
```


これを `sudo crontab -u root -e` してcron に登録．

```
*/15 8-22 * * * sh /home/pi/darknet/watcher.sh
```

8時から22時の間，15分おきに実行するように設定しました．

しばらく待って，slackに投稿されていたらokです．
![スクリーンショット 2019-05-28 20.59.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286106/4c0c7426-949e-1d5b-69c5-a03418bd826e.png)
（私の例では，投稿名，アイコンと文章が若干異なります）

## まとめ
カメラによる撮影，darknetの利用，slackの投稿，および一連の処理を連携させて自動実行する方法を示しました．
カメラの画角の都合上，カメラ1個では部屋の一部しかチェックできないでしょう（私の環境ではできません）．余裕があれば，カメラを追加して全体をチェックできるようにしたいですね．


## 更新履歴
2019年7月8日 タイトルを変更（頭に【構築編】をつけました）