Kinaconの技術ブログ

Ubuntuはじめました。

DockerのコンテナでOpenCV(C++)開発環境を構築する

f:id:m-oota-711:20180824075049j:plain

DockerのコンテナでOpenCV(C++)を実行する
dockerのコマンドに新コマンド体系ができたそうだ。

新コマンド体系は動作の内容がわかりやすいが、入力が面倒。
今回は新コマンドになれるために新コマンドで作業を行った。

参考:docker container / image コマンド新旧比較 - Qiita


Dockerの導入

導入方法は以下。
kinacon.hatenablog.com


sudoの省略

cat /etc/group #グループ一覧
sudo groupadd docker #dockerグループ一覧を追加
sudo gpasswd -a $USER docker #dockerグループにuserを追加
sudo service docker restart #dockerデーモンを再起動
exit #再ログイン

WARNINGが出る場合

WARNING: Error loading config file: /home/user/.docker/config.json: stat /home/user/.docker/config.json: permission denied

既にsudoで実行していると所有者rootで.dockerが作られているので所有者をuserに変更する。

sudo chown -R user ~/.docker

docker.sockのエラー

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.38/images/json: dial unix /var/run/docker.sock: connect: permission denied


以下のコマンドとPCの再起動で治った。(多分、再起動だけでいいかも)

sudo chgrp docker /var/run/docker.sock

Dockerのversion確認

docker version

コンテナ作成

ベースイメージをpullする

ベースイメージは16.04にしました。

docker image pull ubuntu:16.04

イメージの確認

docker image ls

コンテナ起動

docker container run -it ubuntu:16.04


コンテナ起動後(OSの確認)

cat /etc/os-release

C++開発環境を構築

GUIが使用できないためエディタはnanoを利用。

apt update
apt install build-essential cmake nano

※今回のaptのインストールパッケージは「インストールまとめ」にまとめてあります。

OpenCV導入(ソースからライブラリのビルド)

今回はソースからビルドします。



関連パッケージのインストール

ソース取得、展開用 ca-certificates unzip wget
ビルド用 pkg-config
GUI用 libgtk2.0-dev
画像の読み書き用 apt install libjpeg-dev libpng-dev
動画の読み書き用 ffmpeg libavcodec-dev libavformat-dev libavresample-dev libswscale-dev
Usbカメラ取り込み用 libv4l-dev
TBBによる並列化を有効化用 libtbb-dev


OpenCVのインストール

OpenCVのバージョンは3.4.3です。

以下リリースバージョン
Releases - OpenCV library

ビルド時のログをteeで保存しています。
※OPENCV_VERSIONを変更してバージョン変更できます。

OPENCV_VERSION="3.4.3"
mkdir -p /tmp/opencv && cd /tmp/opencv
wget https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip
unzip ${OPENCV_VERSION}.zip -d .
mkdir /tmp/opencv/opencv-${OPENCV_VERSION}/build && cd /tmp/opencv/opencv-${OPENCV_VERSION}/build/
cmake -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D WITH_FFMPEG=ON -D WITH_TBB=ON .. | tee /tmp/opencv_cmake.log
make -j "$(nproc)" | tee /tmp/opencv_build.log
make install | tee /tmp/opencv_install.log


OpenCVのバージョン確認

pkg-config --modversion opencv


ソースファイルを削除(コンテナを軽くする)

cd && rm -rf /tmp/opencv



コンテナを一旦exit(STOP)

exit



コンテナIDを確認してコンテナをcommit(イメージとして保存)

docker container ls -a 
docker container commit [コンテナID] [イメージ名](:[タグ])

チュートリアル実行

事前にチュートリアルはホスト環境で実行確認した。
kinacon.hatenablog.com



コンテナ(環境整備済み)から画像を表示できるようにGUIの設定する。
また、動作確認用プログラム(ソースとcmakelists)をコンテナ内のディレクトリにコピーする


コンテナ(環境整備済み)を起動

docker container run -it --rm \
-v /tmp/.X11-unix/:/tmp/.X11-unix \
-e DISPLAY=$DISPLAY \
[イメージ名](:[タグ])


一旦抜けて(ctl+p、ctl+q)コンテナのIDを確認

docker container ls -a



コンテナからXサーバへの通信を許可

xhost +local:`docker inspect --format='{{ .Config.Hostname }}' [コンテナID]`


コンテナにソースファイルとcmakeファイルをコピー

cd c++/cv_tutorial/
docker container cp CMakelists.txt [コンテナID]:/tmp/
docker container cp DisplayImage.cpp [コンテナID]:/tmp/


コンテナに入る

docker attach [コンテナID]


ビルドして実行

cd /tmp/
mkdir build
cd build
cmake ..
make
./Display ****.png


画像が表示できればOK。




インストールまとめ

※apt 使用時にコンテナ容量を減らす
--no-install-recommendsをつけてインストールする(必須パッケージのみインストール)
最後にapt clean でキャシュを削除

apt update
apt install --no-install-recommends -y build-essential cmake nano \
ca-certificates unzip wget \
pkg-config \
libgtk2.0-dev \
libjpeg-dev libpng-dev \
ffmpeg libavcodec-dev libavformat-dev libavresample-dev libswscale-dev \
libv4l-dev \
libtbb-dev
apt clean

proxy環境の場合

aptの設定

編集ファイル /etc/apt/apt.conf
追記内容
Acquire::http::proxy "http://id:pass@proxy_address:port/";
Acquire::https::proxy "https://id:pass@proxy_address:port/";
cat <<EOF >> /etc/apt/apt.conf
Acquire::http::proxy "http://id:pass@proxy_address:port/";
Acquire::https::proxy "https://id:pass@proxy_address:port/";
EOF

wgetの設定

編集ファイル /etc/wgetrc
追記内容
https_proxy = http://id:pass@proxy_address:port/
http_proxy = http://id:pass@proxy_address:port/
ftp_proxy = http://id:pass@proxy_address:port/
cat <<EOF >> /etc/wgetrc
https_proxy = http://id:pass@proxy_address:port/
http_proxy = http://id:pass@proxy_address:port/
ftp_proxy = http://id:pass@proxy_address:port/
EOF

DockerでGUIアプリケーションを実行するための設定

参考:Dockerコンテナの中でGUIアプリケーションを起動させる | Unskilled?

ドメインソケットの共有

-v /tmp/.X11-unix/:/tmp/.X11-unix

DISPLAY変数をコンテナのDISPLAY変数に入れる

-e DISPLAY=$DISPLAY

XサーバーにおけるXクライアントの許可

すべてのクライアントからの通信を許可

xhost + 


ローカルからの通信を許可

xhost local:


特定のコンテナ(コンテナのホスト名)だけ許可

xhost +local:`docker container inspect --format='{{ .Config.Hostname }}' [コンテナID]`

dockerコマンド

コンテナの一覧表示(稼働中のみ、停止中を含める場合は-aをつける)
docker container ls
ホストからコンテナにファイルをコピーする
docker container cp ソース [コンテナID]:格納先ディレクトリ
コンテナ実行にコンテナから抜ける(STATUS:UP)
ctl+p ctl+q
コンテナ実行にコンテナから抜ける(STATUS:Exited)
exit
実行中のコンテナ(STATUS:UP)に入る
docker container attach [コンテナID]
停止中のコンテナを起動する(STATUS:Exited → UP)
docker container start [コンテナID]
実行中のコンテナをストップする(STATUS:UP → Exited)
docker container stop [コンテナID]
停止中のコンテナを削除する
docker container rm [コンテナID]
停止中のすべてのコンテナを削除する
docker container prune
コンテナをイメージに保存する
docker container commit [コンテナID]
イメージの一覧表示
docker image ls
イメージの削除
docker image rm
使用していないイメージを一括削除
docker image prune

docker container run のオプション

イメージから新規コンテナを起動
docker container run [イメージ名](:[タグ])
オプション
-i ホストの入力をコンテナの標準入出力につなげる
-t tty(標準入出力となっている端末デバイス)を使う
-e 環境変数を渡す
--rm コンテナ終了時に自動で削除する
-v /ホストディレクトリ:/コンテナのディレクトリ ホストのディレクトリをコンテナのディレクトリにマウントする(共有する)

以上。