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層的函數都能進行處理的,建議選擇第三種方法
- 第二種方法建議在第三種方法不滿足條件的情況下進行輔助使用,因為使用了第三種方法的前提是使用第二種方法的動態鏈接庫。
最后附上源碼
- http://download.csdn.net/detail/sbsujjbcy/9275897
總結
以上是生活随笔為你收集整理的Android 使用OpenCV的三种方式(Android Studio)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV2.4.9 For Andr
- 下一篇: Android开发——Android S