#はじめに
Docker上でOpenCV等のビジョン系ライブラリを使用する時は、DockerコンテナとローカルPCのディスプレイを接続する必要がありますが、この方法が分からず結構な時間を要してしまいましたので、途中で遭遇したトラブルとその解決策を含めてまとめていきたいと思います!
#開発環境
Ubuntuです!詳細は下記コマンドでチェックしておきます!
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.3 LTS"
$ arch
x86_64
#Dockerイメージのダウンロード
まずはDocker HubからDockerイメージをダウンロードします。Docker Hubで公開されているDockerイメージは、自由にダウンロード、保存することができます。
$ docker pull ubuntu:18.04
#Dockerコンテナのデプロイ
保存済みのDockerイメージを用いて、Dockerコンテナを立ち上げます。Dockerコンテナをデプロイする際、様々なオプションがあります[1][2]。
今回使用するオプションは、-it
、--privileged
、--env
、--volume
、--name
です。
まず-it
により、Dockerコンテナに対して擬似端末(pseudo terminal)を割り当てることで、Dockerコンテナ上でBashを使用できるようにします。
続いて--privileged
により、全てのデバイスに対するアクセスを許可します。
--env
では、Dockerコンテナ内で使用する環境変数を指定します。
--volume
では、ホストOSのディレクトリをゲストOSにマウントすることができます[3]。
--name
ではコンテナ名を指定することができます。
$ docker run -it \
--privileged \
--env="DISPLAY=$DISPLAY" \
--volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
--volume="$HOME/ws/:/home/" \
--name="ubuntu_cv2" \
ubuntu:18.04
#パッケージのインストール
まずはUbuntuお決まりのアップデート、アップグレードです。
# apt-get update
# apt-get upgrade
続いて、エディタとしてVimをインストールしておきます。
# apt-get install vim
プログラミング言語にはPythonを使用します。
# apt-get install python3.6 \
python3-dev \
python3-pip \
libffi-dev \
libssl-dev
pipを使用してOpenCVをインストールします。
# pip3 install opencv-python
#画像表示プログラムを作成
OpenCVを使用して画像を表示する基本的なプログラムを作成しておきます。
import cv2
# Load an color image
img = cv2.imread('test.jpg')
# Show the image
cv2.imshow('image',img)
# Stop when 0 pressed
cv2.waitKey(0)
cv2.destroyAllWindows()
#トラブル1:OpenCVを正しくインポートできない
まずPythonを実行して、OpenCVが正しくインポートできるかテストしてみます。
# python3
>>> import cv2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/dist-packages/cv2/__init__.py", line 3, in <module>
from .cv2 import *
ImportError: libSM.so.6: cannot open shared object file: No such file or directory
案の定、エラーによりOpenCVをインポートできません。このエラーは、libsm6
、libxext6
、libxrender-dev
のインストール[4]により解決できます。
# apt-get install -y libsm6 libxext6 libxrender-dev
インストール後、もう一度OpenCVをインポートできるかテストしてみます。
# python3
>>> import cv2
OKですね!
#トラブル2:画像を表示できない
先程作成したopen_image.py
を実行してみましょう。
# python3 open_image.py
No protocol specified
: cannot connect to X server :1
PCとのディスプレイ接続に失敗しているようです。ホストPC側で、ゲストPCからのホストPCディスプレイへの接続要求を拒否していることが理由でした。別のターミナルを開けて、ホストPC側で下記コマンドを実行すると、ディスプレイへの接続を許可[5][6][7]することができます。
$ xhost +
access control disabled, clients can connect from any host
再度Dockerコンテナを実行していたターミナルに戻り、open_image.py
を実行してみましょう。
# python3 open_image.py
X Error: BadAccess (attempt to access private resource denied) 10
Extension: 130 (MIT-SHM)
Minor opcode: 1 (X_ShmAttach)
Resource id: 0x247
...
別のエラーが出てきました。エラー原因を調査したところ、環境変数にQT_X11_NO_MITSHM=1
を追加することで解決できるそうです。まずは.bashrc
ファイルをVimで開きます。
# vim ~/.bashrc
続いて、環境変数QT_X11_NO_MITSHM=1
を追記します。
export QT_X11_NO_MITSHM=1
.bashrc
ファイルを保存した後、環境変数の追加を反映させるため、source
コマンド[8]を実行します。
# source ~/.bashrc
echo
コマンドを使用して、環境変数が正しく追加されているか確認してみましょう。
# echo $QT_X11_NO_MITSHM
1
OKですね!三度目の正直です。open_image.py
を実行してみましょう!
# python3 open_image.py
画像が表示されました!!!
#おわりに
様々なトラブルがありましたが、無事にDockerコンテナとPCディスプレイを接続して、OpenCVにより画像を表示させることができました。今回の検証より、Dockerコンテナをデプロイする際には、下記のように環境変数QT_X11_NO_MITSHM=1
を追加しておくと良いことも分かりました。
$ docker run -it \
--privileged \
--env="DISPLAY=$DISPLAY" \
--env="QT_X11_NO_MITSHM=1" \
--volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
--volume="$HOME/ws/:/home/" \
--name="ubuntu_cv2" \
ubuntu:18.04
これからDockerマスターを目指して頑張っていこうと思います!
読んで頂いた方々、ありがとうございます!!!
#参考文献
[1] Docker run options, https://docs.docker.com/v17.12/edge/engine/reference/commandline/run/
[2] Example of docker run, https://qiita.com/tnarihi/items/275c009e9dec1306893f
[3] How to mount on docker, https://docs.docker.com/v17.09/engine/admin/volumes/bind-mounts/
[4] How to solve opencv import error, https://github.com/NVIDIA/nvidia-docker/issues/864
[5] Open X server, https://unix.stackexchange.com/questions/121716/unable-to-open-x-server
[6] Allowing computers access, https://www.stitson.com/pub/book_html/node72.html
[7] About xhost, https://wiki.archlinux.jp/index.php/Xhost
[8] Source command, https://bash.cyberciti.biz/guide/Source_command