ドンピシャな情報が中々見つからない

基本的にはOpenCVのコードを落としてきてビルドする、そしてパスを通します、というような事が公式、非公式かかわらず説明されています。
実際その通りなのですが、どうもGradleやGroovy環境での利用方法に関する情報がかなり少ないようで、なかなかドンピシャな情報にたどり着けませんでした。
そこで、実際に自分が悩んだOpenCVをJava、Apache Groovy、Grails(Gradle)から利用する際のメモを残しておきます。

ビルド

色々利用したい機能などで変わってきますが、とりあえず以下が私がビルドした際の作業ログです。
なお、Ubuntu18.04のDockerイメージ上で実施しました。
vimを入れているのはcmakeのログを確認する際にvimを使いたかった為で、必須ではありません。


# 必要なライブラリのインストール
apt-get update
apt-get install vim cmake git libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavresample-dev ffmpeg curl wget unzip zip build-essential pkg-config zlib1g-dev libpng-dev python python-dev python-numpy libfreetype6-dev

# Java系プロダクトのインストール
cd $HOME
curl -s "https://get.sdkman.io" | bash
source "/root/.sdkman/bin/sdkman-init.sh"
sdk install java 8.0.202-zulu
sdk install ant
sdk install grails 3.3.8
※この時点でJAVA_HOMEを手動で設定しておくこと

# OpenCV Contributionの準備(バージョン3.4)
cd /usr/local/src/
git clone https://github.com/opencv/opencv_contrib.git
cd opencv_contrib
git checkout 3.4

# OpenCVの準備(バージョン3.4)
cd /usr/local/src/
git clone git://github.com/opencv/opencv.git
cd opencv
git checkout 3.4

# ビルド
cd /usr/local/src/opencv/
mkdir build
cd build
cmake -DBUILD_SHARED_LIBS=OFF -DWITH_FFMPEG=ON -DOPENCV_EXTRA_MODULES_PATH=/usr/local/src/opencv_contrib/modules /usr/local/src/opencv ..

make -j5

ビルドが完了すると、OpenCVをJavaから利用するためのjarファイルと、実際のOpenCVの機能が格納されている共有ライブラリ(.soファイル)が生成されます。

  • /usr/local/src/opencv/build/lib/opencv.so
  • /usr/local/src/opencv/build/bin/opencv.jar

実際にはファイル名には343のようなバージョンもつきます。

この2つのファイルをJava(Apache Groovy)で読み込むことで、OpenCVの機能を利用できるようになります。

jar

さて、まずはjarファイルです。
jarファイルなので特に難しいことのない、基本的な作業になります。
ただ、ローカルに有るOpenCVのjarファイルにパスを通しますー、という説明が何故か軒並みMavenばかりです。
ということでGradleで利用する場合について説明します。

基本

難しいことは何もなくて、単純にbuilde.gradledependenciesにOpenCVのjarファイルへのフルパス追記するだけです。

dependencies {
    compile files("/PATH/TO/opencv.jar")
}

環境ごとにjarのパスを切り替える

私の場合、Grailsでの利用が主ですので、当然デプロイ先と開発環境ではjarの設置場所が異なります。
ということで、以下のように別途Gradle用のconfigファイルを用意して、それをbuild.gradleから読み込んで利用するようにしています。

まず、build.gradleと同じ場所にdefault.config.gradleを作成し、以下のような内容を記述します。

ext {
    opencvjar="/PATH/TO/opencv.jar"
}

そして、build.gradleの中身を以下のようにします。(必要な部分のみ抜粋)

apply from:"default.config.gradle"
dependencies {
    compile files("$opencvjar")
}

これで、default.config.gradleをバージョン管理対象外にしておいて、各開発環境、ビルド環境で専用のものを用意しておけば各環境でjarのパスを切り替えることが出来ます。

共有ライブラリ

次に実際にOpenCVの機能が詰まった共有ライブラリです。

基本(Java)

ググればEclipseでササッとパスを通す、という情報が山ほど有りますが、IDEに任せっぱなしだとデプロイ出来ません。
OpenCV用と言えども、soファイルはタダの共有ライブラリなので、普通にコード上で設定することが出来ます。

// フルパスを指定して読み込
System.load("/PATH/TO/opencv.so")

// もしもopencv.soのパスがjava.library.pathに含まれているなら以下のようにも出来る。
System.loadLibrary("opencv.so")

Javaの場合、基本的にこれでOKです。

Apache Groovy

実はApache Groovyだとコレではエラーとなって実行できません。
どうもこの辺りの挙動がJavaとは違うようです。
なので、Apache Groovyでは以下のように別の方法で共有ライブラリを読み込んであげる必要が有ります。
以下はGrailsの起動時に読み込んでおく方法です。
普通のApache Groovyコードで利用する場合にも全く同じ要領で共有ライブラリを読み込んであげればOKです。

class BootStrap {

    def init = { servletContext ->
        // OpenCVのLinux用の共有ライブラリを読み込み。
        // 本当はjarファイル同様、以下のように実際のパスは設定ファイルに追い出しておいたほうが良い
        // String openCVLibrary = Holders.getGrailsApplication().config.getProperty('myapp.openCVLibrary')
        String openCVLibrary = "/PATH/TO/opencv.so"
        Runtime.getRuntime().load0(groovy.lang.GroovyClassLoader.class, openCVLibrary)
    }
    def destroy = {
    }
}

テスト

上記でApache Groovy/GrailsからすでにOpenCVが利用できるようになっているはずです。

Grailsの場合、以下のようなコードを書いて実行して、コンソールに配列のようなものがエラー無く表示されればビルドと設定が正常に完了しています。

import org.opencv.core.Mat

class IndexController {
    def index() {
        Mat mat = Mat.eye(3, 3, CvType.CV_8UC1)
        println (mat.dump())
        render "hoge"
    }
}

上記のアクションメソッドにアクセスすればコンソールに以下のような内容が表示されるはず。

[  1,   0,   0;
   0,   1,   0;
   0,   0,   1]

終わりに

現在プライベートプロジェクトでOpenCVとApache Groovyを使って色々実験しています。
正直な所、OpenCVの機能などに関する説明やサンプルは基本的にC、もしくはPythonで記述されているので、JavaやApache GroovyでOpenCVを利用するのはかなり苦労します。
私はWeb側でGrailsを使いたかったし、型も利用したかったのでApache Groovyを利用していますが、特に理由がないのであれば、Pythonでやってしまったほうが良いんじゃないかな。。。と思います。

SrpingでOpenCVを利用したい、という場合にも本記事の内容がほぼそのまま通用するんじゃないかな?と思います。