LoginSignup
5
4

More than 3 years have passed since last update.

AndroidアプリにOpenCVを導入してみる

Posted at

はじめに

AndroidStudioのデフォルトだけで完結するアプリ作りにも飽きてきたので、
OpenCVを使って画像をあーだこーだしてアプリの幅を広げてみる。
手始めにインストールして試しに使ってみる。

Androidアプリで端末の画像を取り込むの続き

環境

OpenCV 4.1.2
AndroidStudio 3.4.1

インストール

こちらの記事を参考にさせていただきました。
特に支障なくインストールとインポートは完了。

Android StudioでOpenCVを使う

Mat形式で取り込む

前回の記事でデバイスの画像データをbitmapで取り込むところまでやりました。
このbitmapをOpenCVで扱うためのMat形式に変換します。

OpenCVのLibraryに含まれているandroid.packageのUtilsクラスに以下のメソッドが用意されています。
これを使ってbitmapをMatに変換する。
Mat形式に画像を変換することでOpenCVのLibraryを用いて画像を色々と編集することができるようになります。

Utils.java
/**
 * Short form of the bitmapToMat(bmp, mat, unPremultiplyAlpha=false).
 * @param bmp is a valid input Bitmap object of the type 'ARGB_8888' or 'RGB_565'.
 * @param mat is a valid output Mat object, it will be reallocated if needed, so Mat may be empty.
 */
public static void bitmapToMat(Bitmap bmp, Mat mat) {
    bitmapToMat(bmp, mat, false);
}
Main.java
//bmp_img:取り込んだbitmap
//mat_img:あらかじめMat形式の変数を用意しておく
Utils.bitmapToMat(bmp_img,mat_img); 

Matを使ってみる

今回は試しにボタンを押したらカラー画像をグレースケールに変換するアプリを作って見ます。
どのメソッドを使うかというと、公式ドキュメントから地道に探します。
Open Source Computer Vision

それかOpenCVをインストールした状態でプロジェクト全体を[gray]とかで検索するとそれっぽいのが引っかかります。

今回はImageprocクラスの中に以下のようなメソッドが用意されていました。

Imageproc.java
public static void cvtColor(Mat src, Mat dst, int code) {
    cvtColor_1(src.nativeObj, dst.nativeObj, code);
}

codeの引数には、どのような変換を行うのかの定数を入れてあげます。
imageproc.hppのファイルに変換方法一覧があるのでそちらを参照。
今回はカラー画像からグレースケールに変換したいのでCOLOR_RGB2GRAYを利用する。

Main.java
Utils.bitmapToMat(bmp_img,mat_img); //bmp_img:取り込んだbitmap,mat_img:Mat形式の変数を用意しておく
Mat mat_output = new Mat();
cvtColor(mat_img,mat_output,COLOR_RGB2GRAY);

これでmat_imgの画像がグレースケールに変換されmat_outputに入れられるはず。
最後にこのmat_outputを再度bitmapに変換し、ImageViewに出力する。

Main.java
private Mat mat_output = new Mat();

public void onClick(View v) {
    Utils.bitmapToMat(bmp_img,mat_img); //BitmapからMatへ変換
    cvtColor(mat_img,mat_output,COLOR_RGB2GRAY);    //GrayScaleへ変換
    Utils.matToBitmap(mat_output,bmp_img);  //Bitmapに戻す
    img_picture.setImageBitmap(bmp_img);    //ImageViewへ表示
}

クラッシュ発生!

これで完成!と思いきや、ボタンを押した瞬間にクラッシュ発生。
デバッグしてみると、そもそもMatをnewしているところでクラッシュが発生している。

エラーメッセージを見てみると...
java.lang.UnsatisfiedLinkError: No implementation found for long org.opencv.core.Mat.n_Mat() (tried Java_org_opencv_core_Mat_n_1Mat and Java_org_opencv_core_Mat_n_1Mat__)

Mat()が見つかりません、みたいなことが書いてあります。
困ったときのStackoverflowを見てみたら同じ境遇の人が見つかりました。
No implementation found for long org.opencv.core.Mat.n_Mat() error Using OpenCV

記事の内容をまとめると

  • OpenCVのLibraryを読み込む前にOnCreate()が呼ばれてしまっている
  • OpenCVManagerとやらを使って非同期でOpenCVを初期化する
  • OnCreate()前にBaseLoaderCallbackを実行し、この中でMat()のインスタンスを宣言してあげる
  • OnResume()で毎回OpenCVが導入されているかをチェックする

さらに少し調べてわかったことは

  • このOpenCVManagerはユーザーごとに別途インストールしてもらう。
  • Libraryをアプリに含めないことによりアプリの容量が小さくなるとのこと。
  • OpenCVManagerを起動するためにOpenCVLoader.initAsyncを実行する
  • Initが完了したタイミングでBaseLoaderCallbackが呼ばれるので、その中でMatの生成を行う

やってみた

とりあえずStackOverflowに書いてあったソースコードをそのまま流用しました。
デバッグしてみたところ、

  1. OnResume()内でmLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS)が呼ばれる
  2. onManagerConnected内でMatのインスタンスが生成される

という流れが確認できました。

てっきりアプリ起動時にOpenCVManagerのインストールを要求されるかと思ったら何もありませんでした。
またOnResume()内のOpenCVLoader.initAsyncも呼ばれなかった。(初回起動時見逃した...?)
AndroidやOpenCVのバージョンにもよるかもしれないです。

結果

できました!
写真は台湾のかき氷屋さんの「IceMonstar」のキャラクター?です。
マンゴーかき氷がすごい美味しかったので台湾行った際はぜひ。
gray.png

最後に

環境構築に少しだけ手間取りましたが、一応OpenCVが扱えるようになりました。
公式ドキュメントを見たところ膨大なライブラリが用意されているようなので、これから色々触っていきたいと思います。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4