catalinaの備忘録

ソフトウェアやハードウェアの備忘録。後で逆引きできるように。

OpenCV4.0をソースコードからインストールする

想像以上に手間取りました。かたりぃなです。

OpenCVのバージョンだけなら大した問題ではなかったのですが、バージョンアップに追従してC++も新しいものにしていこうという動きがあるみたいです。 (実際OpenCV3の世代でCインターフェースはレガシーなものとして切り捨てられましたし。)

さらに4.0になってからはOpenCV自体をビルドするCMakeも要求バージョンが上がっていて、これもビルドしなおす必要があります。

CMakeもビルド自体は簡単なのですが、CMakeをビルドするためには新しいlibcが必要になっています。

新しいlibcが必要ということはgcc自体のアップデートが必要になるということです。

私がよく使うCentOSgccがかなり古いバージョンしか入っていないので、gccからビルドしなおす必要があるということです。

ついにこの時が来てしまったかといった感じですね。。。

というわけで、次の順にやっていきます。

  1. gcc8.1のビルドとインストール
  2. CMake3.13のビルドとインストール
  3. OpenCV4.0のビルドとインストール

なんか大変なことになってしまいましたが、gcc8までいくとC++20も多少は使えるようになるので、未来志向で前向きにいきたいと思います。

環境はいつものです

  • Windows10Pro
  • Docker for windows
  • centos7ベース

躓いたポイント

cmake/opencvとも、いつものようにビルドすればいいのですが一点だけ注意。

cmakeが参照するcurlhttps対応してない問題というのがあるらしいです。

https://stackoverflow.com/questions/51573524/cmake-is-unable-to-download-by-protocol-https-while-own-cmake-option-procedure

要約すると、opencvのビルド時に追加で必要なファイルをダウンロードしてきたりしているところで面倒な問題があるようです。

追加ライブラリののダウンロードにcurlが使われるのですが、cmakeはシステム組み込みのcurlではなくcmake自信が持っているcurlを使うようになっています。(デフォルトの動作)

これだけなら大したことないのですが、cmakeが持っているcurlと不随するライブラリが古いらしく、httpsサイトからのダウンロードに失敗します。(SSLの一部をサポートしていないため)

これがopencvのbuild時に発覚するので、ビルド時間の長さも相まって手戻りが半端なかったです。

環境構築のためのdockerfileはベタ書きしたので、他の環境でやるときも手順書の代わりになるかと思うので、次回以降はビルドやり直しの手間は減るかなと思います。

docker-file

まずは答えから。

インストールするものをまとめてコンテナ化するdockerfileになります。

ひたすらコマンドを実行するだけのものです。

RUN yum groupinstall -y 'Development tools'
RUN yum install -y git wget cmake
RUN yum install -y sudo

# cmakeのためにlibcとgccを入れる(C++最新を使いたい)
RUN wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-8.1.0/gcc-8.1.0.tar.gz
RUN tar zxvf gcc-8.1.0.tar.gz
RUN cd gcc-8.1.0; ./contrib/download_prerequisites; mkdir build
RUN cd gcc-8.1.0; ./configure --enable-languages=c,c++ --prefix=/usr/local --disable-bootstrap --disable-multilib; make;
RUN cd gcc-8.1.0; make install
RUN cp gcc-8.1.0/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.25 /usr/lib64/
# libcのバックアップとインストール
RUN mv /usr/lib64/libstdc++.so.6 /usr/lib64/libstdc++.so.6.backup
RUN ln -s /usr/lib64/libstdc++.so.6.0.25 /usr/lib64/libstdc++.so.6
RUN rm gcc-8.1.0.tar.gz

# opencv4のためにcmake 3.5以上が欲しい
RUN yum install -y git wget cmake
RUN yum install -y sudo curl-devel zlib-devel
RUN wget https://gitlab.kitware.com/cmake/cmake/-/archive/v3.13.4/cmake-v3.13.4.tar.gz
RUN tar zxvf cmake-v3.13.4.tar.gz
RUN cd cmake-v3.13.4; ./bootstrap --system-curl && make && make install
RUN mv /bin/cmake /bin/cmake.backup
RUN ln -s /usr/local/bin/cmake /bin/cmake
RUN rm cmake-v3.13.4.tar.gz

# c++ opencv
RUN git clone https://github.com/opencv/opencv.git /root/opencv; cd /root/opencv/; git checkout -b 4.0.0 4.0.0 ;
# contrib入れると大きすぎてdockerのデフォルト容量をオーバーして失敗することがあるので、一旦除外
#RUN git clone https://github.com/opencv/opencv_contrib.git /root/opencv_contrib; cd /root/opencv_contrib; git checkout -b 4.0.0 4.0.0 ;
#RUN mkdir /root/opencv/build; cd /root/opencv/build; cmake -D OPENCV_EXTRA_MODULES_PATH=/root/opencv_contrib/modules ..
RUN mkdir /root/opencv/build; cd /root/opencv/build; cmake ..
RUN cd /root/opencv/build; make; make install;

このdockerfileの注意点として、OpenCVのcontribはつけてません。

contribはやたら大きいので、手元の環境ではdocker desktop for windowsのコンテナサイズを超えてしまいました。 なので、一旦contribなしでいきました。

各パッケージのinstall後でファイルを削除しているのも同様の理由です。

動作確認

適当にコード書きます。

OpenCVのビルド情報を表示するだけのものです。

#include <iostream>

#include <opencv2/opencv.hpp>

int main(int argc, char*argv[])
{
    auto buildinfo = cv::getBuildInformation();
    std::cout << buildinfo;
    return 0;
}

ビルドします。ここでも注意点が1つ。

OpenCV4.0ではpkg-configのサポートを終わらせるかどうか議論しているようです。

(自分でビルドとインストールするならパスは分かっているので気にしなくていいのですが、cmake使わない人=パッケージマネージャな人?だとどうするんだとか)

https://github.com/opencv/opencv/issues/13154

どうやらcmakeのオプションにpkgconfig使うように指定すれば、pcファイル吐いてくれるので、それを使えばよさそうです。

今回は自分でビルドしてインストールパスもわかっているので、直接指定します。たとえばこんな感じで。

g++ test.cpp -I/usr/local/include/opencv4/ -L/usr/local/lib64/ -lopencv_core

動かしてみる

ここでもpkg-configがsoを探してくれないので、ちょっとばかり対応が必要です。

出来上がった実行ファイルをそのまま実行すると、soが見つからないっていわれます。

[root@ce33ad34d4ba src]# ./a.out
error while loading shared libraries: libopencv_core.so.4.0: cannot open shared object file: No such file or directory

新しいライブラリ入れるとよくある現象ですね。soを参照できているか見てみます。

[root@ce33ad34d4ba src]# ldd a.out
        linux-vdso.so.1 =>  (0x00007fffd5d80000)
        libopencv_core.so.4.0 => not found
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f51622b6000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f5161fb4000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f5161d9e000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f51619d1000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f5162639000)
[root@ce33ad34d4ba src]# ./a.out

確かにopencvがnot found.ですね。ここでもパスは分かっているので、環境変数を指定して実行します。

LD_LIBRARY_PATH環境変数opencv*.soの置かれているパスを入れて実行。

[root@ce33ad34d4ba src]# LD_LIBRARY_PATH=/usr/local/lib64/ ./a.out

General configuration for OpenCV 4.0.0 =====================================
  Version control:               4.0.0

(略)

やったね。

トラブルシューティング

libcのバージョンが古いときは、共有ライブラリの中を確認する必要があります。

strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX

これで該当するバージョンが入っているかどうか調べることができます。

gccとlibcのバージョンアップではこちらのサイトを参考にさせていただきました。

https://www.saintsouth.net/blog/update-libstdcpp-on-centos6/

感想と今後の展望

サーバ側のOpenCVは最新にすることができました。これでOpenCVのONNIXが利用できるようになります。

ONNNIXはDeepLearningの各種フレームワーク間でデータを受け渡せるようにするフォーマットで、今後はサーバ側はC++/OpenCVだけでいけるかもしれません。

とはいえサーバ側をすべてC++で書くのは骨が折れるので、PythonバインディングOpenCV叩いたほうが早い気がしなくもないです。

あとはC++が最新版になったので、いろいろと使いたい機能が使えるようになりました。

C++も20になって関数型言語っぽい香りが本格的になってきたので、時間をとっていろいろ試したいと思います。

それでは今回はこれくらいで。