そこで、今回はOpenCVと呼ばれるライブラリを用いてお手軽に画像処理をしてみます(といっても、OpenCVを用いるのは私も今回が初めてなのですが)。
準備として、前回の前半に書いてあるように、SimpleMjpegViewがandroid上で動作するようにしておいてください。前回の続きでも良いですし、新規に始めても構いません。新規の場合は図のように映像が表示されます。
OpenCVのインストール
まずはeclipseがインストールされたマシンにandroid用のOpenCVをインストールします。こちらからopencv-android→(最新の数字)とたどり、OpenCV-x.x.x-android-sdk.zipをダウンロードします。私が試したときの最新版はOpenCV-2.4.7.1-android-sdk.zipでした。解凍して現れるファイルを、例えばeclipseのワークスペースにコピーします。次に、OpenCVのフォルダに含まれるsdk/javaフォルダをeclipseにインポートします。通常通り、「ファイル→インポート→既存プロジェクトをワークスペースへ」で行います。
次に、SimpleMjpegViewからOpenCVを参照する設定を行います。eclipse上のプロジェクトエクスプローラー上でSimpleMjpegViewを右クリック→プロパティーとたどり、項目の中のandroidをクリックすると、下半分にライブラリーという項目があるので、追加ボタンをクリックして、OpenCVライブラリを追加します。
最後に、アプリをインストールするandroid端末に、Google PlayからOpenCV Managerをインストールしておきます。
以上の準備が済んだら、ファイルの編集を行います。
ファイルの編集
まず、初期化処理のためにSimpleMjpegViewのsrcフォルダ以下にあるMjpegActivity.javaを編集します。冒頭のimport文に、下記の 3項目を追加します。import org.opencv.android.OpenCVLoader; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.LoaderCallbackInterface;次に、MjpegViewのインスタンスmvの宣言の直後に下記の初期化処理を記述します(※ソース更新に合わせて、若干の変更 2013.1.30/2013.4.29)。
private MjpegView mv = null; String URL; // mv と URL の宣言の直後に下記を記述 private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { Log.i(TAG, "OpenCV loaded successfully"); setContentView(R.layout.main); mv = (MjpegView) findViewById(R.id.mv); if(mv != null){ mv.setResolution(width, height); } new DoRead().execute(URL); } break; default: { super.onManagerConnected(status); } break; } } };そして、同じファイル内で、MjpegViewをnewしている部分をみつけ、下記のようにコメントアウトした上で初期化処理の追記を行います(※ソース更新に合わせて、若干の変更 2013.1.30/2013.4.29)。
// 下記の6行を見つけてコメントアウトし、代わりに下記を追記 // setContentView(R.layout.main); // mv = (MjpegView) findViewById(R.id.mv); // if(mv != null){ // mv.setResolution(width, height); // } // new DoRead().execute(URL); if (!OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mOpenCVCallBack)) { Log.e(TAG, "Cannot connect to OpenCV Manager"); }次に、画像処理の本体を記述します。SimpleMjpegViewのsrcフォルダ以下にあるMjpegView.javaを編集します。まず冒頭のimport文の中に、下記の四項目を追加します。
import org.opencv.android.Utils; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.imgproc.Imgproc;次に、同じくMjpegView.java内で下記のように readMjpegViewを呼び出している部分を見つけます。前回の続きとして実行する場合は、imageprocessing関数が記述されていると思いますが、その場合はその行をコメントアウトしてください。
そしてその後ろに5行のOpenCV命令を記述します。これは画像のグレースケール化を行う処理なのですが、詳細は末尾に記すTechBoosterさんのサイトを参考にしてください。
if(bmp==null){ bmp = Bitmap.createBitmap(IMG_WIDTH, IMG_HEIGHT, Bitmap.Config.ARGB_8888); } int ret = mIn.readMjpegFrame(bmp); if(ret == -1) { ((MjpegActivity)saved_context).setImageError(); return; } // 前回の続きとして実行している場合は下記1行をコメントアウトしておく //imageprocessing(bmp); //OpenCVによる画像処理 Mat bmp_mat = new Mat(IMG_HEIGHT, IMG_WIDTH, CvType.CV_8UC4); Utils.bitmapToMat(bmp, bmp_mat); Imgproc.cvtColor(bmp_mat, bmp_mat, Imgproc.COLOR_RGB2GRAY); Imgproc.cvtColor(bmp_mat, bmp_mat, Imgproc.COLOR_GRAY2RGBA, 4); Utils.matToBitmap(bmp_mat, bmp);以上の記述ができたらandroidにアプリをインストールします。
成功すると、図のようにグレースケール画像が得られます。
このように、OpenCVを用いると少ない記述量で様々な処理を行うことができます。OpenCVが流行っている理由がわかる気がします。
計算時間の比較
前回の「(JNIによる)ピクセル直接編集」と今回のOpenCVの計算にかかる時間はどの程度か調べてみます。対象は今回取り扱ったグレースケール処理の部分のみで、かかった計算時間を100回以上平均をとって計測しました。結果は以下の通りです。
端末 | ピクセル直接編集 | OpenCV |
Galaxy S3 cm10-based JCROM | 7.7ms | 14.8ms (*) |
Xperia Arc cm10-based JCROM | 13ms | 23ms |
みてわかるように、2つの端末の両方でピクセル直接編集の方が高速であることがわかりました。といっても、私はOpenCVを今回初めて使ったので、もっとOpenCVを効率的に用いる方法があるのかもしれませんが。なお、参考までに、表中で (*) のついた 14.8ms について、OpenCVで用いた5行の画像処理命令の内訳を記すと下記のようになります。
Mat bmp_mat = new Mat(IMG_HEIGHT, IMG_WIDTH, CvType.CV_8UC4); | 0.2ms |
Utils.bitmapToMat(bmp, bmp_mat); | 3.1ms |
Imgproc.cvtColor(bmp_mat, bmp_mat, Imgproc.COLOR_RGB2GRAY); | 6.5ms |
Imgproc.cvtColor(bmp_mat, bmp_mat, Imgproc.COLOR_GRAY2RGBA, 4); | 4.4ms |
Utils.matToBitmap(bmp_mat, bmp); | 0.6ms |
RGB2GRAYがグレースケール化の実体だと思いますが、その前後のbitmapToMatとGRAY2RGBAに地味に時間がかかるのが痛いように思います。
おしまい
- @kassy_kzさんらによる同人誌「Tech-orz 2012 Summer」
- TechBooster: OpenCVを使ってみよう(2.画像をグレースケール変換する)
こちらもどうぞ
- AndroidでWifiカメラからのMJPEGストリームを表示する
- AndroidでWifiカメラから受け取った動画を画像処理する(1)ピクセルを直接操作する方法
- AndroidでWifiカメラから受け取った動画を画像処理する(2)OpenCVを用いる方法
0 件のコメント:
コメントを投稿