イントロダクション
アンドロイドでのOpenCVアプリを作成しようと考えています。
そんなわけで、下のサイトを参照してプログラムを動かしてみました。
以下の記述は参考サイトを実行して見た内容です。
AndroidでOpenCV
参考サイト: Android Pub
Step 1: Download OpenCV Android Library
ライブラリのダウンロード
-
OpenCV + Androidのチュートリアルページを開きます。
-
そして、OpenCV-android-sdkをダウンロードします。ZIPファイルをAndroid開発用のフォルダに展開します。
Step 2: Setup project
プロジェクトの作成
-
Android Studioを開き、Emptyプロジェクトを作成する
-
プロジェクトの名前などを設定する
Step 3: Import OpenCV Module
OpenCVの取り込み
-
作成したプロジェクトを開いた状態で、File -> New -> Import Moduleを選択する
-
プロジェクトの作成でダウンロード、展開した、ZIPファイルから「sdk/java」を指定する
- モジュールをインポートしたらビルドが始まるがエラーになる
Step 4: Fixing Gradle Sync Errors
build.gradleファイルを修正する
使用する実機がバージョン4.XだったのでminSdkVersion、targetSdkVersionを4に修正します。
Step 5: Add the OpenCV Dependency
OpenCVの依存性追加
- OpenCVライブラリの追加、ProjectStructure->Dependencies
Step 6: Add Native Libraries
ネイティブライブラリをコピーする
- OpenCVライブラリからAndroidプロジェクトのmainフォルダにペースト
- ペーストしたフォルダの名前を「jniLibs」に修正
Step 7: Add Required Permissions
AndroidManifest.xmlの修正
作成するプロジェクトのappフォルダにあるAndroidManifest.xmlに以下のコードを追記する
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
最終的に下のようなファイルになる
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.zenryokuservice.androidopencv">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
</manifest>
adbコマンド準備
- AndroidSDKのインストール場所を確認する
- File -> androidOtherSettings -> DefaultProjectStructure...
- File -> androidOtherSettings -> DefaultProjectStructure...
- ターミナルを立ち上げて、パスを通す
- viコマンドで「.bash_profile」を開く
- sdk/platform-toolsを追加する
サンプルソースを読む
起動している、コードは参考サイトにあるコード(MainActivity.java)です。
アンドロイドアプリの実装では、準備処理と起動時の処理でメソッドが分かれているので、主要な部分を見ます。
public boolean onTouch(View v, MotionEvent event) {
int cols = mRgba.cols();
int rows = mRgba.rows();
int xOffset = (mOpenCvCameraView.getWidth() - cols) / 2;
int yOffset = (mOpenCvCameraView.getHeight() - rows) / 2;
int x = (int)event.getX() - xOffset;
int y = (int)event.getY() - yOffset;
Log.i(TAG, "Touch image coordinates: (" + x + ", " + y + ")");
if ((x < 0) || (y < 0) || (x > cols) || (y > rows)) return false;
Rect touchedRect = new Rect();
touchedRect.x = (x>4) ? x-4 : 0;
touchedRect.y = (y>4) ? y-4 : 0;
touchedRect.width = (x+4 < cols) ? x + 4 - touchedRect.x : cols - touchedRect.x;
touchedRect.height = (y+4 < rows) ? y + 4 - touchedRect.y : rows - touchedRect.y;
Mat touchedRegionRgba = mRgba.submat(touchedRect);
Mat touchedRegionHsv = new Mat();
Imgproc.cvtColor(touchedRegionRgba, touchedRegionHsv, Imgproc.COLOR_RGB2HSV_FULL);
// Calculate average color of touched region
mBlobColorHsv = Core.sumElems(touchedRegionHsv);
int pointCount = touchedRect.width*touchedRect.height;
for (int i = 0; i < mBlobColorHsv.val.length; i++)
mBlobColorHsv.val[i] /= pointCount;
mBlobColorRgba = converScalarHsv2Rgba(mBlobColorHsv);
Log.i(TAG, "Touched rgba color: (" + mBlobColorRgba.val[0] + ", " + mBlobColorRgba.val[1] +
", " + mBlobColorRgba.val[2] + ", " + mBlobColorRgba.val[3] + ")");
mDetector.setHsvColor(mBlobColorHsv);
Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR);
mIsColorSelected = true;
touchedRegionRgba.release();
touchedRegionHsv.release();
return false; // don't need subsequent touch events
}
このコードで注目したいのは、「赤い線をつけている部分」です。
結論、下の部分で画面に表示している情報を更新しているように思います。
<MainActivity.java>
// Calculate average color of touched region
mBlobColorHsv = Core.sumElems(touchedRegionHsv);
int pointCount = touchedRect.width * touchedRect.height;
for (int i = 0; i < mBlobColorHsv.val.length; i++)
mBlobColorHsv.val[i] /= pointCount;
mBlobColorRgba = converScalarHsv2Rgba(mBlobColorHsv);
Log.i(TAG, "Touched rgba color: (" + mBlobColorRgba.val[0] + ", " + mBlobColorRgba.val[1] +
", " + mBlobColorRgba.val[2] + ", " + mBlobColorRgba.val[3] + ")");
mDetector.setHsvColor(mBlobColorHsv);
Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR);
動かして見たところ、上記のメソッドで画面をタッチしたときの色を取得しているようです。
そして、その色の輪郭部分を描画している。。。ように見えます。
その部分が以下のコードです。
<MainActivity.java>
if (mIsColorSelected) {
mDetector.process(mRgba);
List<MatOfPoint> contours = mDetector.getContours();
Log.e(TAG, "Contours count: " + contours.size());
Imgproc.drawContours(mRgba, contours, -1, CONTOUR_COLOR);
Mat colorLabel = mRgba.submat(4, 68, 4, 68);
colorLabel.setTo(mBlobColorRgba);
Mat spectrumLabel = mRgba.submat(4, 4 + mSpectrum.rows(), 70, 70 + mSpectrum.cols());
mSpectrum.copyTo(spectrumLabel);
}
mDetectorはサンプルコードにあるクラスで輪郭部分の描画を行なっているように見えます。
ちょっと自信がないので、「〜のように見えます」と記載しています。
輪郭部分を塗りつぶす
サンプルの実行では下の通りです。
あとは、コードを弄り確認することにします。
でわでわ。。。