簡単にRaspberry Piを使った物体検出ができるように環境構築してみる

# はじめに
どのご家庭にも、あまっている[Raspberry Pi](https://www.raspberrypi.org/)の一つや二つがあると思いますので、さくっと物体検出できるようにしてみます。

なお、手順はほとんど[こちら](https://github.com/EdjeElectronics/TensorFlow-Object-Detection-on-the-Raspberry-Pi)の日本語訳になります。
（違いは、エラーに対応しただけ）

# 材料
- Raspberry Pi（今回は3B+を使用）
- Webカメラ

なお、OSはRaspbian GNU/Linux 10 (Buster)で確認しました。
また、結構容量を食いますので、SDカードのサイズは大き目がいいです。（今回は128GBで確認）

# 環境構築
ひたすら、Raspberry Piにライブラリ等をインストールしていきます。

<font color="red">なお、途中でうまくインストールできなかったときは、何はともあれ「sudo apt-get update」を試してみてください。</font>

## Raspberry Piのアップデート
updateとupgradeを行います。

```text
$ sudo apt-get update
$ sudo apt-get dist-upgrade
```

なお、upgradeには時間がかかります。

## TensorFlowのインストール
Deep LearningのフレームワークのひとつであるGoogleの[TensorFlow](https://www.tensorflow.org/)をインストールします。

```text
$ pip3 install tensorflow
```

次にTensorFlowが使用しているLibAtlasをインストールします。

```text
$ sudo apt-get install libatlas-base-dev
```

さらにTensorFlowの物体検出の実行に必要なパッケージをインストールしていきます。

```text
$ sudo pip3 install pillow lxml jupyter matplotlib cython
$ sudo apt-get install python-tk
```

## OpenCVのインストール
TensorFlowの物体検出では通常matplotlibで画像の表示を行っているのですが、OpenCVを使ったほうが簡単でエラーも少ないので、ここでは[OpenCV](https://opencv.org/)を使用します。

まずOpenCVの実行に必要なパッケージをインストールします。

```text
$ sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
$ sudo apt-get install libxvidcore-dev libx264-dev
$ sudo apt-get install qt4-dev-tools libatlas-base-dev
```

次にOpenCV本体をインストールします。

```text
$ sudo pip3 install opencv-python
```

## Protocol Buffersのインストール
TensorFlowの物体検出ではGoogleの[Protocol Buffers](https://developers.google.com/protocol-buffers)も使用していますので、こちらをインストールします。
（以前はコンパイルしないといけませんでしたが、今はパッケージがあります）

```text
$ sudo apt-get install protobuf-compiler
```

## TensorFlowのModel Gardenの取得
物体検出などいくつかのモデルを実装したTensorFlowの[Model Garden](https://github.com/tensorflow/models)を取得します。

まずは、保存するディレクトリを用意します。
今回は「tensorflow1」という名前にしました。

```text
$ mkdir tensorflow1
$ cd tensorflow1
```

カレントディレクトリを移動したら、そこにGitから取得します。

```text
$ git clone --depth 1 https://github.com/tensorflow/models.git
```

次に、取得したソースコードにパスを通します。
まず、ファイル「.bashrc」をエディタで開きます。

```text
$ sudo nano ~/.bashrc
```

ファイルの一番最後に、以下の1行を追加し、保存してファイルを閉じます。

```text
export PYTHONPATH=$PYTHONPATH:/home/pi/tensorflow1/models/research:/home/pi/tensorflow1/models/research/slim
```

その後、変更を反映させるため、ターミナルを再起動します。
（「source ~/.bashrc」でもOK）

次に、取得したソースコードの中に.protoファイルがあるので、これをPythonのコードに変換します。

```text
$ cd /home/pi/tensorflow1/models/research
$ protoc object_detection/protos/*.proto --python_out=.
```

カレントディレクトリを、物体検出のホームディレクトリに変更します。
以降実行時も、この場所で行います。

```text
$ cd /home/pi/tensorflow1/models/research/object_detection
```

今回は、物体検出のモデルとして「[SSD（SSD_Lite）](https://arxiv.org/pdf/1512.02325.pdf)」を使用します。
また、Raspberry Piで実行することから、軽めのネットワークである「[MobileNet v2](https://arxiv.org/pdf/1801.04381v3.pdf)」を使用します。
これらを使って[Microsoft COCOデータセット](http://cocodataset.org/)を事前に学習したモデルをダウンロードします。

```text
$ wget http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz
$ tar -xzvf ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz
```

これで準備は完了です。

# 物体検出の実行
まず、実行するためのソースコード（Pythonなので、実行モジュールではなく、スクリプトファイルになります）を取得します。

```text
$ wget https://raw.githubusercontent.com/EdjeElectronics/TensorFlow-Object-Detection-on-the-Raspberry-Pi/master/Object_detection_picamera.py
```

取得したファイルを実行します。

```text
$ python3 Object_detection_picamera.py --usbcam
```

※カメラ画像のウィンドウが表示されるまでに、ワーニング等のメッセージを出力しつつ、30秒ぐらいかかります

なお、WebカメラではなくRaspberry Pi専用の「[Picamera](https://www.raspberrypi.org/products/camera-module-v2/)」を使用して実行する場合は、引数の「--usbcam」を削除してください。

終了するときは、ターミナルのほうで「Ctrl-C」で止めます。

残念ながら、フレームレートが1fpsぐらいですので、もっと速くしたい場合はアクセラレータ等の使用をお勧めします。

## エラー対応
私の環境では、実行時にエラーになってしまいました。

```text
$ python3 Object_detection_picamera.py --usbcam
Traceback (most recent call last):
  File "Object_detection_picamera.py", line 23, in <module>
    import cv2
  File "/usr/local/lib/python3.7/dist-packages/cv2/__init__.py", line 3, in <module>
    from .cv2 import *
ImportError: /usr/local/lib/python3.7/dist-packages/cv2/cv2.cpython-37m-arm-linux-gnueabihf.so: undefined symbol: __atomic_fetch_add_8
```

対処方法として、事前にライブラリを読み込んでおくようにします。
ファイル「.bashrc」をエディタで開きます。

```text
$ sudo nano ~/.bashrc
```

ファイルの最後の以下の1行を追加して、保存します。

```text
export LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1
```

最後のに変更を反映させます。
（ターミナルを再起動してもいいです）

```text
$ source ~/.bashrc
```

これで正常に動作するようになります。

# 注意事項
長時間（5分以上）実行し続けると、CPUがとても熱くなってしまい、シャットダウンしてしまうことがあります。
その場合はCPUにヒートシンクを付ける等の対策をしてください。

# まとめ
少々時間はかかりますが、手順通りにたどっていけば、ほぼ問題なく簡単にRaspberry Piで物体検出の環境が構築できます。

# 参考URL
https://github.com/EdjeElectronics/TensorFlow-Object-Detection-on-the-Raspberry-Pi
https://qiita.com/kobayuta/items/59c7b84caf8994071357
https://github.com/EdjeElectronics/TensorFlow-Object-Detection-on-the-Raspberry-Pi/issues/67
https://qiita.com/XM03/items/48463fd910470b226f22