This article was written on 2018-03-28,may have been out of date ,just for reference.
Android调用OpenCV的Android SDK进行计算机视觉相关的开发,可以调用JAVA层的函数,也可以直接调用JNI层的方法。前者需要在手机上另外安装Android Opencv Manager,并且apk体积也会增大,所以不推荐,后者可以只编译出需要用到的函数的.so库,apk只需要引用这个.so库,所以apk体积不会太大。所以推荐使用opencv的native方法进行jni编程并编译.so库。
本机环境
Win10_x64
Android Studio 3.1
OpenCV3.4.1
准备工作
下载opencv3.4.1
相关配置
最开始,先配置添加外部工具,因为JNI编程需要经常用到,每次cd到目录然后手打javah等命令是一件很没有效率的事情,在文件->设置->工具->外部工具中点击+号新建External Tools
我们需要添加3个工具
Name:
javah(SDK23)
Program:
JDKPath\bin\javah.exe
Arguments:
-d ModuleFileDir\src\main\jni -classpath D:\ProgramData\Android\SDK\platforms\android-23\android.jar;. FileClass
Working directory:
ModuleFileDir\src\main\java
Name:
ndk-build(module)
Program:
D:\ProgramData\Android\SDK\ndk-bundle\build\ndk-build.cmd
Working directory:
ProjectFileDir\ModuleName\src\main
Name:
ndk-build clean(module)
在ndk-build(module)基础上增加一个clean参数即可
Program:
D:\ProgramData\Android\SDK\ndk-bundle\build\ndk-build.cmd
Arguments:
clean
Working directory:
ProjectFileDir\ModuleName\src\main
以后只要在mudule目录中右键然后找到External Tools,点击即可使用这些命令。
一个示例
为了便于扩展,我们创建一个新的module,你可以取名为opencv3,我自己原先取的ImageProcLib举例就不改了。
首先在工程中创建ImageProcLib module,里面包含一个工具类ImageProcUtils,这样,我们在app module中的Activity中就可以调用ImageProcLib module中的工具类中的本地方法。
ImageProcUtils示例:
package cn.gloud.imageproclib;
import android.graphics.Bitmap;
import android.util.Log;
public class ImageProcUtils {
private static final String TAG = "ImageProcUtils";
static {
//导入生成的链接库文件
System.loadLibrary("ImageProcUtils");
}
public boolean ImageMatchTempl(int x, int y, Bitmap imageBitmap, Bitmap templBitmap, int threshold) {
return ImageMatchTemplate(x,y,imageBitmap,templBitmap,threshold);
}
//本地方法,模板匹配
private native boolean ImageMatchTemplate(int x, int y, Bitmap imageBitmap, Bitmap templBitmap, int threshold);
}
在module的 src\main下创建一个文件夹命名为jni
因为我们不需要java层函数,所以只复制...\OpenCV-android-sdk\sdk下的native文件夹到刚才创建的jni目录下即可
配置build.gradle,下面是module的build.gradle文件的模板
apply plugin: 'com.android.library'
android {
...
defaultConfig {
...
//配置NDK信息
ndk {
moduleName "ImageProcUtils"
ldLibs "log", "jnigraphics", "m", "z"
abiFilters "armeabi-v7a","x86" //,"x86"等架构
}
//配置SO文件存放路径
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs = ['src/main/libs']
}
}
}
//设置构建脚本路径,会自动索引同目录下的Application.mk
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
//如果报错More than one file was found with OS independent path时添加
packagingOptions {
pickFirst 'lib/armeabi-v7a/libImageProcUtils.so'
}
...
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:23.4.0'
...
}
利用javah命令编译ImageProcUtils的头文件于jni目录下,例如cn_gloud_imageproclib_ImageProcUtils.h,如果你配置好了外部工具,只需要右键ImageProcUtils,在External Tools中点击javah工具即可,
复制cn_gloud_imageproclib_ImageProcUtils.h到同目录下修改后缀名为.cpp,例如cn_gloud_imageproclib_ImageProcUtils.cpp
.cpp需要进一步修改,示例:
#include
#include
#include
#include
#ifndef LOG
#define TAG "ImageMatchTemplate"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#endif
/*
* Class: cn_gloud_imageproclib_ImageProcUtils
* Method: ImageMatchTemplate
* Signature: (IILandroid/graphics/Bitmap;Landroid/graphics/Bitmap;I)Z
*/
JNIEXPORT jboolean JNICALL Java_cn_gloud_imageproclib_ImageProcUtils_ImageMatchTemplate
(JNIEnv *env, jobject obj, jint x, jint y, jobject imageBitmap, jobject templBitmap,jint threshold){
}
jni目录下创建Android.mk和Application.mk文件
Android.mk:
LOCAL_PATH:=(call my-dir) include (CLEAR_VARS)
OPENCV_LIB_TYPE :=STATIC #利用静态库编译
ifeq ("(wildcard (OPENCV_MK_PATH))","")
include (LOCAL_PATH)/native/jni/OpenCV.mk else include (OPENCV_MK_PATH)
endif
LOCAL_MODULE := ImageProcUtils #和System.loadLibrary("ImageProcUtils");中指定的一样
LOCAL_LDLIBS += -llog -ljnigraphics #相关依赖库
LOCAL_SRC_FILES := cn_gloud_imageproclib_ImageProcUtils.cpp #源文件
include (BUILD_SHARED_LIBRARY) #编译动态库 #LOCAL_SRC_FILES := libImageProcUtils.so #预编译则指定so库 #include (PREBUILT_SHARED_LIBRARY) #预编译动态库
Application.mk:
APP_STL := gnustl_static #STL库
APP_CPPFLAGS := -frtti -fexceptions #编译参数
APP_PLATFORM := android-21 #android平台
APP_ABI += armeabi-v7a x86 #cpu架构
右键jni目录点击外部工具的ndk-build(module)就可以编译生成工具类需要的.so库了,.so库会生成在jni目录下的libs目录中,目录在build.gradle中指定
app module引用ImageProcLib module,修改app的build.gradle
dependencies {
...
implementation project(path: ':ImageProcLib')
}
修改工程的settings.gradle,
include ':app', ':ImageProcLib'