今回はOpenCV 2.3.1を使ってAndroidで画像認識をやってみます。

マーカーレス・トラッキングです。

こちらのサイトを参考にさせていただきました。

上記のサイトではLinux環境でサンプルをインポートしていますが、ここではサンプルを参考にして、Windows環境で新規にプロジェクトを作成してみましょう。

サンプルの直ダウンロードはこちら




目次

学習画像を変更

シンプルな学習画像を使ってみる




環境

Windows XP(SP3)
Eclipse 3.7.2
android-ndk-r8d
Cygwin 1.7.17
OpenCV-2.3.1-android



OpenCV 2.3.1をライブラリとして登録しておきます。
このページを参照。
アンドロイドでOpenCV(お顔検出)



段取り

1:Javaベースの新規プロジェクト作成

    パッケージ名にシングルバイトのアンダースコアは使わないほうがいいです。
    jni_part.cppでエラーの原因になる可能性があります。

    作成後プロジェクト名を右クリックしてPropertiesを選んで、Propertiesを開く

    Properties->Resource->Text file encodingをUTF-8

    Properties->Android->Library-> OpenCV 2.3.1

2:コード移植

    学習画像が準備されている場合は、5、6を先にやっておいたほうがいいかも。エラーが出るのを防げます。

    メインActivityにサンプルのDetectImageActivity.javaのコードを移植

    新たにPublic classとして、CameraPreview、InfomationViewを作って、サンプルから移植

3:jniプロジェクト追加

    プロジェクト名を右クリックして、New -> Otherを選択。

    C/C++の中の、「Convert to a C/C++ Project(Adds C/C++ Nature)」を選択。

    Convert to a C/C++ Projectのウィンドウが開いたら、

    Candidate for Conversionの自プロジェクトにチェックが入っているのを確認。

    Project option で「Makefile Project」と「CygwinGCC」を選んでFinish。

    プロジェクト名を右クリックして、New -> Folderを選択。プロジェクトにjniフォルダーを新規に追加

    サンプルを参考にjniフォルダーに、Android.mk、Application.mk、jni_part.cppファイルを作成

    【jni_part.cpp】を移植する場合

    com_example_detectimageの部分をプロジェクトのパッケージ名の並びで置き換えてください

    【Android.mk】はこんな感じ。

       LOCAL_PATH := $(call my-dir)
       include $(CLEAR_VARS)
       include E:\OpenCV-2.3.1\share\OpenCV\OpenCV.mk <--OpenCV-2.3.1-androidのOpenCV.mkのパスに変更
       LOCAL_MODULE := native_sample
       LOCAL_SRC_FILES := jni_part.cpp
       LOCAL_LDLIBS += -llog -ldl
       include $(BUILD_SHARED_LIBRARY)

    【Application.mk】に以下を追加、デフォルトではLevel14以下のプラットフォームが使えないための措置

       APP_PLATFORM := android-8



    Properties->C/C++ Buildを設定。

    Build command欄に、NDKのndk-build.cmdの場所をフルパスで設定。

    Build directoryが自プロジェクトになっているのを確認。

    Behaviourタブを選んで、2つのBuildにチェックを入れ、2つの欄を空白にして、cleanのチェックも外しておきます。

    Properties->C/C++ GeneralのPath and SymbolsでSource Locationに自プロジェクトのjniフォルダーをAddして、
    既存のものをDeleteしておきます。

    C/C++ GeneralのPath and SymbolsのIncludesで、NDKのincludeフォルダーをAddしておいてください。
       例:C:\android-ndk-r8d\platforms\android-8\arch-arm\usr\include

4:AndroidManifest.xmlに以下を追加

android:minSdkVersion="9"

----------------

android:screenOrientation="landscape"

----------------

<supports-screens android:resizeable="true"
                      android:smallScreens="true"
                      android:normalScreens="true"
                      android:largeScreens="true"
                      android:anyDensity="true" />

<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"/>


5:res/values/string.xmlに以下を追加

    これは、画像を認識した時表示する文字列。

   
<string name="no_crossing">No crossing by pedestrians</string>
<string name="closure">Closed to vehicular traffic</string>


6:サンプルのres/rawをコピー

    ここには学習画像が入っています。

7:デプロイ

    上記の設定の場合、プロジェクトをcleanする度にNDKのビルドが実行されます。

    このまま開発環境から実機にデプロイすると、以下のようなエラーが出てデプロイできないことがあります。

    Error generating final archive: Found duplicate file for APK: lib/armeabi-v7a/libnative_camera_r2.2.2.so
    Origin 1: E:\<プロジェクトのワークスペース>\libs\armeabi-v7a\libnative_camera_r2.2.2.so
    Origin 2: E:\android_opencv\OpenCV-2.3.1\libs\armeabi-v7a\libnative_camera_r2.2.2.so


    この場合、\libs\armeabi-v7a\libnative_camera_r2.2.2.so や\libs\armeabi-v7a\libnative_camera_r2.3.3.so を削除する
    必要がありますが、デプロイの場合Runさせた後にlibnative_camera_r2.2.2.soやlibnative_camera_r2.3.3.soが生成される
    ので事前に削除できません。

    そこで、一度ビルドが実行されたら、Properties->C/C++ Build->BehaviourのBuild(Increment build)のチェックを
    外しておきます

    その後、libnative_camera_r2.2.2.so と\libs\armeabi-v7a\libnative_camera_r2.3.3.soを削除します。

    (libnative_sample.soは残しておきます)

    これでRunしても再ビルドは実行されず、libnative_camera_r2.2.2.so と\libs\armeabi-v7a\libnative_camera_r2.3.3.so
    も生成されません。

    この設定は、Eclipse終了時は元に戻しておいてください。再起動時にプロジェクトに問題が発生する
    かもしれないので...。



    jni_part.cppでエラーが出てしまって消えない場合
    おそらくエラーではなく、Eclipseの勘違い?で出るようです。
    Eclipseを再起動してください。エラーがなくなる.....と思います。



認識対象の画像





こんな感じ。背景があっても認識されています。




サンプルアプリです。

インストール・実行は自己責任でお願いします。

インストール

Target:Android 2.3.3 or later

動作確認実機:Xperia acro(docomo) Android 2.3.4



アプリをQRコードからインストールする方法はコチラを参照


タブレットの場合

QRコードでダウンロードすると、Downloadフォルダー内でzipファイルになってインストールできない状態の場合があります。

その場合は、拡張子のzipをapkに変更してファイル名をタップすればインストール用のダイアログが出ますので、そこからインストールしてください。




学習画像を変更してみましょう。



少し認識率悪い感じですが、OKです(背景に重なっていても認識されます)。





画像の変更は、res/rawの学習画像を入れ替えるだけでいいようです。

リビルドする必要もないですし、サイズもサンプルでは100x100の正方形画像ですが、長方形でも問題ありませんでした。

jpgでもpngでもいいです。

どのくらいの画像が最適なのかは調査中。



学習画像を変更する場合

学習画像のセットは以下のところ。

【DetectImageActivity.java】

    private void init() {
      int[] ids = {R.raw.no_crossing, R.raw.closure};
         ・
         ・
         ・

    }

認識時に表示する文字列のセットは以下のところ。

【InfomationView.java】

    private int[] mExplanationIds = { R.string.no_crossing, R.string.closure };

コード内では、画像と文字列の読み込み順にID(0~)を振っています。

認識時の識別はこのIDを使っているようです。

画像名や説明文を変える場合は上記以外に、res/values/strings.xmlの該当箇所を変更する必要があります。

日本語表示も可能です。

表示の仕方は、【InfomationView.java】のonDraw()の中で設定されています。


画像名を変更したり、学習画像を追加したりした場合

NDKでリビルドして、libsのファイルを作り直す必要があります。

追加の場合は以下を変更します。

res/values/strings.xmlに追加

DetectImageActivity.javaのint[] widths、int[] heights、int[][] rgbasの要素数変更

setTrainingImagesの第4引数の値を変更

これらはjni_part.cppに渡されます。



Properties->C/C++ BuildのBehaviourタブ、Build(Incremental build)にチェックを入れて、プロジェクトをclean

これでリビルドが実行され、libsのファイルが更新されます。

再度、Properties->C/C++ BuildのBehaviourタブ、Build(Incremental build)にチェックを外し、
\libs\armeabi-v7a\libnative_camera_r2.2.2.so と\libs\armeabi-v7a\libnative_camera_r2.3.3.so を削除してデプロイ。



検出精度に関しては、あまり高いとは言えませんがチューニングしてみる場合は以下を参照。

C++のネイティブコードをコールしているのは、【DetectImageActivity.java】のsetTrainingImages()と【CameraPreview.java】のdetectImage()です。

jni_part.cppのコードでsimilarity変数や閾値を変えてみたり他の関数を追加したりして、試してもいいかも知れません。




シンプルな学習画像を使ってみる。

学習画像がシンプルな場合、結構おもしろい使い方ができます。

次のような学習画像を使ってみます。

ますめ(かごめ)とペンタグラムです。ドーマン、セーマンというやつです。



これはこれで認識されるのですが、以下のような手書きでも実は認識されます。



特徴点が単純なので、似たようなものも認識するようです。

これは「ユニーク」に認識するのではなく、似たものを片っ端から認識しても「可」という場合、使えるかもしれません。

こういうカーテンの図柄も「かごめ」として認識されました。








ソース

サンプルプロジェクト

OpenCV-2.3.1-android-bin.tar.bz2

Under construction






他のOpenCV関連ページ



OpenCV覚書

矩形領域の座標を取得するページ

OpenCV 2.3.1でカスケードを作って、Androidで使ってみる

アンドロイドでOpenCV(お顔の検出)

アンドロイドでOpenCV(色検出)

アンドロイドでOpenCV(特徴点検出)

AndroidでOpenCV 2.4.6を使ってみる

OpenCV + NyMMDで初音ミクさんにご挨拶してもらいます

Android OpenCV 2.4.6 の顔検出アプリを一から作ってみる