Android NDK集成OpenCV使用C++的.h和.so库函数

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的目录下,形成这样的代码结构:

60e0bfa045cb449bbb000f6f5590b441.png

 

(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)运行输出:

76306d930b2c45fba6e33777697d228f.png

附录,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

猜你喜欢

转载自blog.csdn.net/zhangphil/article/details/130434576