今回は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 の顔検出アプリを一から作ってみる