基本思想:想把一个使用QT开发的工程,(其中实现逻辑涉及FFMPEG NCNN OPENCV的工程)打包成一个动态库,供Android小组调用
一、 构建一个简单的clion工程,该工程中调用了第三方的opencv,完成了一个像素点的累加;
cmakelists.txt
cmake_minimum_required(VERSION 3.21)
project(untitled1)
find_package(OpenCV REQUIRED)
set(CMAKE_CXX_STANDARD 14)
add_executable(untitled1 main.cpp cv_item.cpp cv_item.h)
target_link_libraries(untitled1 ${OpenCV_LIBS} )
main.cpp
#include "cv_item.h"
cvItem *cvObject= nullptr;
int main() {
cvObject=new cvItem();
cvObject->init(4,4,12,12);
cv::Mat img(600, 600, CV_8UC3, cv::Scalar(255, 255, 255));
int a= cvObject->process(img);
printf("a=%d\n",a);
return 0;
}
cv_item.h
//
// Created by ubuntu on 2022/2/24.
#ifndef UNTITLED1_CV_ITEM_H
#define UNTITLED1_CV_ITEM_H
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
class cvItem {
public:
cvItem();
~cvItem();
public:
void init(int x,int y,int width,int height);
int process(cv::Mat img);
private:
int x,y,width,height;
};
#endif //UNTITLED1_CV_ITEM_H
cv_item.cpp
//
// Created by ubuntu on 2022/2/24.
//
#include "cv_item.h"
cvItem::cvItem(){
x=0;
y=0;
width=1;
height=1;
}
cvItem::~cvItem(){
}
void cvItem::init(int x,int y,int width,int height) {
this->x=x;
this->y=y;
this->width=width;
this->height=height;
}
int cvItem::process(cv::Mat img) {
cvtColor(img, img, cv::COLOR_BGR2GRAY);//使图片灰度化
int sum=0;
//使用二维数组循环读取 row代表行 col是列
for (int row = 0; row < img.rows; row++)//行循环
{
for (int col = 0; col < img.cols; col++)//列循环
{
sum+= img.at<uchar>(row, col);
}
}
return sum;
}
测试结果
/home/ubuntu/CLionProjects/untitled1/cmake-build-debug/untitled1
a=91800000
Process finished with exit code 0
二、创建一个JNI工程,导入一下nihui大师的opencv-mobile库,修改一下androids studio 的文件
(1)、整个文件的目录结构,最好把JNI的接口单独写一个package,这很重要,不仅JNI的返回函数名字含有这个包的层次名,而且一旦需要从JNI返回list数据到java段,也需要该层次包名
(2)、同时为了后面生成的动态库做准备,设置一下生成的库类型
(3)、native-lib.cpp文件内容
#include <jni.h>
#include <string>
#include "cv_item.h"
cvItem *cvObject= nullptr;
extern "C" JNIEXPORT jstring JNICALL
Java_com_sxj731533730_test_Test_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
cvObject=new cvItem();
cvObject->init(4,4,12,12);
cv::Mat img(600, 600, CV_8UC3, cv::Scalar(255, 255, 255));
int a= cvObject->process(img);
std::string str ="a="+ to_string(a);
return env->NewStringUTF(str.c_str());
}
cmakelists.txt文件内容,生成动态库
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.18.1)
# Declares and names the project.
project("myapplication")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
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()
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.5.4-android/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)
include_directories(${CMAKE_SOURCE_DIR}/include)
add_library( # Sets the name of the library.
myapplication
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp
cv_item.cpp
)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
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)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
myapplication
${OpenCV_LIBS}
# Links the target library to the log library
# included in the NDK.
${log-lib})
测试结果,也同时生成了我们需要的库文件,上述cmakelists.txt文件,
(4)、生成的库在这个目录,拷贝出来,新创建一个工程测试一下,保证包名一致即可,我直接在原工程上,删文件了构造新工程了
(5)、在原代码基础上,删掉cv_item.cpp文件,将上述的so文件导入main/jniLIbs/libs/目录下,在build.gradle添加导入so,
sourceSets{
main{
jniLibs.srcDirs=["src/main/jniLibs/libs"]
jniLibs.srcDirs=["libs"]
}
}
同时在cmakelists.txt导入配置so动态库,删掉原来引用的cv_item.cpp
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.18.1)
# Declares and names the project.
project("myapplication")
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()
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.5.4-android/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)
include_directories(${CMAKE_SOURCE_DIR}/include)
add_library(libmyapplication SHARED IMPORTED)
set_target_properties(libmyapplication PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/libs/${ANDROID_ABI}/libmyapplication.so)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
myapplication
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
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)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
myapplication
${OpenCV_LIBS}
libmyapplication
# Links the target library to the log library
# included in the NDK.
${log-lib})
测试一下可用
这是原工程的目录架构
新工程的目录架构,要保证system.loadLibrary的库引入名字是动态库的名字,同时在com下构建的目录结构和原文件结构一致 com/sxj731533730/test/test,
同时别忘修改cmakelists.txt引入动态包和修改build.gradle包含lib库
build.gradle
sourceSets{
main{
jniLibs.srcDirs=["src/main/jniLibs/libs"]
jniLibs.srcDirs=["libs"]
}
}
测试结果
通过上述方法,本菜鸡将一个QT工程中含有FFMPEG和NCNN、OPENCV的三方实现工程编译成了so,可以方便调用了,当然需要你一开始有交叉编译好的FFMPEG NCNN OPENCV的android包支持