Android Studioで、OpenCV (C++)を使う必要があったので、まとめてみました。
Android開発は、始めたばかりなので、間違っているところがありましたら、教えて頂けるとありがたいです。
試した環境は、以下の通り。
- Android Studio 1.4
- OSX 10.11
- OpenCV 3.0.0 (for Android)
※ OpenCV for Androidは、以下のフォルダにインストールされているものとす。
/Users/<name>/Library/Android/OpenCV-3.0.0-android-sdk/
まず、OpenCVを使用するアプリケーションの作成
新規プロジェクトを作成する場合
「New Project...」で「My Application」という名前の「Blank Activity」を作成したとする。
「Import Module...」で以下のフォルダをインポートする。
/Users/<name>/Library/Android/OpenCV-3.0.0-android-sdk/sdk/java/
「openCVLibrary300」という名前でライブラリがインポートされる。
settings.gradle にopenCVの依存関係が追加される。
include ':app'
include ':openCVLibrary300' // <--- 追加される
/app/build.gradleを以下のように修正
...
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.android.support:design:23.1.0'
compile project(':openCVLibrary300') // <--- 追加する
}
OpenCVのSDKに付属のサンプルを試す場合
SDKに付属のサンプルは、以下の場所にある。
/Users/<name>/Library/Android/OpenCV-3.0.0-android-sdk/samples/
サンプルを開く場合、Android Studioの「Open...」で直接開かずに、「Import Project...」で開きたいサンプルのフォルダを選択し、インポート先をユーザフォルダの下などの別フォルダにする。
そうすると、同じフォルダにOpenCVのライブラリをインポートした状態のプロジェクトが作成される。
OpenCVのライブラリのロードをどうする?
OpenCVは、C/C++で書かれたライブラリである。Android向けには、JavaからOpenCVを使用するためのJava Wrapperも提供されている。Java Wrapperを使用する場合でも、アプリが起動するためには、C/C++の共有ライブラリ(libopencv_java3.so)をロードする必要がある。
OpenCVの共有ライブラリをロードする方法として、以下の二つがある。
A: OpenCV Managerを使用する
- OpenCVの共有ライブラリを含まないため、配布するアプリのサイズは小さくなる。
- ただし、ユーザ環境にOpenCV Managerがインストールされている必要がある。
- アプリケーションの起動時に、OpenCV Managerがインストールされていない環境では、OpenCV Managerのダウンロード/インストールを要求される。
- OpenCV Managerは、必ずしも最新バージョンのOpenCVに対応していない。
B: 共有ライブラリをアプリケーションパッケージ(.apk)に含める
- 共有ライブラリを含む分、配布するアプリのサイズは大きくなる。
- OpenCV Managerは不要。
- 最新バージョンのOpenCVが使用できる。
OpenCV Managerを使用する方法
ActivityクラスのonResumeで、OpenCVLoader.initDebug()を使って、OpenCV Managerを呼び出す。
詳細は、"/OpenCV-3.0.0-android-sdk/samples/image-manipulations/"などを参照。
public class ImageManipulationsActivity extends Activity implements CvCameraViewListener2 {
@Override
public void onResume()
{
super.onResume();
if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else {
Log.d(TAG, "OpenCV library found inside package. Using it!");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
共有ライブラリを.apkに含める方法
プロジェクトの"app/src/main"の下の"jniLibs"フォルダを作成。
"/OpenCV-3.0.0-android-sdk/sdk/native/libs/"の下のディレクトリを"jniLibs"の下にコピー。
コピー先の各フォルダの"libopencv_java3.so"を残して、".a"ファイルは削除する。
main/
src/
jniLibs/
arm64-v8a/
libopencv_java3.so
armeabi/
libopencv_java3.so
armeabi-v7a/
libopencv_java3.so
mips/
libopencv_java3.so
mips64/
libopencv_java3.so
x86/
libopencv_java3.so
x86_64/
libopencv_java3.so
プロジェクトのActivityクラスを以下のように修正。
OpenCVのサンプル、"image-manipulations"の例。
public class ImageManipulationsActivity extends Activity implements CvCameraViewListener2 {
/* --- 追加 (共有ライブラリをロードする) --- */
static {
System.loadLibrary("opencv_java3");
}
@Override
public void onResume()
{
super.onResume();
/* --- OpenCV Managerの呼び出しをコメントアウト --- */
/* if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else */ {
Log.d(TAG, "OpenCV library found inside package. Using it!");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
NDKを使用して、C/C++からOpenCVを使用する
OpenCV Managerを使っても出来そうですが、調べていません。ここでは、共有ライブラリを.apk内に含めることとします。
上記の「共有ライブラリを.apkに含める方法」のところまでは同じ。
OpenCVのサンプル、"face-detection"を使用して説明する。
./gradle/wrapper/gradle-wrapper.prpertiesを修正
#Sun Oct 11 14:07:25 JST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
# 修正前
#distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
# 修正後
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
Gradle-Wrapperに、他にどのバージョンが存在するかは、以下で確認可能
https://services.gradle.org/distributions
(2015.10.11現在、2.5しかダメ)
Gradle wrapperを使用するように変更
"preferences" > "Build, Execution, Deployment" > "Gradle" を開く。
"Project-level settings"を"Use local gradle distribution"から"Use default gradle wrapper (recommended)"に変更する。
./build.gradleを修正
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
// classpath 'com.android.tools.build:gradle:1.3.0' // 修正前
classpath 'com.android.tools.build:gradle-experimental:0.2.0' // 修正後
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
他にどういうバージョンがあるかは、以下で確認可能
https://jcenter.bintray.com/com/android/tools/build/gradle-experimental/
./app/build.gradleを修正
apply plugin: 'com.android.application'
android {
compileSdkVersion 14
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "org.opencv.samples.facedetect"
minSdkVersion 8
targetSdkVersion 8
ndk {
moduleName "detection_based_tracker"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile project(':openCVLibrary300')
}
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 14
buildToolsVersion = "23.0.1"
defaultConfig.with {
applicationId = "org.opencv.samples.facedetect"
minSdkVersion.apiLevel = 8
targetSdkVersion.apiLevel = 8
versionCode = 1
versionName = "1.0"
}
}
android.buildTypes {
debug {
ndk.with {
debuggable = true
}
}
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.pro')
}
}
compileOptions.with {
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
android.ndk {
moduleName = "detection_based_tracker"
cppFlags += "-Werror"
cppFlags += "--debug"
cppFlags += "-frtti"
cppFlags += "-fexceptions"
cppFlags += "-I${file('/Users/<name>/Library/Android/OpenCV-3.0.0-android-sdk/sdk/native/jni/include')}".toString()
cppFlags += "-I${file('src/main/jni')}".toString()
ldLibs += ["android", "log", "stdc++", "dl", "z"]
stl = "gnustl_static"
}
android.productFlavors {
create("arm") {
ndk.with {
abiFilters += "armeabi"
File curDir = file('./')
curDir = file(curDir.absolutePath)
ldLibs += curDir.absolutePath + "/src/main/jniLibs/" + "armeabi" + "/libopencv_java3.so"
}
}
create("arm7") {
ndk.with {
abiFilters += "armeabi-v7a"
File curDir = file('./')
curDir = file(curDir.absolutePath)
ldLibs += curDir.absolutePath + "/src/main/jniLibs/" + "armeabi-v7a" + "/libopencv_java3.so"
}
}
create("arm8") {
ndk.with {
abiFilters += "arm64-v8a"
File curDir = file('./')
curDir = file(curDir.absolutePath)
ldLibs += curDir.absolutePath + "/src/main/jniLibs/" + "arm64-v8a" + "/libopencv_java3.so"
}
}
create("x86") {
ndk.with {
abiFilters += "x86"
File curDir = file('./')
curDir = file(curDir.absolutePath)
ldLibs += curDir.absolutePath + "/src/main/jniLibs/" + "x86" + "/libopencv_java3.so"
}
}
create("x86-64") {
ndk.with {
abiFilters += "x86_64"
File curDir = file('./')
curDir = file(curDir.absolutePath)
ldLibs += curDir.absolutePath + "/src/main/jniLibs/" + "x86-64" + "/libopencv_java3.so"
}
}
create("mips") {
ndk.with {
abiFilters += "mips"
File curDir = file('./')
curDir = file(curDir.absolutePath)
ldLibs += curDir.absolutePath + "/src/main/jniLibs/" + "mips" + "/libopencv_java3.so"
}
}
create("mips-64") {
ndk.with {
abiFilters += "mips64"
File curDir = file('./')
curDir = file(curDir.absolutePath)
ldLibs += curDir.absolutePath + "/src/main/jniLibs/" + "mips64" + "/libopencv_java3.so"
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':openCVLibrary300')
}
./openCVLibrary300/build.gradleを修正
apply plugin: 'com.android.library'
android {
compileSdkVersion 14
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 8
targetSdkVersion 8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
apply plugin: 'com.android.model.library'
model {
android {
compileSdkVersion = 14
buildToolsVersion = "23.0.1"
defaultConfig.with {
minSdkVersion.apiLevel = 8
targetSdkVersion.apiLevel = 8
}
}
android.buildTypes {
debug {
ndk.with {
debuggable = true
}
}
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.pro')
}
}
compileOptions.with {
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
}
C/C++コードのDebug
- プロジェクトのC/C++のコードに、ブレークポイントを設定する。
- ツールバーの"Select Run/Debug Configuration"をドロップダウン。
- "<アプリケーション名>-native"を選択。
- 無ければ、"Edit Configurations..."を選択。
- 開いた画面(Run/Debug Configurations)の左上の[+]ボタンで、"Android Native"を追加する。
- ⇒ 選択肢に"<アプリケーション名>-native"が追加される。
- "Run"または"Debug"で、アプリケーションを実行。
- ⇒ ブレークポイントで停止する。
おしまい