Raspberry Piで作るお子様帰宅チェック


今年も武蔵野アドベントカレンダーで久々に記事投稿です。
今年は春頃買ったRaspberry Piくんが放置されていて可哀想なので、活用してみよう！というチャレンジを記録します。

# 今回の目的
で、何をするといいんだろうねぇ。。。と言うことで、「[カラー図解　Raspberry Piではじめる機械学習　基礎からディープラーニングまで](http://bluebacks.kodansha.co.jp/books/9784065020524/appendix/)」を読んでみて、じゃんけんプログラム？？とか考えつつ、本と同じでも書く意味もない。
ということで、カメラモジュール使って、玄関に設置して子供が帰宅したら顔を認識してSlackにメッセージ送るようなプログラムでも作ってみることにしました。

# 用意するもの
とりあえず、今回は以下を準備して実験実験。
- Raspberry Pi 3B+
- Raspberry Pi用のカメラモジュール

# やってみよう！
プログラム自体はサンプルなど世の中にあり特に問題なく動いたが事前準備ががが。。。
## 事前準備（ソフト編）
### OSインストール
- Raspbianを入れてます。入れ方はネット上にたくさん記事あるのでご参照のこと。
- wifiの接続設定は実施しておく。
- あと、tightvncserverとかインストールしてVNCで普段使ってるデスクトップから接続できるとカメラで写ってるものが確認できたりと色々便利でした。

### Pythonのインストール
- pythonだけは買った直後の四月ごろにインストールしてたので、どうやって入れたのか、元から入っていたのか全く記憶にないのです。。。まあ、誰でもインストールできるだろう。

### OpenCVなど必要パッケージのインストール
OpenCVはソースコンパイルからやってたんですが。。。実はパッケージ落ちてるんですね。。。orz。夜中に２時間半くらいコンパイル終わるの待ってしまったよ。。。

#### OpenCVのパッケージのインストール
こんな感じでお手軽。

```
$ sudo apt-get install libopencv-dev
$ sudo apt-get install python-opencv
```

#### picameraのインストール
Raspberry PiのカメラモジュールをPythonから触るためのパッケージ。
   
```
$ sudo pip install "picamera[array]"
``` 

#### slackwebのインストール
slackのAPI操作するためのパッケージ

```
$ sudo pip install slackweb
```

さらに、プログラムから投稿するためにはSlack側でBotを作ってあげる必要があります。
slackの設定画面に行って、「Incoming WebHooks」あたりでチャンネル追加して設定すると、投稿用のURLが出てくるので控えておきましょう。

## 事前準備（ハード編）
カメラモジュールをRaspberry Piに取り付ければOK。

### 取り付け
開封前：
![00ED874B-5241-4AB6-AD4E-3A306F8C0723.jpeg](https://qiita-image-store.s3.amazonaws.com/0/216557/1cd52b7a-cf40-2b68-66ac-0ba9427ab9c6.jpeg)
こんな箱に入ってます。
本体と同じくらいな箱だけど中身は小さいっ！！

取り付けた写真：
![3B807861-54BD-44AE-AAD5-1E8F524933A9.jpeg](https://qiita-image-store.s3.amazonaws.com/0/216557/bf9e3360-9a3c-c5ac-2b45-5cb58d26d2dc.jpeg)
開けたら、所定の場所に取り付け。
取り付ける時は、ケーブルの向きに注意〜。
ちなみにこの配置だとカメラは上下逆になってるので、さかさの映像になるので、使うときは直そう。

### 設定
カメラモジュールの使用を許可する設定を行う必要があります。
Raspberry PiのGUIのメニューからRaspberry PiのConfig選んでも一向に設定画面が出て来ない。。。
ということで、コマンドっ！

```
$ sudo raspi-config
```

cameraをenableにして再起動すればOK。

### 動作確認
とりあえず、カメラを認識してるか確認するために以下を入力し、jpg画像が保存されて入ればOK。
このコマンド自体はカメラに映ってる内容をjpgに保存するもの。

```
$ raspistill -o test.jpg
```

## プログラムしてみる
やっと本題！！
カメラに映った顔をしたら、slackにメッセージ飛ばしてみるのです。
今回は、[raspberry pi opencv ビデオで顔認識](https://kokensha.xyz/raspberry-pi/raspberry-pi-face-detection-with-opencv-no-compile/#i-7) を参考にして、

- 動画表示する部分を削除
- 顔検出された場合にslackへ送信
- 顔認識するたびに投稿くるとウザいので、投稿間隔（１分以内だったら再投稿しない）処理を追加。

こんなソースになりました。

```python:face_post.py
from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2, time
import slackweb
from datetime import datetime

# slackpost
slack = slackweb.Slack(url="[SlackのWebHooksで設定されてるURL]")

last_post = datetime(2018, 12, 1, 00, 00 ,00)

# フレームサイズ
FRAME_W = 320
FRAME_H = 192

# 正面の顔検出用
cascPath = '/usr/local/share/OpenCV/lbpcascades/lbpcascade_frontalface.xml'
faceCascade = cv2.CascadeClassifier(cascPath)

camera = PiCamera()
camera.resolution = (FRAME_W, FRAME_H)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(FRAME_W, FRAME_H))
time.sleep(0.1)

for image in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):

    frame = image.array

    # Convert to greyscale for detection
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.equalizeHist( gray )
    # 顔検出
    faces = faceCascade.detectMultiScale(gray, 1.1, 3, 0, (10, 10))

    # 顔が検出された場合の処理
    if len(faces) >= 1: # 検出されるとfacesの配列が１以上になる
        now_time = datetime.now()
        diff = now_time - last_post
        if diff.total_seconds() > 60: # 60秒以上間隔が空いてればポスト。連続ポスト防止。
            slack.notify(text="顔認識したよ")
            last_post = datetime.now()
    frame = cv2.resize(frame, (540,300))

    key = cv2.waitKey(1) & 0xFF

    rawCapture.truncate(0)
```

## 動かしてみる
今回は正面の顔しか認識しない＋誰ってのも認識しないので、「誰か」いるのがわかるレベルです。
とりあえず、正面からカメラに映るとちゃんとスラックにメッセージ飛んでるよ〜〜〜〜っ！！
ちなみに下の写真で6:11に連続で認識してるところは、1分以上間隔あけて投稿するロジック入れる前で顔が見つかるとひたすら投稿するようになってたのでした。
![FFA3CC85-2DCE-4531-A56F-F10CBD9D2980.jpeg](https://qiita-image-store.s3.amazonaws.com/0/216557/95b54a30-9343-d5c3-8960-2a1cc21a49e8.jpeg)

今後は子供を識別して、「●●ちゃんが帰って来たよ」とかメッセージ遅れるといいかもしれない。
が、子供同士結構似た顔してるのでそれ識別できるんだっけ？？というあたりが非常に気になる。。。

# おまけ
カメラモジュール、雑に扱ってましたら。。。なんと先頭が外れてしまいました。。。orz
壊れたカメラの写真：
![7D06E40F-D610-4D26-9273-F1106309728D.jpeg](https://qiita-image-store.s3.amazonaws.com/0/216557/a1459080-6085-d7cb-1d11-d6d3e63aea2d.jpeg)



なくなったカメラ部分は見つからないし、まだプログラム作る前だったので、慌てて再調達。。。
ヨドバシカメラだと、在庫あれば当日受け取れて便利っ！かつポイントあったから出費が抑えられたが。。。

結論；精密機器は大切に扱いましょう。