Raspberry Pi 3B (Ubuntu16.04)　にopenCV3.x をいれよう

#概要
以前Coral Edge TPU を使って、TensorFlowLiteを用いた機械学習のコードを実行させました。
この時は単純にTPUのテストとして遊んだだけだったので、ホストはそのへんに転がっていた Ubuntu16.04 のPCだったのですが、今回はラズベリーパイをホストにして推論させようと思い、まずはささっとライブラリの準備、、と思ったのですが、これに思った以上に時間を食われてしまったので、解決策を共有しておきます（ものすごくダサい方法なので、もっとエレガントな方法があるはず！！）

時間がかかりすぎて何に詰まったか覚えてすらいないので、思い出せる範囲で雑に書いていきます。

私のようなLinux初心者の方は、最終手段として使ってください

#環境
ハードウェア: Raspberry Pi 3 Model B
OS        : Ubuntu 16.04
python　  : python3.5.2 (3.6や3.7でもできると思います、未検証ですが)

★入れることのできるopenCVのバージョン:
openCV3.3.x、またはそれより古いもの


#openCVのインストール
##まずはpipのバージョン確認
このような辺鄙な投稿につられてきた方にはそもそもopenCV等ライブラリを説明する必要はないと思うので、早速本題からいきます。

まず、pip(もしくはpip3など)コマンドでopenCVをいれることのできた方はここでさよならです。他の方がとても綺麗にまとめてくださっているので、こちらをご覧ください。
https://qiita.com/atuyosi/items/5f73baa08c3408f248e8
https://qiita.com/kazuppp/items/ceee999aef8cddbb252c
contribのほうがいろいろ入ってるみたいですが、機械学習のための画像処理目的であれば上記のライブラリで大丈夫です、多分

```
>> pip install opencv-python または
>> pip install opencv-contrib-python
```

上記pipを実行して、次のエラーがでた勇者の方は是非続きをお読みください。

```
Collecting opencv-python
  ERROR: Could not find a version that satisfies the requirement opencv-python (from versions: none)
ERROR: No matching distribution found for opencv-python
```

なお、上記のエラーはpython3.7の場合に出るみたいです。python3.5でなんで出るんだよ！って思うんですが、仕方ないので3.7をお使いの方はダウングレードをするか、リポジトリのURLを直接ぶち込みましょう。（後述）


なお、そもそもopenCVを実行したいpythonのバージョンと、pipでインストールされるパッケージのパッケージのバージョンが違う恐れがあるので、一応確認してください。なお私のラズパイは指定なくpipやpip3するとpython3.4に入ります。。

```
>> pip show pip または
>> pip3 show pip

ame: pip
Version: 19.1.1
Summary: The PyPA recommended tool for installing Python packages.
Home-page: https://pip.pypa.io/
Author: The pip developers
Author-email: pypa-dev@groups.google.com
License: MIT
Location: /home/Me/.local/lib/python3.4/site-packages
Requires: 
Required-by: 
```

Locationが　.local　以下のpython3.4になってますね、これだとせっかくpipでいれてもpython3.5ではなく3.4の方に入ってしまうので、pipの際3.5で入れられるように指定しましょう。

```
>> python3.5 -m pip command ...
```

一応確認

```
>> python3.5 -m pip show pip
Name: pip
Version: 19.1.1
Summary: The PyPA recommended tool for installing Python packages.
Home-page: https://pip.pypa.io/
Author: The pip developers
Author-email: pypa-dev@groups.google.com
License: MIT
Location: /usr/local/lib/python3.5/dist-packages
Requires: 
Required-by: 
```

ちゃんと Location が python3.5 になってますね、私はシステムの python3.5 にいろいろぶち込みましたが、ご覧の方は virtualenv などで環境を分けたほうがいいと思います。openCVの公式にもそう書いてあります。

毎回pipの際にバージョン指定するのがめんどくさいならpipのパスを変えてもいいですね。私はパスを変えていないので、以後pipを使う際は、バージョンを指定しています。

```
>> echo 'export PATH="$HOME/Library/Python/3.5/bin:$PATH"' >> ~/.bashrc
>> source ~/.bashrc
```

pipのバージョンが古い方は、アップデートしたほうがいいかもしれません。とにかく19.1.1ではうまくいきました

```
python3.5 -m pip install --upgrade pip  
```

## openCVのインストール
それではopenCVをいれましょう。先ほどはpipでパッケージの名前を指定しても見つからなかったので、仕方ないのでリポジトリのURLをぶち込んで直接いれましょう。

```
python3.5 -m pip install  https://www.piwheels.org/simple/opencv-python/opencv_python-3.3.0.9-cp35-cp35m-linux_armv7l.whl
```

cp35となっている箇所は、python3.6の方はcp36になってると思います。
万が一以下のエラーがでるようであれば、最後のハイフンとハイフンの間をお使いのプラットフォームに対応したものに変更してください。こちらのサイトがとても参考になります。https://qiita.com/r-ngtm/items/f7dc53bf713d12f6be9d

```
>> python3.5 -m pip install  https://www.piwheels.org/simple/opencv-python/opencv_python-3.3.0.9-cp35-cp35m-linux_armv7l.whl --user
ERROR: opencv_python-3.3.0.9-cp35-cp35m-linux_armv7l.whl is not a supported wheel on this platform.
```

``` プラットフォームに対応したwhlファイルの確認方法
>> python3.5
>>> from pip._internal.pep425tags import get_supported
>>> get_supported()
[('cp35', 'cp35m', 'linux_armv7l'), ('cp35', 'abi3', 'linux_armv7l'), ('cp35', 'none', 'linux_armv7l'), ('cp34', 'abi3', 'linux_armv7l'), ('cp33', 'abi3', 'linux_armv7l'), ('cp32', 'abi3', 'linux_armv7l'), ('py3', 'none', 'linux_armv7l'), ('cp35', 'none', 'any'), ('cp3', 'none', 'any'), ('py35', 'none', 'any'), ('py3', 'none', 'any'), ('py34', 'none', 'any'), ('py33', 'none', 'any'), ('py32', 'none', 'any'), ('py31', 'none', 'any'), ('py30', 'none', 'any')]
>>>
```

私の環境では('cp35', 'cp35m', 'linux_armv7l')　が対応しているので、その名前のwhlファイルでおっけーでした。

このopenCVのインストールは、numpyのインストール及びビルドも行われるので（多分）数時間かかることもあります。気長に寝て待ちましょう。なお、なんかnumpyのなんとかでエラーが出ていたら、古いnumpyをアンインストールしましょう。

```
python3.5 -m pip uninstall numpy
```

sudoとか--userとかは必要ならつけてください。なお、勝手にnumpy　1.18のように最新のnumpyが勝手に入るので、必要と思ったらダウングレードしてください。私は1.16にダウングレードしました。


```
>> python3.5 -m pip list | grep numpy
numpy                        1.16.2
```

numpyのダウングレード

```
>> python3.5 -m pip install numpy==1.16.2
```

また、どうしてもopenCVの3.4以降をいれたい方はリポジトリのバージョンを3.4.4.19とかに変えればインストールはうまく行きます。しかしインポートはおそらくうまくいかないので、調べた範囲で解決策をかいておきます。私は3.3でいいので上記でやりました。


## openCVのインポート
必要なパッケージのインストールが終わった（終わったとは言っていない）ので、実際にpythonでインポートしてみましょう。

```
>> python3.5
>>> import cv2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: /opt/ros/kinetic/lib/python2.7/dist-packages/cv2.so: undefined symbol: PyCObject_Type
```

cv2のインポートの際に２系のパッケージを探しにいってるみたいですね。２系や、異なる３系のバージョンでopenCVを入れている際に起こるエラーです。いろいろ解決策はあるのですが、一番早い解決方法を書いておきます。

```
unset PYTHONPATH
```

これでpathがリセットされるので、面倒ですがターミナルを立ち上げるごとにやってください。

では気を取り直してもう一度

```
>> python3.5
>>> import cv2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/nakasato/.local/lib/python3.5/site-packages/cv2/__init__.py", line 9, in <module>
    from .cv2 import *
ImportError: libwebp.so.6: cannot open shared object file: No such file or directory
```

いやになっちゃいますね。このlibwebp.so.6は、aptで入れることができるなら入れたらいいと思います。https://qiita.com/atuyosi/items/5f73baa08c3408f248e8
それができればopenCVの3.4以降も入れることができるはずです。

私のケースでは、

```
>> sudo apt install libwebp6
Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package libwebp6
```

のように、apt-add-repositoryで参照するリポジトリを指定しないといけない（よくわからない）ので、諦めました。（後書き参照）

このlibwebpはopenCVが依存している画像処理系のパッケージの一つです。他にもたくさんあるので、openCVのバージョンによっては全てインストール必要があります。このlibwebpにはいくつかバージョンがあり、ラズパイと私のPCで全く同じパッケージのバージョン、OSにしているはずなのに、依存しているバージョンが５だったり６だったりでよくわからないので、非常にみっともない方法で解決しました。

まずはlibwebpが入ってるかの確認。apt-file　コマンドが入っていなければ、適当にaptでインストールしてください。インストール後のアップデートを忘れずに

```
sudo apt install apt-file
apt-file update
```


```
>> apt-file search libwebp
libwebp-dev: /usr/lib/arm-linux-gnueabihf/libwebp.a
libwebp-dev: /usr/lib/arm-linux-gnueabihf/libwebp.so
libwebp-dev: /usr/lib/arm-linux-gnueabihf/libwebpdemux.a
libwebp-dev: /usr/lib/arm-linux-gnueabihf/libwebpdemux.so
libwebp-dev: /usr/lib/arm-linux-gnueabihf/libwebpmux.a
libwebp-dev: /usr/lib/arm-linux-gnueabihf/libwebpmux.so
libwebp-dev: /usr/lib/arm-linux-gnueabihf/pkgconfig/libwebp.pc
libwebp-dev: /usr/lib/arm-linux-gnueabihf/pkgconfig/libwebpdemux.pc
libwebp-dev: /usr/lib/arm-linux-gnueabihf/pkgconfig/libwebpmux.pc
libwebp-dev: /usr/share/doc/libwebp-dev/AUTHORS
libwebp-dev: /usr/share/doc/libwebp-dev/NEWS.gz
libwebp-dev: /usr/share/doc/libwebp-dev/PATENTS
libwebp-dev: /usr/share/doc/libwebp-dev/README.gz
libwebp-dev: /usr/share/doc/libwebp-dev/changelog.Debian.gz
libwebp-dev: /usr/share/doc/libwebp-dev/copyright
libwebp5: /usr/lib/arm-linux-gnueabihf/libwebp.so.5
libwebp5: /usr/lib/arm-linux-gnueabihf/libwebp.so.5.0.4
libwebp5: /usr/share/doc/libwebp5/changelog.Debian.gz
libwebp5: /usr/share/doc/libwebp5/copyright
libwebpdemux1: /usr/lib/arm-linux-gnueabihf/libwebpdemux.so.1
libwebpdemux1: /usr/lib/arm-linux-gnueabihf/libwebpdemux.so.1.0.2
libwebpdemux1: /usr/share/doc/libwebpdemux1/changelog.Debian.gz
libwebpdemux1: /usr/share/doc/libwebpdemux1/copyright
libwebpmux1: /usr/lib/arm-linux-gnueabihf/libwebpmux.so.1
libwebpmux1: /usr/lib/arm-linux-gnueabihf/libwebpmux.so.1.0.2
libwebpmux1: /usr/share/doc/libwebpmux1/changelog.Debian.gz
libwebpmux1: /usr/share/doc/libwebpmux1/copyright
```

やっぱり、libwebp5がはいってますね、、PCの方では同じOS,openCV,numpyのバージョンでこれでうまくいってるんですが、、とにかく、libwebp.so.5があるので、適当にこれがあるディレクトリに、こいつをリンクづけたものを配置しましょう。コピーでもいいとは思います

```
>> cd /usr/lib/arm-linux-gnueabihf/
>> ln libwebp.so.5 libwebp.so.6
```

いや中身同じやのにこれでいいのかと思うんですが、openCV3.4以降ではこれらの画像処理系に依存していると書きましたが、どうやら3.3含めそれより前のバージョンでは依存してないみたいです。なので適当に中身の入っているファイルを指定されている名前で用意したら動きました。詳しくはわかりません、、なので、openCV3.3でいいよという方は、libwebp.so.6というファイルを適当につくりましょう。（とりあえず動けばいいんだよ！）

なお、openCV3.4以降ではしっかりlibwebp6に依存しているので、このやり方ではインポートの時点でエラーがでます。libwebp5とlibwebp6では関数やシンボルの名前がまず違うみたいですね、中身は確認してませんが

と、いうことでこれでopenCVがしっかりインポートできるはずです。お疲れ様でした


##いや、ちゃんとlibwebp6をインストールしたい！もしくはopenCV3.4以降をいれたい！という方
詳しくは全く調べてないので、適当に流し読みしてください。
私の使用しているラズパイでは、/etc/apt/sources.list.d に最低限の情報しか書いてないからか知りませんが、aptで入れることのできるパッケージにかなり制限がありました。ラズパイ特有なんですかねぇ、、なので、apt install　を実行した際に、E: Unable to locate package ... と出てしまう場合、このファイルに自分でパッケージのあるリポジトリの情報を打ち込んでやる必要があります。

apt-add-repositoryというコマンド、もしくは上記ファイルを直接編集することで、aptで自動的にそのリポジトリを参照してくれるようです。apt-add-repositoryコマンドを使うには、以下のパッケージをインストールしましょう。

```
sudo apt install software-properties-common
```


さて、このコマンドを使うべくlibwebpのリポジトリを見たのですが,
（https://launchpad.net/ubuntu/+source/libwebp）
バージョン６（libwebp6）はUbuntu18.04以降での名前みたいで、さらにそいつはarm32に対応してないようでした、なんでやねん！

ということで、libwebp6をインストールするのは諦めて試行錯誤した結果、適当にリンクをつけるというとても悲しい方法で解決しましたとさ、めでたしめでたし

ちゃんとしたやり方（ラズパイにlibwebp6をいれる）をご存知のかたは、是非この恥エンジニアにご教授くださいませ。