SDTest on Raspberry Pi

この記事ではRaspberry Pi 3 Model B+にインストールしたRaspbian Busterを使っています。

# 下準備
Raspberry Pi にRaspbian Busterをインストールするところからはじめます。
## SD Memory Card Formatterをインストール
SDカードをフォーマットするやつです。32GBのカードを使ってます。
[SD Memory Card Formatter - SD Association](https://www.sdcard.org/downloads/formatter/)
## balenaEtcherをインストール
zipファイルを解凍せずに、そのまま書き込めるのがよいです。
[balenaEtcher - Home](https://www.balena.io/etcher/)
## Raspbian Buster with desktopをダウンロード
全部入りじゃない方を使います
[Download Raspbian for Raspberry Pi](https://www.raspberrypi.org/downloads/raspbian/)
# Raspbian Busterのインストール
SDカードをフォーマットして、balenaEtcherで`2019-09-26-raspbian-buster.zip`をSDカードへ書き込む。ここから先の作業はRaspberry Piだけでできますが、VNC越しに作業する場合は設定を有効にします。
Raspberry Pi Configuration Interfaces:

    VNC: Enable

初期ユーザー名とパスワード:

    username: pi
    password: raspberry

Update Software をして再起動

# QTのインストール
今回はRaspberry Pi4でネイティブビルドしたものを配布している神がおられたので、これを使います。qmakeもクロスコンパイルしたものと違ってPi上で動くしラッキー。

    wget https://github.com/koendv/qt5-opengl-raspberrypi/releases/download/v5.12.5-1/qt5-opengl-dev_5.12.5_armhf.deb
    sudo apt-get update
    sudo apt install ./qt5-opengl-dev_5.12.5_armhf.deb
# Qt Creatorのインストール
あとで7インチタッチスクリーン向けにUI最適化するときにUIファイル弄るのに使う。

    wget https://github.com/koendv/qt5-opengl-raspberrypi/releases/download/v5.12.5-1/qt5-opengl-qtcreator_4.9.1_armhf.deb
    sudo apt install ./qt5-opengl-qtcreator_4.9.1_armhf.deb
# PyQt5のビルド
PyQtは自力ビルドするしかないです。sipとPyQt5のバージョンは組み合わせがあるので、最新版を使えばいいってわけじゃなさそうです。

## sip
    mkdir src
    cd src
    wget https://www.riverbankcomputing.com/static/Downloads/sip/4.19.14/sip-4.19.14.tar.gz
    tar -xvzf sip-4.19.14.tar.gz
    cd sip-4.19.14
    python3 configure.py --sip-module=PyQt5.sip
    make
    sudo make install
    cd ..
## PyQt5
これ時間かかります。たぶん2-3時間くらい。扇風機でもよいので冷却ファン推奨。

    wget https://www.riverbankcomputing.com/static/Downloads/PyQt5/5.12/PyQt5_gpl-5.12.tar.gz
    tar -xvzf PyQt5_gpl-5.12.tar.gz
    cd PyQt5_gpl-5.12
    LD_LIBRARY_PATH=/usr/lib/qt5.12/lib python3 configure.py --confirm-license --qmake=/usr/lib/qt5.12/bin/qmake QMAKE_LFLAGS_RPATH=
    make
    sudo make install
    cd ..
## PyQt Webengine
5.12からはWebengineが別モジュール扱いとなったらしいです。

    wget https://www.riverbankcomputing.com/static/Downloads/PyQtWebEngine/5.12/PyQtWebEngine_gpl-5.12.tar.gz
    tar -xvzf PyQtWebEngine_gpl-5.12.tar.gz
    cd PyQtWebEngine_gpl-5.12
    LD_LIBRARY_PATH=/usr/lib/qt5.12/lib python3 configure.py --qmake=/usr/lib/qt5.12/bin/qmake
    make
    sudo make install
    cd ..
# SDTestのインストール
主にOpenCVのインストールに必要なパッケージ群を先に入れときます。
## 必要なパッケージを事前インストール

    sudo apt-get install cmake
    sudo apt-get install libtiff5-dev libjasper-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 libcairo2-dev
    sudo apt-get install libgdk-pixbuf2.0-dev libpango1.0-dev
    sudo apt-get install libgtk2.0-dev libgtk-3-dev
    sudo apt-get install libatlas-base-dev gfortran
    sudo apt-get install libhdf5-dev libhdf5-103
    sudo apt-get install libqtgui4 libqtwebkit4 libqt4-test
    sudo apt-get install llvm
    sudo apt-get install libusb-1.0-0-dev cython
## libuvcのビルド
    cd ~/src
    git clone https://github.com/pupil-labs/libuvc
    cd libuvc
    mkdir build
    cd build
    cmake ..
    make && sudo make install
    sudo ldconfig
    cd ..
## libjpeg-turboのビルド
    cd ~/src
    wget -O libjpeg-turbo.tar.gz https://sourceforge.net/projects/libjpeg-turbo/files/1.5.1/libjpeg-turbo-1.5.1.tar.gz/download
    tar xvzf libjpeg-turbo.tar.gz
    cd libjpeg-turbo-1.5.1
    ./configure --with-pic --prefix=/usr/local
    sudo make install
    sudo ldconfig
    cd ..
## pipのインストール
このプロセスでpipコマンドのデフォルトがpip3になるはずです。pip3しなくてもpip3ってことです。

    cd ~
    wget https://bootstrap.pypa.io/get-pip.py
    sudo python get-pip.py
    sudo python3 get-pip.py
    sudo rm -rf ~/.cache/pip

ターミナルの再起動が必要です。

## cythonのインストール
    sudo pip install cython
## udevルールの設定
これ設定しとかないとカメラ使えないです。

    echo 'SUBSYSTEM=="usb",  ENV{DEVTYPE}=="usb_device", GROUP="plugdev", MODE="0664"' | sudo tee /etc/udev/rules.d/10-libuvc.rules > /dev/null
    sudo udevadm trigger
## pyuvcのインストール
    cd ~/src
    git clone https://github.com/pupil-labs/pyuvc.git
    cd pyuvc
    sudo python3 setup.py install
    cd ..
## virtualenvとvirtualenvwrapper のインストールと設定
    sudo pip install virtualenv virtualenvwrapper
    nano ~/.bashrc

シェルの起動ファイルに次の行を追加

    # virtualenv and virtualenvwrapper
    export WORKON_HOME=$HOME/.virtualenvs
    export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
    source /usr/local/bin/virtualenvwrapper.sh

`Ctrl+x, y, Enter`で閉じて、起動ファイルを再読み込み

    source ~/.bashrc
## 仮想環境の作成
システムパッケージを継承して仮想環境を作ります。

    mkvirtualenv --system-site-packages control_camera -p python3
## SDTestのダウンロード
control_cameraブランチのものを使います。最初masterブランチのQCamera使うバージョンでやってみたのですが、QtMultimediaのGstreamerプラグインじゃカメラの映像がぶっ壊れます。

    git clone -b feature/control_camera https://github.com/RUTILEA/SDTest.git
    cd SDTest
    nano requirements/base.txt

`opencv-contrib-python`を残して`opencv-python`をコメントアウト。PyQt5はさっきインストールしたのでこれもいらない。tensorflowとkerasのバージョンを変更。Raspbian BusterはPython 3.7なので、tensorflow 1.13以降で。kerasは2.3系だとグラフがないよみたいなエラー出る。

    jinja2
    #opencv-python
    
    ###### Requirements with Version Specifiers ######
    fbs[sentry] == 0.8.3
    #PyQt5 == 5.9.2
    PyInstaller == 3.4
    tensorflow == 1.13.1
    keras == 2.2.4
    imageio == 2.*

`Ctrl+x, y, Enter`で閉じる
## camera_model.pyを編集

    nano src/main/python/model/camera_model.py

uvcのインポートコードを修正

    import queue, cv2, copy
    import uvc
    
    class CameraModel(QObject):

`Ctrl+x, y, Enter`で閉じる
## novelty_detector.pyを編集

    nano src/main/python/module/novelty_detector.py

MobileNetV2とLOFを使うように変更。nth_layerは、とりあえず42で。どのあたりのレイヤーでぶった切ったらいい感じなのか、よくわかってないです。

    class NoveltyDetector:
    
        def __init__(self, nth_layer=42, nn_name='MobileNetV2', detector_name='LocalOutlierFactor', pool=None, pca_n_components=None):
            """

メモリ不足に対応するためバッチサイズを指定

    self._load_NN_model(imgs[0].shape)
    feature = self.extracting_model.predict(imgs, batch_size=16, verbose=1)
    if self.pca_n_components:

2箇所ある

        self._load_NN_model(imgs[0].shape)
    feature = self.extracting_model.predict(imgs, batch_size=16, verbose=1)
    if self.pca_n_components:

`Ctrl+x, y, Enter`
## 依存パッケージの一括インストール

    pip install -r requirements/base.txt -U

## スワップサイズの変更
メモリ不足するのでワップサイズの変更は必須です。やっぱPi4の4GBモデルほしい。

    sudo nano /etc/dphys-swapfile

100MBから1024MBへ

    CONF_SWAPSIZE=1024

`Ctrl+x, y, Enter`で閉じて、dphys-swapfileサービスを再起動

    sudo /etc/init.d/dphys-swapfile stop
    sudo /etc/init.d/dphys-swapfile start

## プログラムの起動
opencv4の不具合？回避のためライブラリをプリロードしてます。学習枚数100枚くらいまでなら動きます。推論時間は2秒くらい。

    export LD_LIBRARY_PATH=/usr/lib/qt5.12/lib
    cd SDTest
    workon control_camera
    LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1.2.0 python src/build.py run
長くなったので、7インチタッチスクリーンへのUI最適化は別の記事に。

# 参考リンク
[Building PyQt5 for Python 2 on Linux - Rigaut-Luczak Lola - Medium](https://medium.com/@Lola_Dam/building-pyqt5-for-python-2-on-linux-b054f697b60c)
[Install OpenCV 4 on Raspberry Pi 4 and Raspbian Buster - PyImageSearch](https://www.pyimagesearch.com/2019/09/16/install-opencv-4-on-raspberry-pi-4-and-raspbian-buster/)