2018年12月24日月曜日

Origamiを利用してOpenCVをビルドせずにClojureで使う方法


この記事は Clojure Advent Calendar 2018 24日目の記事です。

背景

OpenCVとは画像処理に関する便利な機能を提供してくれるプログラムのライブラリです。
ClojureとはJavaの実行環境で動く関数型プログラミング言語です。

過去の記事でOpenCVをビルドし、Clojureを実行する時に利用するleiningenやclojureコマンドでビルドしたファイルを読み込んで動かしました。

ClojureのcljプロジェクトでOpenCVを使う方法
clojureでopencv3.2を呼び出し、javax.swingで画像を表示する方法

上記の方法ではOpenCVのビルドが必要なため、プログラムを動かすまでに時間がかかります、
ClojureでもビルドしないでOpenCVを使う方法が無いかと思っていたら、OrigamiというOpenCVをClojureで使いやすくするライブラリがあることを教えてもらいました。
また、メールにてOrigamiの作者の方から直々に使い方を教えてもらったりしたことにより、OpenCVをビルドせずにClojureのleiningen環境とclojureコマンド環境で動かすことに成功しました。

便利だと思うので方法を共有します。

使ったもの

cljコマンドかLeiningenがインストールされたPC

動作確認に利用したバージョンはこちらです。
$ clj
Clojure 1.9.0
$ lein --version
Leiningen 2.8.1 on Java 1.8.0_191 OpenJDK 64-Bit Server VM

インストール方法はそれぞれのページで紹介されています。
Clojure Getting Started
Leiningen

Origami

背景で言及したとおり、OpenCVをclojureで使いやすくしてくれるライブラリです。
Origamiを利用することで、ビルドせずにOpneCVを利用できます。

https://github.com/hellonico/origami

この記事ではOrigamiの設定方法とOpenCVの読み込み方を説明しますが、Origamiのapiの使い方は説明しません。
Origamoのapiの使い方が気になる方は、上記のリポジトリや下記のコマンドで生成されるサンプルコードなどをご覧ください。
lein new clj-opencv [プロジェクト名]

cljプロジェクトでOpenCVを利用

OrigamiのREADMEで紹介されているように、deps.ednに参照先のリポジトリと合わせてOrigamiを依存先に設定することでOpenCVを利用できる状態になります。
deps.edn
{:mvn/repos
 {"vendredi" {:url "https://repository.hellonico.info/repository/hellonico/"}}
 :deps 
 {origami {:mvn/version "4.0.0-1"}}}

上記の設定でreplを起動すれば、Origamiが使えます。
(require '[opencv4.core :as origami])

OpenCVをimportしてNativeLoaderを呼び出せば、素のOpenCVを利用できます。
(import '[org.opencv.core Core])
(org.scijava.nativelib.NativeLoader/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME nil)

下記のようなコマンドで、OpenCVのバージョンを表示したり、webカメラがPCに付いていれば画像を取得しての大きさを表示したりできます。
(import '[org.opencv.core Core Mat]
        '[org.opencv.videoio VideoCapture])
(prn :opencv-info Core/VERSION Core/NATIVE_LIBRARY_NAME)
(org.scijava.nativelib.NativeLoader/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME nil)
(def mat-frame (new Mat))
(def cv-camera (new VideoCapture 0))
(.read cv-camera mat-frame)
(prn :camera-image-size (.cols mat-frame) (.rows mat-frame))


leinプロジェクトででOpenCVを利用

project.cljにOrigamiに関するリポジトリと依存ライブラリを設定すれば、OrigamiとOpenCVを使える状態になります。
project.clj
  :repositories [["vendredi" "https://repository.hellonico.info/repository/hellonico/"]]
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [origami "4.0.0-1"]]

上記の設定でreplを起動すれば、Origamiが使えます。
(require '[opencv4.core :as origami])

leinプロジェクトでOpenCVだけを使う場合は2通りの方法があります。
1つはソースファイルやreplでNativeLoaderを呼び出す方法です。
(import '[org.opencv.core Core])
(org.scijava.nativelib.NativeLoader/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME nil)

もう1つはproject.cljでinjectionとしてNativeLoaderを設定しておく方法です。
ソースコードやreplでの呼び忘れや記述量を減らせるので、個人的にこちらの方が好みです。
project.clj
  :injections [(org.scijava.nativelib.NativeLoader/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME nil)] org.opencv.core.Core/NATIVE_LIBRARY_NAME nil)

cljプロジェクトと同様に、下記のようなコマンドでOpenCVのバージョンやカメラ画像のピクセル数を表示できます。
(import '[org.opencv.core Core Mat]
        '[org.opencv.videoio VideoCapture])
(prn :opencv-info Core/VERSION Core/NATIVE_LIBRARY_NAME)
(def mat-frame (new Mat))
(def cv-camera (new VideoCapture 0))
(.read cv-camera mat-frame)
(prn :camera-image-size (.cols mat-frame) (.rows mat-frame))



仕組みについて

Origamiの作者であるhellonicoさんが管理しているopencv-nativeにビルド済みのファイルが含まれていて、それをNativeLoaderで読み込んでいるようでした。

Origamiのproject.cljを見ると、org.scijava/native-lib-loaderとopencv-nativeが依存するライブラリとして設定されています。


NativeLoaderはorigamiのコードでOpenCVの読み込みに利用されています。


opencv-nativeをダウンロードしたあとで下記のコマンドを実行すると、opencv-nativeには、Mac Cindows LinuxとARMの64bit向けのシステムファイルが含まれていることが分かります。
jar -tf ~/.m2/repository/opencv/opencv-native/4.0.0-0/opencv-native-4.0.0-0.jar

上記コマンドの実行結果
META-INF/
META-INF/MANIFEST.MF
natives/linux_32/
natives/linux_64/
natives/linux_64/libopencv_java400.so
natives/linux_arm/
natives/linux_arm64/
natives/linux_arm64/libopencv_java400.so
natives/osx_64/
natives/osx_64/libopencv_java400.dylib
natives/windows_32/
natives/windows_64/
natives/windows_64/opencv_java400.dll


opencv-nativeにはWindows, Mac, Linux, Linux on Arm向けの64ビットのビルド済みファイルがありました。
それらの環境で動かすClojureのプロジェクトであれば、Origamiを通してOpenCVを利用できそうです。

ちなみに、Raspberry PiのJavaは32bitシステムとして動いているようで、Origamiを通してOpenCVを使うことはできませんでした。(Raspberry Pi 3B+で確認しました。)


まとめ

OpenCVをビルドせずにClojureで使うことができました。
便利なライブラリがあって、ありがたいことです。

何かの参考になれば嬉しいです。

0 件のコメント :