Android OpenCV 〜サンプルアプリを動かす〜

イントロダクション

アンドロイドでのOpenCVアプリを作成しようと考えています。
そんなわけで、下のサイトを参照してプログラムを動かしてみました。

以下の記述は参考サイトを実行して見た内容です。

AndroidでOpenCV

参考サイト: Android Pub

Step 1: Download OpenCV Android Library

ライブラリのダウンロード

  1. OpenCV + Androidのチュートリアルページを開きます。

  2. そして、OpenCV-android-sdkをダウンロードします。ZIPファイルをAndroid開発用のフォルダに展開します。

Step 2: Setup project

プロジェクトの作成

  1. Android Studioを開き、Emptyプロジェクトを作成する
    activity1

  2. プロジェクトの名前などを設定する

Step 3: Import OpenCV Module

OpenCVの取り込み

  1. 作成したプロジェクトを開いた状態で、File -> New -> Import Moduleを選択する

  2. プロジェクトの作成でダウンロード、展開した、ZIPファイルから「sdk/java」を指定する

  1. モジュールをインポートしたらビルドが始まるがエラーになる

Step 4: Fixing Gradle Sync Errors

build.gradleファイルを修正する


使用する実機がバージョン4.XだったのでminSdkVersion、targetSdkVersionを4に修正します。

Step 5: Add the OpenCV Dependency

OpenCVの依存性追加

  1. OpenCVライブラリの追加、ProjectStructure->Dependencies

Step 6: Add Native Libraries

ネイティブライブラリをコピーする

  1. OpenCVライブラリからAndroidプロジェクトのmainフォルダにペースト
  2. ペーストしたフォルダの名前を「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コマンド準備

  1. AndroidSDKのインストール場所を確認する
    • File -> androidOtherSettings -> DefaultProjectStructure...
      DefaultProjectStructure!
  2. ターミナルを立ち上げて、パスを通す
    • 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はサンプルコードにあるクラスで輪郭部分の描画を行なっているように見えます。

ちょっと自信がないので、「〜のように見えます」と記載しています。

輪郭部分を塗りつぶす

サンプルの実行では下の通りです。

あとは、コードを弄り確認することにします。

でわでわ。。。

次回 >>>

投稿者:

takunoji

音響、イベント会場設営業界からIT業界へ転身。現在はJava屋としてサラリーマンをやっている。自称ガテン系プログラマー(笑) Javaプログラミングを布教したい、ラスパイとJavaの相性が良いことに気が付く。 Spring framework, Struts, Seaser, Hibernate, Playframework, JavaEE6, JavaEE7などの現場経験あり。 SQL, VBA, PL/SQL, コマンドプロント, Shellなどもやります。

コメントを残す