Raspberry Piで人数カウントしてTwitterに投稿する

どうもー[isaax](https://isaax.io)の杉田です。この記事は[isaaxアドベントカレンダー13日目](https://qiita.com/advent-calendar/2018/isaax)の記事です。

今年の10月15日に[AIoTLT](https://iotlt.connpass.com/event/103199/)でデモした**Raspberry Piで人数カウントしてTwitterに投稿する**デバイスの作り方の解説をします。
仕組みはコチラのスライドを見てください。

[![Slideshare](//image.slidesharecdn.com/2018-10-15aiotlt-181019101812/95/slide-1-1024.jpg)](//www.slideshare.net/tomoyukisugita/3-ai)
<a href="//www.slideshare.net/tomoyukisugita/3-ai" title="3分で実装完了！エッジ AI デモ" target="_blank">3分で実装完了！エッジ AI デモ</a> from <a href="https://www.slideshare.net/tomoyukisugita" target="_blank">Tomoyuki Sugita</a>

ただ、スライドだけだとどんなデモをしたのかわからないと思うので、少しだけ中身の解説をします。

## この記事のゴール

この記事を読んだ人がisaaxを使って同じ様に実装できるようになることを目指します。

## :warning: 注意点 :warning:
Twitterに人の顔を許可なくアップロードすると__肖像権の侵害__や__プライバシーの侵害__で訴えられる可能性があります。間違っても許諾を取らずに人の顔写真をTwitterに投稿しないようにしてください。(Twitterに限らずですが)

もっとはっきり言うと、この記事を参考にしてみなさんがトラブルを起こしても私は一切責任をとりません。必ず__自己責任で__試してください。

## 前提条件

### 使用機材

* macOS HighSierra or Mojave
* Raspberry Pi 3B+
* Amazonで見つけた1400円位のカメラモジュール

Windowsでも開発出来ると思うけど未検証です。

### 私のスキルレベル

* Gitはバリバリ使える
* PHPはバリバリ書ける
* Pythonは何となく分かる
* Raspberry Piは自分でOS焼いてSSHログインして開発できる程度
* AIは理論はわかるが実装はできない

Pythonはできなくても、基本的なプログラミングができれば__気合__でなんとかなります。

## サンプルコード

[![Slideshare](//image.slidesharecdn.com/2018-10-15aiotlt-181019101812/95/slide-10-1024.jpg)](https://www.slideshare.net/tomoyukisugita/3-ai/10)

https://github.com/tomotomo/raspi-camera-twitter

こちらのサンプルコードをForkしてisaaxに登録すればすぐに使えます。isaaxの使い方についてはコチラの[チュートリアル記事](https://camp.isaax.io/ja/tutorial/getting_started_iot_with_isaax)を見てください。

ベースにしたコードはisaax勉強会で使ったものです。
https://camp.isaax.io/ja/examples/ai-camera-slack

ぶっちゃけSlackへの投稿をTwitterに変更するだけなので、誰でもできそう。

## コードの解説

Twitterへの画像投稿は

1. 画像を投稿してURLを取得
2. ツイートに画像をアタッチする

という2段階になりますので、[Qiitaで見つけたサンプルコード](https://qiita.com/yubais/items/864eedc8dccd7adaea5d)をベースに実装してきます。

コード全体は[Github](https://github.com/tomotomo/raspi-camera-twitter/blob/master/libs/twitter_notification.py)で見てください。重要なポイントだけ解説します。

```python:twitter_notification.py

# Get from Enver Service via isaax
try:
    CK = os.environ['TWITTER_CK'] # Consumer Key
    CS = os.environ['TWITTER_CS'] # Consumer Secret
    AT = os.environ['TWITTER_AT'] # Access Token
    AS = os.environ['TWITTER_AS'] # Accesss Token Secert
except KeyError as e:
    sys.stderr.write('You need to set {} using Isaax.\n'.format(e))
    sys.stderr.write('See: https://isaax.io/docs/ja/environment-variables.html\n')
    sys.exit(1)
```

TwitterのトークンとかシークレットとかGithubに上げたくないので`os.environ`で環境変数から取得します。環境変数がない場合はTwitterに投稿できないので例外終了します。

後述しますが、環境変数はisaaxを使って管理するので、例外発生時に`sys.stderr.write`で[isaaxの環境変数のマニュアル](https://isaax.io/docs/ja/environment-variables.html)に誘導する親切設計にしてみました。


```python:twitter_notification.py
def upload(persons):

    '''省略'''

    # Media ID を付加してテキストを投稿
    now = datetime.datetime.now()
    params = {'status': '{}現在、人が{}人写ってるっぽいね〜 #iotlt #isaax'.format(now.strftime('%H:%M:%S'),persons), "media_ids": [media_id]}
    req_media = twitter.post(url_text, params = params)

```

`upload`関数の引数`persons`はINTです。AIで人数をカウントして、このライブラリの`upload`関数を呼び出して使います。

Twitterは同じ内容をばんばか投稿するとアカウント停止を食らう可能性があるので、投稿内容に`{}現在`という文言を追加して同じ内容にならないようにします。

呼び出す箇所は[person\_detector\.py](https://github.com/tomotomo/raspi-camera-twitter/blob/master/libs/person_detector.py)内に記載しました。コードで言うとこのへん。

```python:person_detector.py

        if persons > 0:
            timestamp = datetime.now()
            if (timestamp - self.last_uploaded).seconds >= 30:
                cv2.imwrite("image.jpg", frame)
                print('Uploading...')
                upload(persons)
                self.last_uploaded = timestamp
                print('Finished.')
```

ここでもやはり、Twitterへばんばかアップロードしてアカウント停止を食らうのが怖いので、`if (timestamp - self.last_uploaded).seconds >= 30:`で30秒以上インターバルを空けないと投稿できないようにしています。

`upload(persons)`の部分をすげ替えてあげれば、Twitter以外へも投稿できるようになるので、割とカスタマイズしやすいかと思います。[元のサンプルコード](https://camp.isaax.io/ja/examples/ai-camera-slack)は人数カウントとアップロード処理が同じファイルに書かれていて改造しにくかったので、きれいに分離する作業を頑張りました。


## Raspberry Piのセットアップ

環境変数を設定する前に、Forkした私のサンプルコードをisaaxのプロジェクトに登録してください。やり方は[チュートリアル記事](https://camp.isaax.io/ja/tutorial/getting_started_iot_with_isaax)に任せて割愛します。

あ、インストールした際に色んなモジュールが不足しているというエラーメッセージがisaaxのダッシュボードに表示されると思いますので、Raspberry Piにログインしてインストールコマンドを実行してください。

```shell:RaspberryPi
# AIのモデルをダウンロードします
cd /home/pi
wget https://github.com/chuanqi305/MobileNet-SSD/raw/master/MobileNetSSD_deploy.caffemodel
wget https://raw.githubusercontent.com/chuanqi305/MobileNet-SSD/master/MobileNetSSD_deploy.prototxt
# 必要なモジュールをインストールします
sudo apt update
sudo apt -y upgrade
sudo apt update
sudo apt install -y build-essential cmake pkg-config
sudo apt install -y libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
sudo apt install -y libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt install -y libxvidcore-dev libx264-dev
sudo apt install -y libgtk2.0-dev libgtk-3-dev
sudo apt install -y libatlas-base-dev gfortran
sudo apt install -y libqtgui4 libqt4-test
sudo apt install -y libilmbase12 libopenexr22 libgstreamer1.0-dev
sudo apt install -y python3-dev python3-pip
sudo pip3 install numpy opencv-python picamera[array] flask imutils pyzbar
```

AIのモデルはGithubのリポジトリに載せてしまうと重くなってしまうので、別にダウンロードします。
たぶん、無駄なPythonモジュールもインストールしてしまってると思うけど気にしない。。。

## Isaaxで環境変数の設定

アプリケーションを動かすための最後の設定です。

[isaax](https://isaax.io/app)のダッシュボードにアクセスして、作成したプロジェクトを開き、__DEFAULTクラスター__を開きます。
![isaax-cluster.png](https://qiita-image-store.s3.amazonaws.com/0/14211/be37578e-4c57-c42e-8836-d122322049ab.png)

画面中程に__Cluster Settings__という項目を見つけることが出来るので、クリックして詳細を開きます。

![isaax-cluster-settings.png](https://qiita-image-store.s3.amazonaws.com/0/14211/2d1069fe-ae5b-0241-6815-a7046c9e729c.png)

__ユーザー変数__のタブをクリックします。

![isaax-cluster-settings-uservar.png](https://qiita-image-store.s3.amazonaws.com/0/14211/287e8983-b1e2-ac2e-8223-e37960981868.png)

すると、RaspberryPiの環境変数を設定できる画面が表示されますので、`TWITTER_CK`, `TWITTER_CS`, `TWITTER_AT`, `TWITTER_AS`の4つを設定します。
設定した変数は、先述した下記のコードでPythonスクリプト内で読み込むことができます。

```python:twitter_notification.py
# Get from Enver Service via isaax
try:
    CK = os.environ['TWITTER_CK'] # Consumer Key
    CS = os.environ['TWITTER_CS'] # Consumer Secret
    AT = os.environ['TWITTER_AT'] # Access Token
    AS = os.environ['TWITTER_AS'] # Accesss Token Secert
except KeyError as e:
```

設定が終わったらアプリケーションを再起動して新しい環境変数を読み込みます。(Pythonはプロセスの起動時に環境変数を読み込むため、再起動しないと変更後の環境変数を取得できないため)

![isaax-cluster-restart.png](https://qiita-image-store.s3.amazonaws.com/0/14211/2b54494b-42b1-ca27-e9ab-d971c55aaed2.png)

ポチッとな。

上手く動くとこんな感じでTwitterに投稿されます。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">人が1人写ってるっぽいね〜 <a href="https://twitter.com/hashtag/iotlt?src=hash&amp;ref_src=twsrc%5Etfw">#iotlt</a> <a href="https://twitter.com/hashtag/isaax?src=hash&amp;ref_src=twsrc%5Etfw">#isaax</a> <a href="https://t.co/GL16en1myn">pic.twitter.com/GL16en1myn</a></p>&mdash; Tomoyuki Sugita (@tomotomobile) <a href="https://twitter.com/tomotomobile/status/1051741309118033920?ref_src=twsrc%5Etfw">2018年10月15日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

投稿時刻をツイートに含めることを忘れてたので`git push`してコードを修正。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">07:55:54現在、人が1人写ってるっぽいね〜 <a href="https://twitter.com/hashtag/iotlt?src=hash&amp;ref_src=twsrc%5Etfw">#iotlt</a> <a href="https://twitter.com/hashtag/isaax?src=hash&amp;ref_src=twsrc%5Etfw">#isaax</a> <a href="https://t.co/NJjtLgPAup">pic.twitter.com/NJjtLgPAup</a></p>&mdash; Tomoyuki Sugita (@tomotomobile) <a href="https://twitter.com/tomotomobile/status/1051743454986784768?ref_src=twsrc%5Etfw">2018年10月15日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

上手く動きました。

## まとめ

AIの実装が全くと行っていいほど出てこなかったけど、それでもできちゃいました。

isaaxを使えば`git push`するだけですぐにデバイスに組み込んだソフトウェアの挙動を変えられるので超楽です。バージョン管理もgithubに紐付いているので、問題の調査も簡単です。

試しに使ってみてください。