安卓NDK开发——使用CMake封装CPP文件成so库并调用so库

安卓NDK开发——使用CMake封装CPP文件成so库并调用so库一 创建 NDK 工程 创建 Android 工程 创建一个 NDK 工程 配置 NDK 支持 打开项目中的 build gradle 文件 通常是在 app 模块的目录下 在 android 块中添加以下代码 指定 CMake 版本和 NDK 版本 apply plugin com

大家好,我是讯享网,很高兴认识大家。

一、创建NDK工程

  1. 创建Android工程:
    创建一个NDK工程:在这里插入图片描述
    讯享网
  2. 配置NDK支持:
    • 打开项目中的build.gradle文件(通常是在app模块的目录下)。
    • android块中添加以下代码,指定CMake版本和NDK版本:
apply plugin: 'com.android.application' android { 
    compileSdkVersion 24 buildToolsVersion "29.0.2" defaultConfig { 
    applicationId "com.dashu.scanjia" archivesBaseName = "$applicationId" ndk { 
    moduleName "ScanJiaLib" abiFilters "armeabi-v7a", "arm64-v8a" } minSdkVersion 24 } externalNativeBuild { 
    cmake { 
    version "3.10.2" path file('src/main/jni/CMakeLists.txt') } } } dependencies { 
    implementation 'com.android.support:support-annotations:28.0.0' } 

讯享网
  1. 创建C/C++代码文件夹:
    • 在项目的app/src/main目录下,创建一个名为cpp的文件夹。
    • cpp文件夹中,创建一个C或C++文件,例如native-lib.cpp
      在这里插入图片描述
  2. 配置CMakeLists.txt:
    • app模块的目录下,创建一个名为CMakeLists.txt的文件,把所有用到的库依赖都使用这个make进行导入,我这里导入了onnxruntime ,OpenCV,Ncnn,还有把自己编写的C++代码也导入,导入的C++代码只要.cpp文件。
讯享网project(ScanJiaLib) cmake_minimum_required(VERSION 3.4.1) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp") if(DEFINED ANDROID_NDK_MAJOR AND ${ANDROID_NDK_MAJOR} GREATER 20) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-openmp") endif()  opencv 库 set(OpenCV_DIR "${CMAKE_SOURCE_DIR}/sdk/native/jni") find_package(OpenCV REQUIRED) if (OpenCV_FOUND) message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}") message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}") else () message(FATAL_ERROR "opencv Not Found!") endif (OpenCV_FOUND) include(${CMAKE_CURRENT_SOURCE_DIR}/onnxruntime-shared/OnnxRuntimeWrapper.cmake) find_package(OnnxRuntime REQUIRED) if (OnnxRuntime_FOUND) message(STATUS "OnnxRuntime_LIBS: ${OnnxRuntime_LIBS}") message(STATUS "OnnxRuntime_INCLUDE_DIRS: ${OnnxRuntime_INCLUDE_DIRS}") else () message(FATAL_ERROR "onnxruntime Not Found!") endif (OnnxRuntime_FOUND) #ncnn库 set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn--android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn) find_package(ncnn REQUIRED) set_target_properties( ncnn PROPERTIES INTERFACE_COMPILE_OPTIONS "-frtti;-fexceptions" # ncnn.cmake 里面是关的,把它重新打开防止跟opencv2冲突,如果是重新编译ncnn的请自己尝试要开还是关 ) add_library(ScanJia-jni SHARED ScanJia_jni.cpp AngleNet.cpp BitmapUtils.cpp clipper.cpp CrnnNet.cpp DbNet.cpp DocDewarp.cpp DocLayout.cpp DocumentCorrection.cpp DocumentEdge.cpp LayoutUtils.cpp OCRDoc.cpp OcrLite.cpp OcrResultUtils.cpp OcrUtils.cpp parmas.cpp praxis.cpp TextDirection.cpp) target_link_libraries(ScanJia-jni ${OnnxRuntime_LIBS} ncnn ${OpenCV_LIBS} jnigraphics) 
  1. 配置native-lib.cpp:
    在Jni中调用CPP的代码:
extern "C" JNIEXPORT jstring JNICALL Java_com_dashu_scanjia_ScanJiaSim_OCR(JNIEnv *env,jobject, jobject image) { 
    int padding = 50; float boxScoreThresh = 0.6; float boxThresh = 0.3; float unClipRatio = 2.0; bool doAngle = true; bool mostAngle = true; int maxSideLen = 1024; cv::Mat imgRGBA, imgBGR, imgOut; bitmapToMat(env, image, imgRGBA); cv::cvtColor(imgRGBA, imgBGR, cv::COLOR_RGBA2BGR); int originMaxSide = (std::max)(imgBGR.cols, imgBGR.rows); int resize; if (maxSideLen <= 0 || maxSideLen > originMaxSide) { 
    resize = originMaxSide; } else { 
    resize = maxSideLen; } resize += 2*padding; cv::Rect paddingRect(padding, padding, imgBGR.cols, imgBGR.rows); cv::Mat paddingSrc = makePadding(imgBGR, padding); //按比例缩小图像,减少文字分割时间 ppocr::ScaleParam s = ppocr::getScaleParam(paddingSrc, resize);//例:按长或宽缩放 src.cols=不缩放,src.cols/2=长度缩小一半 ppocr::OcrResult ocrResult = ocrLite->detect(paddingSrc, paddingRect, s, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); cv::cvtColor(ocrResult.boxImg, imgOut, cv::COLOR_BGR2RGBA); cv::resize(imgOut,imgOut,imgRGBA.size()); matToBitmap(env, imgOut, image); return env->NewStringUTF(ocrResult.strRes.c_str()); } 

二、封装so库

上面大概演示了NDK项目是如何导入与调用C++代码的,但很多时候,C++的实现代码并不能都给别人,所要把.cpp文件封装成.so文件,只留api接口给用户调用。要封装成.so文件分步,一是指定so文件输出的目录,二是指定哪些.cpp文件封装成.so 。

  1. 指定SO输出目录
    在CMakeLists.txt里面添加下面语句来指定生成的so输出的路径:
讯享网set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI}) 
  1. 指定生成so的.cpp文件
    我这里有很多个cpp文件,可以选择全部导入,也可以选择导入要封装的.cpp文件。
add_library(ScanJia-jni SHARED ScanJia_jni.cpp AngleNet.cpp BitmapUtils.cpp clipper.cpp CrnnNet.cpp DbNet.cpp DocDewarp.cpp DocLayout.cpp DocumentCorrection.cpp DocumentEdge.cpp LayoutUtils.cpp OCRDoc.cpp OcrLite.cpp OcrResultUtils.cpp OcrUtils.cpp parmas.cpp praxis.cpp TextDirection.cpp) 
  1. 编译生成.so
    编译工程,编译完成之后可以在指定的地方找到的编译好的.so文件:
    在这里插入图片描述

三、调用库

在CMakeLists.txt里面指定so文件路径,就可以不用依赖.cpp文件:

讯享网1.添加第三方库 add_library(ScanJia-lib SHARED IMPORTED ScanJia_jni.cpp) 2.添加库的路径 set_target_properties(ScanJia-lib PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI}/libScanJia-jni.so) target_link_libraries(ScanJia-jni ScanJia-lib ${OnnxRuntime_LIBS} ncnn ${OpenCV_LIBS} jnigraphics) 

整体的CMakeLists.txt文件变化如下:

project(ScanJiaLib) cmake_minimum_required(VERSION 3.4.1) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp") if(DEFINED ANDROID_NDK_MAJOR AND ${ANDROID_NDK_MAJOR} GREATER 20) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-openmp") endif() 封装时用到,指定so库的输出路径 #set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI})  opencv 库 set(OpenCV_DIR "${CMAKE_SOURCE_DIR}/sdk/native/jni") find_package(OpenCV REQUIRED) if (OpenCV_FOUND) message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}") message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}") else () message(FATAL_ERROR "opencv Not Found!") endif (OpenCV_FOUND) include(${CMAKE_CURRENT_SOURCE_DIR}/onnxruntime-shared/OnnxRuntimeWrapper.cmake) find_package(OnnxRuntime REQUIRED) if (OnnxRuntime_FOUND) message(STATUS "OnnxRuntime_LIBS: ${OnnxRuntime_LIBS}") message(STATUS "OnnxRuntime_INCLUDE_DIRS: ${OnnxRuntime_INCLUDE_DIRS}") else () message(FATAL_ERROR "onnxruntime Not Found!") endif (OnnxRuntime_FOUND) #ncnn库 set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn--android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn) find_package(ncnn REQUIRED) set_target_properties( ncnn PROPERTIES INTERFACE_COMPILE_OPTIONS "-frtti;-fexceptions" # ncnn.cmake 里面是关的,把它重新打开防止跟opencv2冲突,如果是重新编译ncnn的请自己尝试要开还是关 ) 调用.so文件 1.添加第三方库 #add_library(ScanJia-lib SHARED IMPORTED ScanJia_jni.cpp) 2.添加库的路径 #set_target_properties(ScanJia-lib # PROPERTIES IMPORTED_LOCATION # ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI}/libScanJia-jni.so) add_library(ScanJia-jni SHARED ScanJia_jni.cpp AngleNet.cpp BitmapUtils.cpp clipper.cpp CrnnNet.cpp DbNet.cpp DocDewarp.cpp DocLayout.cpp DocumentCorrection.cpp DocumentEdge.cpp LayoutUtils.cpp OCRDoc.cpp OcrLite.cpp OcrResultUtils.cpp OcrUtils.cpp parmas.cpp praxis.cpp TextDirection.cpp) target_link_libraries(ScanJia-jni ${OnnxRuntime_LIBS} ncnn ${OpenCV_LIBS} jnigraphics) 另外加的.cpp文件 #add_library(ScanJia-jni SHARED ScanJia_jni.cpp) 整体调用  #target_link_libraries(ScanJia-jni ScanJia-lib ${OnnxRuntime_LIBS} ncnn ${OpenCV_LIBS} jnigraphics) 
小讯
上一篇 2025-03-13 11:04
下一篇 2025-03-05 09:49

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/29543.html