Skip to content

Android Studio JNI层调用OpenCV进行图像处理

iPanda edited this page Mar 15, 2019 · 1 revision

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 <cn_gloud_imageproclib_ImageProcUtils.h> #include <android/bitmap.h> #include <android/log.h> #include <opencv2/opencv.hpp> #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' 
Clone this wiki locally