はじめに
「Jetson NanoのDockerでOpenCV 4.1.0をコンパイルする」ではDockerを使ってOpenCV 4.1.0を無事コンパイルすることができた。しかしこのままではDockerを抜けた環境で使うことはできない。そこで、このコンパイルしたバイナリをどうしたらDockerを抜けた環境で、もっとも簡単に利用できるか考えてみる。
結論はgithubに反映した。
https://github.com/yamamo-to/jetson_nano/tree/master/opencv4_compile
ターゲット言語はPython
C/C++からは単にリンクすれば利用できるので、これからメインで使うであろうPythonから呼び出すことを考える。すなわち
import cv2
print(cv2.__version__)
で4.1.0が返ってくるような、最も簡単な方法を探ろうという試みである。
ディスク容量
コンパイル時に必要なディスク容量
コンパイル環境はDockerイメージだけで1GBある。
docyamamo-to@jetson-nano:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
opencv4_build latest 9710cbd87862 21 hours ago 1.01GB
ubuntu 18.04 9f020c638543 4 weeks ago 63.3MB
さらにソースコードとビルド後のサイズ含めると追加で6.7GBである。
yamamo-to@jetson-nano:~/Documents/jetson_nano/opencv4_compile/home$ du -s -h build
6.7G build
つまり、コンパイルには最低約8GB必要である。
実行時に必要なディスク容量
一方で実行環境と言えば
yamamo-to@jetson-nano:~/Documents/jetson_nano/opencv4_compile/home$ du -s -h dist/
199M dist/
たったの約200MBである。これからやりたいことは、この200MBだけをDockerの環境から持ち出して、普通の環境でOpenCV 4.1.0を使えるようにしたい、ということである。
Pythonモジュールの仕組み
例えばPythonで書かれたソースコードと同じディレクトリにhoge
のようなディレクトリがあり、その中に空のファイル__init__.py
が存在するとimport hoge
を行うことができる。同じディレクトリでなくともサーチパス(sys.pathで見られる)が通っていれば探してくれる。
yamamo-to@jetson-nano:~$ python3
Python 3.6.8 (default, Jan 14 2019, 11:02:34)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/yamamo-to/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages', '/usr/lib/python3.6/dist-packages']
>>>
OpenCVのモジュール名
Docker内でインストールされたパスがどこにあるのかを確認する。
foo@e6ba62eb25b4:~$ python3
Python 3.6.8 (default, Jan 14 2019, 11:02:34)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__file__
'/usr/local/lib/python3.6/dist-packages/cv2/python-3.6/cv2.cpython-36m-aarch64-linux-gnu.so'
>>>
この結果から/usr/local/lib/python3.6/dist-packages
がサーチパスに含まれていれば良いことが分かる。
またJetPack4.2のOpenCVをPythonから呼び出すためにインストールするpython3-opencv
は次の通りである。
yamamo-to@jetson-nano:~$ apt-file -F show python3-opencv
python3-opencv: /usr/lib/python3/dist-packages/cv2.cpython-36m-aarch64-linux-gnu.so
python3-opencv: /usr/share/doc/python3-opencv/changelog.Debian.gz
python3-opencv: /usr/share/doc/python3-opencv/copyright
ファイル名cv2.cpython-36m-aarch64-linux-gnu.so
は全く同じでディレクトリが/usr/local/libか/usr/libの違いだけである。サーチパスの優先順位の高いところにOpenCV 4.1.0のモジュールが呼ばれるように配置すれば良さそうだ。
サーチパスの追加
/usr/local以下を/opt/opencv-4.1.0にコピーした上で、PYTHONPATHにパスを通して呼び出せるか試してみる。
yamamo-to@jetson-nano:~/Documents/jetson_nano/opencv4_compile$ sudo cp -a home/dist/usr/local /opt/opencv-4.1.0
export PYTHONPATH=/opt/opencv-4.1.0/lib/python3.6/dist-packages:$PYTHONPATH
実行すると
$ pipenv run python3
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/opencv-4.1.0/lib/python3.6/dist-packages/cv2/__init__.py", line 89, in <module>
bootstrap()
File "/opt/opencv-4.1.0/lib/python3.6/dist-packages/cv2/__init__.py", line 79, in bootstrap
import cv2
ImportError: libopencv_hdf.so.4.1: cannot open shared object file: No such file or directory
>>>
libopencv_hdf.so.4.1
が見つからないというエラーがでた。このファイル自身は/opt/opencv-4.1.0/lib/libopencv_hdf.so.4.1
にあるので、これはLD_LIBRARY_PATHを通せば良い。
export LD_LIBRARY_PATH=/opt/opencv-4.1.0/lib:$LD_LIBRARY_PATH
では改めて。
$ pipenv run python3
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__
'4.1.0'
>>>
呼び出すことに成功した!それならば最初からインストール先が/usr/localではなく/opt/opencv-4.1.0となるようにCMAKE_INSTALL_PREFIX
を変更すれば良さそうだ。
依存ライブラリ
opencvが呼び出せることと、呼び出したプログラムが正常に動くことは別である。依存ライブラリがない場合、それを必要としたライブラリが読み込まれた時点でエラーとなる。少なくとも今回/opt/opencv-4.1.0で作成したパッケージを使うためには、下記のライブラリ群がインストールされていることが必要である。
sudo apt install cuda-cublas-10-0 cuda-cufft-10-0 cuda-npp-10-0 libavcodec57 libavformat57 libdc1394-22 libglib2.0-dev libgstreamer-plugins-base1.0-0 libgtk2.0-0 libhdf5-100 libjpeg-turbo8 libswscale4
SquashFS
存在を忘れつつあったSquashFSでディレクトリごと圧縮してファイル一つにする。
mksquashfs /opt/opencv-4.1.0 $HOME/opencv-4.1.0.sfs -b 1048576 -comp xz -Xdict-size 100%
ファイルサイズは
yamamo-to@jetson-nano:~/Documents/jetson_nano/opencv4_compile$ ls -lh home/opencv-4.1.0.sfs
-rw-r--r-- 1 yamamo-to yamamo-to 29M 6月 18 07:10 home/opencv-4.1.0.sfs
29MBになった。これを/opt/opencv-4.1.0にマウントすれば使えるようになる。
まとめ
Dockerでコンパイルして作成されたディレクトリを圧縮した29MBのファイルopencv-4.1.0.sfs
を持ち出して/opt/opencv-4.1.0
にマウントする。
sudo mkdir /opt/opencv-4.1.0
sudo mount -o loop opencv-4.1.0.sfs /opt/opencv-4.1.0
次に環境変数PYTHONPATH
とLD_LIBRARY_PATH
を設定する。
export PYTHONPATH=/opt/opencv-4.1.0/lib/python3.6/dist-packages:$PYTHONPATH
export LD_LIBRARY_PATH=/opt/opencv-4.1.0/lib:$LD_LIBRARY_PATH
aptで関連ライブラリをインストールする。
sudo apt install libatlas3-base libhdf5-100
これでOpenCV 4.1.0が動作するようになる。