Android NDK集成OpenCV使用C++的.h和.so库函数
opencv可以作为一个单独的Android module库,被工程下的其他模块使用,但是这样就没法在Android NDK项目的c++代码直接使用opencv的.h文件和.so文件。要在Android NDK项目C++代码文件中使用,则需要以Android NDK C/C++方式集成opencv。
(1)为当前module创建一个Android NDK的c++模块,参考:
Android添加C++/CPP项目代码(2)_zhangphil的博客-CSDN博客基于Windows平台,Android NDK(JNI)开发技术》【摘要】本文介绍如何基于Windows平台,在Eclipse中使用Android NDK技术实现“Android平台上的JNI ( Java Native Interface ) ”开发。新增的getStringCpp()是新增的一个方法,因为没有实现所以报红。以上完成后,就可以在Java层像使用普通Java函数一样使用getStringCpp()其中,loadLibrary()里面填写的即是(2)里面的xxx.cpp的xxx名字。https://blog.csdn.net/zhangphil/article/details/130207425
(2)下载opencv提供的Android SDK。基于opencv-4.7.0。
Releases - OpenCVhttps://opencv.org/releases/下载后的sdk解压。
本例只考虑arm64-v8a,把目录opencv-4.7.0-android-sdk\OpenCV-android-sdk\sdk\native\libs\arm64-v8a 下面的 libopencv_java4.so 放入到 (1)中的cpp目录下的的jniLibs目录里面(jniLibs可以自己手动创建),在app的build.gradle配置文件android - defaultConfig块里面增加配置:
ndk {
abiFilters 'arm64-v8a'
}
externalNativeBuild {
cmake {
cppFlags ''
arguments "-DANDROID_STL=c++_shared"
}
}
把opencv-4.7.0-android-sdk\OpenCV-android-sdk\sdk\native\jni\include下面C++定义的头文件目录 opencv2 全部连文件夹复制到cpp的目录下,形成这样的代码结构:
(3)修改CMakeLists.txt。(重要,且容易出错)
cmake_minimum_required(VERSION 3.22.1)
project("opencv")
# 指定一个本地头文件路径。
include_directories(${CMAKE_SOURCE_DIR}/)
add_library( # Sets the name of the library.
opencv
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
opencv.cpp)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# 设置opencv的动态库
add_library(libopencv_java4
SHARED
IMPORTED)
set_target_properties(libopencv_java4
PROPERTIES
IMPORTED_LOCATION
${CMAKE_HOME_DIRECTORY}/jniLibs/${ANDROID_ABI}/libopencv_java4.so
)
target_link_libraries( # Specifies the target library.
opencv
libopencv_java4
# Links the target library to the log library
# included in the NDK.
${log-lib})
(4)创建Android的Java层函数调用opencv的C/C++ native函数:
package my.opencv;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("opencv");
}
public native String myOpenCv();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("fly-Android", myOpenCv());
}
}
(5)myOpenCV对应在native层的C/C++实现,在opencv.cpp里面:
#include <jni.h>
#include <stdlib.h>
#include <string>
#include <android/log.h>
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/types_c.h"
#include "opencv2/opencv_modules.hpp"
const char *TAG = "fly-native";
#define LOG __android_log_print
void LOGI(const char *info, std::string s) {
LOG(ANDROID_LOG_INFO, TAG, info, s.c_str());
}
void LOGI(const char *info, int num) {
LOGI(info, std::to_string(num));
}
using namespace cv;
extern "C"
JNIEXPORT jstring JNICALL
Java_my_opencv_MainActivity_myOpenCv(JNIEnv *env, jobject thiz) {
int v_major = cv::getVersionMajor();
int v_minor = cv::getVersionMinor();
LOGI("major %s", v_major);
LOGI("minor %s", v_minor);
std::string vs = cv::getVersionString();
return env->NewStringUTF(vs.c_str());
}
(6)运行输出:
附录,OpenCL的一些so库:
OpenCLDemo/app/src/main/jniLibs at master · csarron/OpenCLDemo · GitHubOpenCLDemo for Redmi Note 4X (nikel, MTK), Nexus 5, Nexus 6p and Pixel 2 - OpenCLDemo/app/src/main/jniLibs at master · csarron/OpenCLDemohttps://github.com/csarron/OpenCLDemo/tree/master/app/src/main/jniLibs这些库大部分不一定必须放在cpp目录下的jniLibs里面通过CMakeLists.txt配置,可以直接放到更外层的app\libs\arm64-v8a等下面。
Android JNI配置CMakeLists.txt修改.cpp在logcat打印日志_zhangphil的博客-CSDN博客以上完成后,就可以在Java层像使用普通Java函数一样使用getStringCpp()其中,loadLibrary()里面填写的即是(2)里面的xxx.cpp的xxx名字。需要注意的,现在一般是64位的so库,如果app\libs下没有\arm64-v8a文件夹,需要新建arm64-v8a目录文件,然后把64位的so库放到。(2)在module的路径下,比如app\下,如果有app\libs目录,不需新建,如果没有,在app\下,新建libs,形成\app\libs目录。https://blog.csdn.net/zhangphil/article/details/130423157