Android 使用OpenCV的三种方式(Android Studio)

from: http://blog.csdn.net/sbsujjbcy/article/details/49520791

其实最早接触OpenCV是很久很久之前的事了,大概在2013年的5,6月份,当时还是个菜逼(虽然现在也是个菜逼),在那一段时间,学了一段时间的Android(并不算学,一个月都不到),之后再也没接触android,而是一直在接触Java Web。那次接触OpenCV是因为一个学长的毕业设计,这次接触OpenCV是因为自己的毕业设计。2013年那年技术太菜,ndk环境都搭不好,当初还是eclipse环境,一直按照网上的教程去搭,下什么cygwin,简直就是个坑,网上的文章转来转去,都是过时的。后来一个机会看到了google官方的一个文档,就像发现了新大陆一样,发现ndk环境根本不需要装cygwin,装了你就坑了,装这个东西有好多G呢,时间浪费不说,简直误人子弟啊。后来在那年7月写下一篇博客

NDK开发环境

这段时间在填自己毕业设计的坑,要用到OpenCV,首先得下载到sdk吧,这个从官网上下载就好了
OpenCV for Android

注意下载的是OpenCV for android。当前版本是3.0

这里写图片描述

解压后,里面的内容如下

这里写图片描述

samples目录下是样例代码,sdk目录下是我们需要用到的Java层和jni层的代码。apk目录是manager的apk安装包

其实OpenCV最简单的使用方式是使用manager,也就是使用apk目录下的安装包,安装对应的apk,将java层代码导入,使用OpenCVLoader.initAsync()加载库,之后你就可以直接用java代码调用Opencv相关的功能了。

这里写图片描述

但是这种方式除了安装我们自己的apk还需要安装上面提到的manager的apk,用户体验十分不好,不推荐使用,本文的三种方式将完全脱离这个manager的apk。

本文下面的三种方式的内容参考自文章 OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)

本篇文章使用android studio作为开发环境,由于实验性的构建工具对ndk支持还不好,所以使用旧的构建方式,在原来写的一篇博客基础上修改即可android studio下ndk开发

这正式介绍三种方式之前,我们需要做一些前期准备。

首先新建一个项目,将OpenCV中sdk目录下的native目录拷到项目根目录

这里写图片描述

然后新建Jni目录

这里写图片描述

在里面新建两个文件

这里写图片描述

编辑gradle.properties文件,增加下面的属性使用旧版的ndk功能(不添加会使用实验性的ndk构建工具)

<code class="hljs bash has-numbering">android.useDeprecatedNdk=<span class="hljs-literal">true</span></code><ul style="" class="pre-numbering"><li>1</li></ul><ul style="" class="pre-numbering"><li>1</li></ul>

在local.properties文件中配置ndk目录

<code class="hljs tex has-numbering">ndk.dir=D<span class="hljs-command">\:</span><span class="hljs-command">\\</span>AndroidSDK<span class="hljs-command">\\</span>sdk<span class="hljs-command">\\</span>ndk-bundle</code><ul style="" class="pre-numbering"><li>1</li></ul><ul style="" class="pre-numbering"><li>1</li></ul>

编辑build.gradle,在android节点中增加下面的代码

<code class="hljs makefile has-numbering"><span class="hljs-constant">APP_STL</span> := gnustl_static
<span class="hljs-constant">APP_CPPFLAGS</span> := -frtti -fexceptions
<span class="hljs-constant">APP_ABI</span> := armeabi armeabi-v7a
<span class="hljs-constant">APP_PLATFORM</span> := android-8
</code>

这时候,使用gradle构建一下,如果能成功构建出so,说明配置没问题,如下图,点击as右侧的gradle展开,双击ndkBuild进行构建

这里写图片描述

这里写图片描述

下面开始讲第一种方法,纯jni层的代码,该方法基于上面的所有步骤,为静态链接库

声明java层的native方法

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> OpenCVHelper {
    <span class="hljs-keyword">static</span> {
        System.loadLibrary(<span class="hljs-string">"OpenCV"</span>);
    }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> native <span class="hljs-keyword">int</span>[] <span class="hljs-title">gray</span>(<span class="hljs-keyword">int</span>[] buf, <span class="hljs-keyword">int</span> w, <span class="hljs-keyword">int</span> h);
}
</code>

注意上面的OPENCV_LIB_TYPE属性的改动,从STATIC改为了SHARED,这时候再用ndkBuild一下,你会发现会输出一些警告以及一部分红色的内容

这里写图片描述

生成的so库的大小为310k,小了好几倍

这里写图片描述

这时候如果你直接取运行程序,会报错误

这里写图片描述

原因是我们使用的是动态库加载方式,还需要将依赖的so加进去,这个so就是图中的libopencv_java3.so,他在我们的最开始加到项目里的native目录中

这里写图片描述

将它拷到我们的jniLibs目录中去,这里只拷贝armeabi和armeabi-v7a中的,至于其他的按需拷贝

这里写图片描述

这时候运行就不会报错了。

既然我们使用了动态链接库,那么我们同样也可以使用java层的接口,优点是java开发速度相对快一点。第三种方法在第二种方法基础上,使用纯java层代码进行处理。

在此之前,我们需要将sdk目录中的java代码拷到项目中去

这里写图片描述

但是org.opencv.engine包中是一个aidl,我们需要将它剪贴到aidl目录中去,就像这样子

这里写图片描述

最后还有一个资源文件attrs.xml,拷过来

这里写图片描述

build一下项目,不出意外应该会报错,这时候找到该类,引入自己的R文件包就可以了

这里写图片描述

再次build应该就不会有什么问题了。

java层的测试方法

<code class="hljs avrasm has-numbering">OpenCVLoader<span class="hljs-preprocessor">.initDebug</span>()<span class="hljs-comment">;</span>
Mat rgbMat = new Mat()<span class="hljs-comment">;</span>
Mat grayMat = new Mat()<span class="hljs-comment">;</span>
Bitmap srcBitmap = BitmapFactory<span class="hljs-preprocessor">.decodeResource</span>(getResources(), R<span class="hljs-preprocessor">.drawable</span><span class="hljs-preprocessor">.ic</span>)<span class="hljs-comment">;</span>
Bitmap grayBitmap = Bitmap<span class="hljs-preprocessor">.createBitmap</span>(srcBitmap<span class="hljs-preprocessor">.getWidth</span>(), srcBitmap<span class="hljs-preprocessor">.getHeight</span>(), Bitmap<span class="hljs-preprocessor">.Config</span><span class="hljs-preprocessor">.RGB</span>_565)<span class="hljs-comment">;</span>
Utils<span class="hljs-preprocessor">.bitmapToMat</span>(srcBitmap, rgbMat)<span class="hljs-comment">;//convert original bitmap to Mat, R G B.</span>
Imgproc<span class="hljs-preprocessor">.cvtColor</span>(rgbMat, grayMat, Imgproc<span class="hljs-preprocessor">.COLOR</span>_RGB2GRAY)<span class="hljs-comment">;//rgbMat to gray grayMat</span>
Utils<span class="hljs-preprocessor">.matToBitmap</span>(grayMat, grayBitmap)<span class="hljs-comment">; //convert mat to bitmap</span>
img<span class="hljs-preprocessor">.setImageBitmap</span>(grayBitmap)<span class="hljs-comment">;</span></code>

注意使用OpenCVLoader.initDebug();进行初始化而不是使用OpenCVLoader.initAsync()

这种方法的特点是处理都在java层,不怎么会涉及jni层的代码,除非java层完成不了的工作会转移到jni层去。

三种方法各有各的优点,根据自己的情况进行选择。

  • 如果c++特别好的,建议使用第一种方法
  • 如果更习惯java代码的,并且java层的函数都能进行处理的,建议选择第三种方法
  • 第二种方法建议在第三种方法不满足条件的情况下进行辅助使用,因为使用了第三种方法的前提是使用第二种方法的动态链接库。

最后附上源码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值