在上一篇文章中简单记录了关于Qt配置Android开发环境的内容,也包括配置OpenCV的部分,这篇文章则是记录在Android Studio上配置OpenCV的方法。由于OpenCV提供的Android开发工具包即包括C++ API也包括Java API,同时Android Studio也支持NDK的开发,故用户可选择使用纯Java完成整个应用的开发,也可以借助JNI和NDK,使用Java和C++混合编程完成应用的开发。Android Studio配置OpenCV包含两个部分,一是OpenCV Java 库的配置,二是C++库的配置,在本文中都会有简单记录。实际上关于Android Studio配置OpenCV的文章已经很多,但问题在于大部分使用的Android Studio版本都比较老,导致我在按照他们的教程配置的时候均出现了一些问题。为方便自己以后复习,我觉得有必要自己记录一下最新版本Android Studio的OpenCV配置方法,比较完整的教程可参考OpenCV On Android最佳环境配置指南。
在配置OpenCV之前,需要先完成Android Studio的开发环境配置,即确保在Android Studio上已经可以正常构建简单的应用程序。接着根据需要的版本在OpenCV官网下载Android开发工具包。我PC上安装的Android Studio版本是4.1.1,SDK和NDK是最新版本,安卓版本是29,OpenCV版本是4.4.0。
打开一个Android Studio Native C++工程,依次点击File->New->Import Module,在弹出的窗口中选择下载的OpenCV Android SDK安装目录下的sdk\java目录,如下图所示:
输入路径后点击Next->Finish即可。在老版Android Studio中,Import Module时可以设置Module的名字,但在最新版中没有这个选项,需要在Import后右键点击左侧Module根目录,选择Refactor->Rename,在弹出的窗口中选择Rename module进行更名,本例中更名为opencv
,更名后如下所示:
由于opencv模块的build.gradle文件内容与app模块的build.gradle不同,且Android Studio不支持同时有两个模块配置为com.android.application
,因此需要对opencv的build.gradle文件进行修改,修改的内容如下:
apply plugin: 'com.android.application'
为apply plugin: 'com.android.library'
defaultConfig
中的applicationId "com.example.xxx"
字段compileSdkVersion
,内容与app模块的build.gradle文件保持一致老版Android Studio可在File->Project Structure->Dependencies中设置app模块的依赖选项,但新版无法直接添加,需要在app模块的build.gradle文件中的dependencies
处手动添加一行implementation project(":opencv")
。
完成上面的配置后,还需配置OpenCV Java的运行库,不然在程序运行时会提示需要安装OpenCV Manager。配置的方法如下:
sdk\native\libs\
下的文件夹到Android Studio工程app\libs
目录下,可根据需要,仅复制目标设备的运行库,通常复制armeabi-v7a和arm64-v8a即可,如下图所示:sourceSets {
main {
jniLibs.srcDirs = ["libs"];
}
}
arguments "-DANDROID_STL=c++_shared"
添加后如下所示:
完成上面的配置后,在打包apk时会将libopencv_java4.so
和c++_shared.so
自动包括进去,注意需要是Native C++工程,其他类型的工程可能需要手动添加c++_shared.so到apk中。需要吐槽的是,即使包括了OpenCV运行库,在应用程序运行时依旧会提示需要安装OpenCV Manager,需要做点处理避开OpenCV Manager的初始化,具体可以参考OpenCV使用DNN模块加载SDD模型Android示例
比较简单的方法是创建Native C++工程,Android Studio会自动生成cpp相关的文件,包括.cpp源码和CMakeLists.txt,接着用CMake的配置方式在CMakeLists.txt中配置OpenCV即可,配置的内容如下:
set(OpenCV_DIR D:/OpenCV/opencv-4.4.0-android/OpenCV-android-sdk/sdk/native/jni)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(native-lib ${OpenCV_LIBS})
添加配置后,还需在MainActivity中加载native-lib
库,如果是Native C++工程,Android Studio会自动生成加载的代码如下:
static {
System.loadLibrary("native-lib");
}
在需要C++处理时,可在Java类中声明native
函数,并在.cpp文件中具体实现,native函数的形式与普通函数一致,不同的是需要在函数前添加native关键字。举例就是:假设Java包名为com.example.opencv.MainActivity
,我们需要一个使用C++代码处理帧的函数processFrameJNI
,那么在MainActivity中可声明函数如下:
native void processFrameJNI(Object frame);
在.cpp文件中对应的代码如下:
#include
#include
#include
#include
extern "C" JNIEXPORT void JNICALL
Java_com_example_opencv_MainActivity_processFrameJNI(
JNIEnv* env,
jobject /* this */,
jobject frame) {
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, frame, &info);
void* pdata{nullptr};
AndroidBitmap_lockPixels(env, frame, &pdata);
if (pdata && info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
cv::Mat image(info.height, info.width, CV_8UC4, pdata);
cv::cvtColor(image, image, CV_RGBA2BGR);
/* process the image here ... */
cv::cvtColor(image, image, CV_BGR2RGBA);
}
AndroidBitmap_unlockPixels(env, frame);
}
注意.cpp文件中函数名形式必须与Java包名一致,如使用到NDK的图形库如Bitmap,还需在CMakeLists.txt中添加相关的运行库如下:
target_link_libraries(native-lib jnigraphics)
在写Windows下Qt编写Android应用程序的环境搭建记录的时候我说如果避不开Java的话,还是在Android Studio上编写Java和C++的混合代码要更为便捷一些。当然,有些熟悉Qt的开发人员可能更倾向于在Qt上开发,这个因人而异。就我自己来说,是更倾向于Android Studio的。不得不说JNI是个好东西,经由它可以使得应用程序开发即能享受Java成熟的UI设计,同时也能享受C++带来的性能提升,相信在以后写APP时会是我的首选。