Ubuntu 20.04 on raspberry pi 4にOpenCVを入れてpythonで使う


# 概要
- Stay Home週間に遊ぶためにraspberry pi 4とHigh Quality Cameraをポチったのですが、カメラは休み前の出荷締切に注文が間に合わず、raspberry pi 4だけ届きました。
- カメラが来たらきっと使うことになるだろうと思い、OpenCVを入れてみました。raspberry pi 4 かつ Ubuntu 20.04かつOpenCVかつpythonで使う　という記事が見つからなかったので残します。

# OpenCVのインストール
ソースコードからビルドしました。

```shell-session
$ wget https://github.com/opencv/opencv/archive/3.4.3.zip -O opencv-3.4.3.zip
$ wget https://github.com/opencv/opencv_contrib/archive/3.4.3.zip -O opencv_contrib-3.4.3.zip
$ unzip opencv-3.4.3.zip
$ unzip opencv_contrib-3.4.3.zip
$ cd opencv-3.4.3
$ mkdir build
$ cd build
$ ./cmake.sh
$ make -j4
$ sudo make install
$ sudo ldconfig
$ cd /path/to/site-packages
$ sudo ln -s /usr/local/lib/python3.6/site-packages/cv2.cpython-36m-aarch64-linux-gnu.so cv2.so
```

cmakeはたくさんオプションがあるのと、何度もやり直したので以下のようにファイルにしておきました。

```shell:cmake.sh
#!/bin/sh
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local \
-D WITH_OPENCL=OFF -D WITH_CUDA=OFF -D BUILD_opencv_gpu=OFF \
-D BUILD_opencv_gpuarithm=OFF -D BUILD_opencv_gpubgsegm=OFF \
-D BUILD_opencv_gpucodec=OFF -D BUILD_opencv_gpufeatures2d=OFF \
-D BUILD_opencv_gpufilters=OFF -D BUILD_opencv_gpuimgproc=OFF \
-D BUILD_opencv_gpulegacy=OFF -D BUILD_opencv_gpuoptflow=OFF \
-D BUILD_opencv_gpustereo=OFF -D BUILD_opencv_gpuwarping=OFF \
-D BUILD_DOCS=OFF -D BUILD_TESTS=OFF \
-D BUILD_PERF_TESTS=OFF -D BUILD_EXAMPLES=OFF \
-D BUILD_opencv_python3=ON -D FORCE_VTK=ON \
-D WITH_TBB=ON -D WITH_V4L=ON \
-D WITH_OPENGL=ON -D WITH_CUBLAS=ON \
-D BUILD_opencv_python3=ON \
-D PYTHON3_EXECUTABLE=`pyenv local 3.6.8; pyenv which python` \
-D PYTHON3_INCLUDE_DIR=`pyenv local 3.6.8; python -c 'from distutils.sysconfig import get_python_inc; print(get_python_inc())'` \
-D PYTHON3_NUMPY_INCLUDE_DIRS=`pyenv local 3.6.8; python -c 'import numpy; print(numpy.get_include())'` \
-D PYTHON3_LIBRARIES=`find $PYENV_ROOT/versions/3.6.8/lib -name 'libpython*.so'` \
-D WITH_FFMPEG=ON \
..

```

私がOpenCVに不慣れな上に、やや特殊な環境なこともあってすんなり行きませんでした。以下の点でつまづきました。

- libjasper-devが無いよエラーが出てどうすればいいんだと悩みました。が、どこかの英語の掲示板に必須じゃないし無理していれなくてもいいんじゃね的なことが書いてあったので飛ばしました。JPEG関係のライブラリらしいです。掲示板の通り入れてなくてもビルドは通りました。
- cmakeでビルドしたあと、`import cv2`ができなくて悩みました。ちゃんと`-D PYTHON3_hogehoge`オプションを付けてpython3向けのMakefileにしてもらう必要がありました。cmakeの結果をちゃんと見てなかったです。。

# matplotlib
画像表示用にmatplotlibを入れました。backendがnon-GUIだよ的なエラーが出たので以下のようにPyQt5を入れました。（試行錯誤しながらやったのでコマンドが足りてない気がします。。）

```
$ sudo apt install -y qt5-qmake qt5-default
$ wget https://sourceforge.net/projects/pyqt/files/sip/sip-4.19.12/sip-4.19.12.tar.gz
$ wget https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.10.1/PyQt5_gpl-5.10.1.tar.gz
$ tar -xvf sip-4.19.12.tar.gz
$ tar -xvf PyQt5_gpl-5.10.1.tar.gz
$ cd sip-4.19.12/
$ python configure.py --sip-module=PyQt5.sip
$ make -j4
$ sudo make install
$ cd ../PyQt5_gpl-5.10.1/
$ python configure.py --qmake /usr/bin/qmake --sip-incdir ~/deeplabcut/sip-4.19.12/siplib
$ make
$ sudo make install
$ pip install pyqt5
```

# pythonで動作確認
レナさんの顔検出ができるか？を題材にOpenCVの動作確認をしました。

```python:cvtest.py
import cv2
import matplotlib.pyplot as plt

cascade_path = '/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml'

def face_detection(img_src):
    img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)
    cascade = cv2.CascadeClassifier(cascade_path)
    facerect = cascade.detectMultiScale(img_gray)
    if len(facerect) == 0:
        print('No face detected')
        return None

    rect = facerect[0]
    cv2.rectangle(
        img_src,
        tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]),
        (255, 255, 255),
        thickness=2)
    return img_src

if __name__ == "__main__":
    lena_path = './lena.png'
    lena_src = cv2.imread(lena_path)
    lena_face_detected = face_detection(lena_src)
    if lena_face_detected is None:
        img_show = lena_src
    else:
        img_show = cv2.cvtColor(lena_face_detected, cv2.COLOR_BGR2RGB)
    plt.imshow(img_show)
    plt.show()
```

以下が実行結果です。無事検出できてますね。ﾜｰｲ

![cvtest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629545/b2f2253e-c728-d029-d82c-5c2c449b174b.png)

カメラが届いたらこれと組み合わせて遊びたいと思います。

以上です。