OpenCVのサンプル face-detection をAndroid Studioでビルド、実行する

OpenCVのサンプル face-detection をAndroid Studioでビルド、実行する

1. はじめに

Android Studio 1.4では、NDKをサポートしているようなので、練習として、OpenCV for Android OpenCV > PLATFORMS > ANDROID のサンプル face-detection をAndroid Studioでビルド、実行します。

2. OpenCV for Android SDKのインストール

OpenCV > DOWNLOADS より、OpenCV for Android をダウンロードします。記事執筆時の最新バージョンは、3.1です。zipファイルを適当なディレクトリに展開します。

$ cd ~/src
$ unzip OpenCV-3.1.0-android-sdk.zip

3. face-detectionのAndroid Studioへのインポート

OpenCV-android-sdk/samplesにあるface-detectionをAndroid Studioにインポートします。Android StudioのQuick StartのImport project (Eclipse ADT, Gradle, etc.)を使って、Select Eclipse or Gradle Project to importで、face-detectionを選択して、OKをします。

3. build.gradleの修正

サンプル face-detectionをAndroid Studioにインポートすると、次のようなエラーが出ます。

Failed to sync Gradle project 'face-detection'
Error:Cause: failed to find target with hash string 'android-14' in: /Users/osabe/src/android-sdk-macosx openAndroidSdkManager"

このエラーは、build.gradleで、compileSdkVersionが14に指定されているが、Android SDKのパッケージリポジトリにandroid-14がないのが原因です。また、本サンプルでは、android.hardware.camera2 の機能を使用していますが、これは、API level 21から利用可能です( android.hardware.camera2 )。そこで、build.gradleで、compileSdkVersion、minSdkVersionの値を修正します。

修正箇所
- openCVLibrary310の下のbuild.gradleファイル

    compileSdkVersion 14
    buildToolsVersion "23.0.2"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 21
    }

    compileSdkVersion 21
    buildToolsVersion "23.0.2"

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 21
    }

に修正。
– openCVSamplefacedetectionの下のbuild.gradleファイル

    compileSdkVersion 14
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "org.opencv.samples.facedetect"
        minSdkVersion 8
        targetSdkVersion 8

        ndk {
            moduleName "detection_based_tracker"
        }
    }

    compileSdkVersion 21
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "org.opencv.samples.facedetect"
        minSdkVersion 21
        targetSdkVersion 21

        ndk {
            moduleName "detection_based_tracker"
        }
    }

に修正。

4. gradle.propetiesファイルの作成

Gradle projectをsyncすると、次のようなエラーが発生する。

Error:(12, 0) Error: NDK integration is deprecated in the current plugin.  Consider trying the new experimental plugin.  For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

Top / OS関係 / Android / AndroidStudio /AndroidStudio によると、トップディレクトリに、次の内容のファイル gradle.propertiesを作成するといい。

android.useDeprecatedNdk=true

ファイルを作成して、プロジェクトをsyncする。

5. local.propertiesファイルの修正

4で、gradle.propertiesファイルを作成し、プロジェクトをsyncすると、次のエラーが発生する。

Error:Execution failed for task ':openCVSamplefacedetection:compileDebugNdk'.
> NDK not configured.
  Download the NDK from http://developer.android.com/tools/sdk/ndk/.Then add ndk.dir=path/to/ndk in local.properties.
  (On Windows, make sure you escape backslashes, e.g. C:\\ndk rather than C:\ndk)

トップディレクトリのlocal.propertiesファイルに、

ndk.dir=<android ndkの絶対パス>

を記述する。その後、プロジェクトをClean Project、Rebuild Projectする。

6. ビルド失敗に対する対策(openCVSamplefacedetectionのbuild.gradleを編集)

プロジェクトをRebuildすると、次のエラーが発生する。

Error:(2, 33) opencv2/core/core.hpp: No such file or directory

AndroidStudioでOpenCVのサンプルを動かす によると、このエラーは、Android Studioでのビルドで、Android.mkの設定が反映されないのが原因。ビルド時に、ndk-buildを実行するタスクを追加する。次のように、openCVSamplefacedetectionのbuild.gradleのandroidブロック内で、

    sourceSets.main.jni.srcDirs = []

    task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
        def ndkDir = "/Users/foo/src/android-ndk-r10e"
        commandLine "$ndkDir/ndk-build",
                '-C', file('src/main/jni').absolutePath,
                '-j', Runtime.runtime.availableProcessors(),
                'all'
    }

    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn buildNative
    }

を追加する。ファイル修正後、再度、Rebuild。

7. Rebuild失敗に対する対策

6で、openCVSamplefacedetectionのbukld.gradleの修正後、プロジェクトをRebuildすると、次のエラーが発生する。

Error:(15) ../../sdk/native/jni/OpenCV.mk: No such file or directory

AndroidStudioでOpenCVのサンプルを動かす によると、OpenCVのsdkを、プロジェクトから認識できないのが原因で、openCVSamplefacedetection/src/main/jniにあるAndroid.mkファイルを次のように修正する。

  include ../../sdk/native/jni/OpenCV.mk

   include <OpenCV sdkの絶対パス>/sdk/native/jni/OpenCV.mk

に修正する。修正後、Rebuild。face-detection/openCVSamplefacedetection/src/main/libs/armeabi-v7aディレクトリに、libdetection_based_tracker.so ファイルが生成されれば、ビルドが成功する。

8. アプリ実行

アプリをRunすると、次のようなエラーが発生する。

03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect D/AndroidRuntime: Shutting down VM
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime: FATAL EXCEPTION: main
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime: Process: org.opencv.samples.facedetect, PID: 21512
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/org.opencv.samples.facedetect-2/base.apk"],nativeLibraryDirectories=[/data/app/org.opencv.samples.facedetect-2/lib/arm64, /vendor/lib64, /system/lib64]]] couldn't find "libdetection_based_tracker.so"
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at java.lang.Runtime.loadLibrary(Runtime.java:367)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at java.lang.System.loadLibrary(System.java:1076)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at org.opencv.samples.facedetect.FdActivity$1.onManagerConnected(FdActivity.java:67)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at org.opencv.android.AsyncServiceHelper$3.onServiceConnected(AsyncServiceHelper.java:319)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1223)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1240)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at android.os.Handler.handleCallback(Handler.java:739)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:95)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:148)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5417)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
03-29 11:12:54.312 21512-21512/org.opencv.samples.facedetect E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
03-29 11:12:54.319 21512-21512/org.opencv.samples.facedetect I/Process: Sending signal. PID: 21512 SIG: 9

face-detection/openCVSamplefacedetection/build/outputs/apkディレクトリに生成したapkファイルをunzipで展開すると、ダイナミックファイルが含まれていないのが、エラーの原因( AndroidStudioでOpenCVのサンプルを動かす ) 。そこで、シンボリックをはる。

$ cd face-detection/openCVSamplefacedetection/src/main
$ ln -s libs jniLibs

9. OpenCV Managerのインストール

アプリを再度、Runする。今度は、OpenCV Managerがインストールされていないので、インストールしろというメッセージが出る。そこで、OpenCV Mangerをインストールする。

10. アプリを再度、実行

アプリが動作するようになる。ただし、Nexus 6Pでは、logcatに次のエラーを出して、アプリが実行できない。

03-29 11:23:24.338 23120-23120/? E/AndroidRuntime: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/org.opencv.samples.facedetect-1/base.apk"],nativeLibraryDirectories=[/data/app/org.opencv.samples.facedetect-1/lib/arm64, /vendor/lib64, /system/lib64]]] couldn't find "libdetection_based_tracker.so"

NDK r10 b 32 bit or 64 bit or compile using both and how to achieve it によると、原因は、Android Studioが生成するjniのダイナミックライブラリが32bitの物に対して、Nexus 6PのCPUがarm 64bitであるため。そこで、face-detection/openCVSamplefacedetection/src/main/jni ディレクトリにある Application.mk ファイルを次のように修正する。

APP_ABI := armeabi-v7a arm64-v8a

修正後、プロジェクトをBuild Clean、Rebuild。再度、アプリ実行する。正常実行される。

11. 参考サイト
OpenCV > PLATFORMS > ANDROID
OpenCV > DOWNLOADS
android.hardware.camera2
NDK r10 b 32 bit or 64 bit or compile using both and how to achieve it
AndroidStudioでOpenCVのサンプルを動かす