Android 使用OpenCv,利用cmake

来源:互联网 发布:导入mysql中文乱码解决 编辑:程序博客网 时间:2024/05/03 10:26
Android Studio下使用OpenCv,利用cmake


一、概述:(关于学习研究的过程及cmake的优势可略过)
发一个图片编辑的项目,貌似必须用到OpenCv的函数,但是这个导入并使用的过程真是异常的艰辛,不知道去学了多少各种各样的知识,也走了多少的弯路,遇到多少的坑。要学习JNI调用的东西,android ndk配置的东西,还有C++的知识,图像处理的知识,Android Studio和gradle的各种配置,各种尝试,很多知识点资料文档也是很少,百度搜到的很多都无法使用,要么不能满足实际项目的条件,各种翻墙英语的去查。只有一个个的摸索,经过几个月断断续续的学习摸索,终于能够有像样一点的使用OpenCv的方法了。
经历过的方案:
1、使用Android.mk和application.mk进行配置,即ndk-build方式,这是目前网上最多的教程,但是很多由于这样那样的原因是用不了的。自己通过各种博客,视频研究等最后弄出来了,但是还是有很多不足。
(比如一个问题 是先用.mk文件导入OpenCv的库,然后你还要用到ndk里面的log,bitmap等库,在ndk-build模式下这些库必须 在gradle中进行导入,不能写在.mk文件中,这就必须在gradle中写入ndk节点;然而神奇的事情发生了,这时源代码不能被编译,.mk文件中指明创建的库并没有创建,为什么呢?
后来找到编译器给出的错误及解决办法,是因为在gradle中谢了ndk节点,构建系统就不会 再去通过android.mk文件进行构建了,即android.mk那里的构建就失效了,然而所知道的方法是OpenCv又必须用.mk文件导入。这就 来了一个矛盾,用了OpenCv就不能用ndk里面的库。然后去查,根据Stack Overflow上面的方法,每次改动C++码后,不用gradle,用命令行手动构建出so库后,放到对应的文件加下面,再注释掉.mk文件或者原件,再用gradle构建apk)目前没找到其他好的方式,所以这样太麻烦了。
2、将OpenCv的.so文件编译成.jar文件,然后通过Java方法去掉用,这就是OpenCv的那个依赖项目的作用,这个只需要将.so的文件复制到相应目录下,然后用一个gradle的任务,(具体的代码弄丢了,不过感觉这也不是好的方式,因为不能到C++层,很多东西无法操作了。)将OpenCv的.so,.a库编译成jar,然后就能调用了,这个也不需要安装OpenCv的manger那个apk,但是它编译出来的文件十分的大,没找到好的解决方式,所以最后没用了。
3、使用CMake的方式,CMake是Google官方推荐的最新的开发native的构建方式,比其以前的方式,实际上是强了不知道多少倍。因为最开始的ndk-build是官方引入的一种很原始的编写构建native代码的方式,当时还没有尽力来弄这方面,为了能开发C++代码,就拼凑了一个构建系统出来,在Android Studio这种比较现代的IDE中,完全不是一个层次的。所以在最近的更新中,算是把C++编译构建纳入到Android Studio的IDE中了。使用cmake开发native代码,除了少量配置,基本上和开发Java代码是一样的了,它支持代码提示,断点调试,各种编辑功能,效率应该高了数倍,所以事实上以前那种古老的ndk-build完全可以丢了,学习cmake的成本比其节约的时间少太多了。说了这么多关于cmake的,下面正式的如何使用cmake导入OpenCv:
二、具体操作
这个弄起来是比较复杂的,会遇到不少的坑,所以要准备好,短时间可能弄不要,最好要有相关的jni,C++,Android ndk的一些知识。
下载OpenCv的sdk等可以很容易搜到,这里不再赘述了,只讲与本方法相关的操作。
1、首先,也是主要的,先学会cmake基本的使用,创建新的带c的项目或者在已有项目中加入c。这个可以从网上的博客或者Google等学到。也不需要太多的功夫。在我的另一篇博客中也有介绍:Android Studio的gradle下配置ndk,jni/
2、构建好一个带c的项目后在src\main\下面创建jniLibs目录,然后把下载来的OpenCv的库比如F:\Android\OpenCV-3.1.0-android-sdk\OpenCV-android-sdk\sdk\native\libs 下所有子文件复制到该目录下
3、配置gradle:
在cmake已经配置好的情况下
在defaultconfig节点下加入,设置需要的abi,减小报的体积
 ndk {        // Specifies the ABI configurations of your native        // libraries Gradle should build and package with your APK.        abiFilters 'armeabi'    }
然后在Android根节点下加入
sourceSets {        main {            jniLibs.srcDirs = ['F:\\androidProject\\BaoZouPTu\\app\\src\\main\\jniLibs']        }    }


3、然后编写 编写cmakeList.txt文件,如下例子

set(pathToProject F:\\androidProject\\BaoZouPTu) 
set(pathToOpenCv F:\\Android\\OpenCV-3.1.0-android-sdk\\OpenCV-android-sdk)#设置OpenCv的路径变量
cmake_minimum_required(VERSION 3.6.0) 

#支持-std=gnu++11
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")


#配置加载native依赖
include_directories(${pathToOpenCv}/sdk/native/jni/include)#包含掉OpenCv的头文件目录
#动态方式加载
add_library(lib_opencv STATIC IMPORTED ) #表示创建一个导入库,静态方式
#引入libopencv_java3.so文件
set_target_properties(lib_opencv
                       PROPERTIES
                       IMPORTED_LOCATION ${pathToProject}/app/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so
                       )//包含libopencv_java3.so这个库


#自己的源文件
add_library(imageSynthesis SHARED
                    ImageSynthesis.cpp
                    NewColorTransfer.cpp
                    MyUtil.cpp
                    edgeBlur.cpp
 )

target_link_libraries(imageSynthesis log android -ljnigraphics lib_opencv)

4、最后创建C源文件,并写入OpenCv的头文件,可以使用OpenCv的api了。看Android Studio是否提示或报错,可以知道是否导入成功

#include<vector>#include <opencv2/core/cvdef.h>#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>using namespace cv;using namespace std;
//从RGB空间转换到lab空间Mat ColorTransfer::RGBToLab(Mat &m) {    Mat_<Vec3f> I = m;//定义一个Mat_型的mat,便于运算    for (int i = 0; i < I.rows; ++i) {        for (int j = 0; j < I.cols; ++j) {//矩阵运算,一行三列的RGB*[3*3]的参数矩阵            double L = 0.3811 * I(i, j)[0] + 0.5783 * I(i, j)[1] + 0.0402 * I(i, j)[2];            double M = 0.1967 * I(i, j)[0] + 0.7244 * I(i, j)[1] + 0.0782 * I(i, j)[2];            double S = 0.0241 * I(i, j)[0] + 0.1288 * I(i, j)[1] + 0.8444 * I(i, j)[2];            if (L == 0) L = 1;            if (M == 0) M = 1;            if (S == 0) S = 1;            L = log(L);//求自然对数底            M = log(M);            S = log(S);            I(i, j)[0] = (float) ((L + M + S) / sqrt(3.0));//运算一下重新赋值            I(i, j)[1] = (float) ((L + M - 2 * S) / sqrt(6.0));            I(i, j)[2] = (float) ((L - M) / sqrt(2.0));        }    }    return I;}
5、最后编译运行看是否成功生成so文件,并且可以调用。

在学会使用cmake之后,只需要这样几步,导入OpenCv是相当简单的,然后还需要jni,C++的相应的工程相关的知识。

最后,这里是导入的libopencv_java3.so库,因为是导入的.so库,里面有所有的函数,打包后还是有4M。如果静态导入.a库,或者只导入需要的部分,那样只有调用到的函数被打包进去,库要小得多,怎么做目前还有待解决。


0 0