在OpenCV for Android 2.4.5中使用SURF(nonfree module)

來源:互聯網
上載者:User

在OpenCV4Android中沒有nonfree module,因此也就沒有了SURF和SIFT組件。但是我們可以通過OpenCV for Windows的nonfree module開原始碼通過NDK將其編譯為Android可以使用的.so庫檔案,然後通過JNI技術,將該.so檔案掛載到JNI的庫中。

具體實現方法如下:

需要的工具:

  1. NDK
  2. OpenCV for Android
  3. OpenCV for Windows(其實只需要兩個標頭檔)
  4. Android ADT

    電腦作業系統為Windows7 x86,Android開發環境為ADT 20130512。下面說明如何在OpenCV中使用nonfree module:

   1.編譯nonfree module庫

    博主OpenCV for Windows安裝路徑為C:\Program Files\opencv,OpenCV4Android路徑為 E:\My Documents\Android\OpenCV-2.4.5-android-sdk。

   nonfree module 的原始碼儲存在C:\Program Files\opencv\modules\nonfree\src中,標頭檔儲存在C:\Program Files\opencv\modules\nonfree\include\opencv2\nonfree中。

    編譯的過程中需要兩個標頭檔,一個為nonfree.hpp,一個為features2d.hpp,將這兩個標頭檔拷貝至OpenCV4Android SDK的include檔案夾下:E:\My Documents\Android\OpenCV-2.4.5-android-sdk\sdk\native\jni\include\opencv2\nonfree檔案夾下。

    為了編譯庫檔案,我們還需要nonfree module的原始碼。原始碼為C:\Program Files\opencv\modules\nonfree\src中的nonfree_init.cpp,precomp.cpp,sift.cpp,surf.cpp和precomp.hpp五個檔案。為了簡單起見,我們需要一個簡單的Android JNI的工程來幫我們編譯這些原始碼。

   2.配置NDK環境

     在Android中建立JNI工程的方法是在一個已經建立好的Android工程上點擊右鍵,new->Ohter->Convert to a C/C++ Project(Adds C/C++ Nature),並在Android工程目錄中建立jni檔案夾,將上述5個原始碼檔案拷貝至jni檔案夾中。並在jni檔案夾中建立Android.mk和Application.mk檔案。此時檔案組織如下:

    博主NDK的位置為C:\android-ndk-r8e,在系統變數中建立NDKROOT,變數值為C:\android-ndk-r8e,在該檔案夾下有ndk-build.cmd指令碼命令檔案,該檔案是使用NDK編譯C代碼的關鍵。配置完畢後,在Android工程中配置C++編譯命令,配置如下所示,意味使用環境變數中NDKROOT/ndk-build.cmd進行編譯    在Behaviour選項卡中勾選Build on resource save(Auto build)。至此NDK配置完畢     3.編寫makefile檔案    在Android.mk中代碼如下

LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)OPENCV_INSTALL_MODULES:=onOPENCV_CAMERA_MODULES:=offinclude ..\OpenCV-2.4.5-android-sdk\sdk\native\jni\OpenCV.mkLOCAL_C_INCLUDES:= ../OpenCV-2.4.5-android-sdk/sdk/native/jni/includeLOCAL_MODULE    := nonfreeLOCAL_CFLAGS    := -Werror -O3 -ffast-mathLOCAL_LDLIBS    += -llogLOCAL_SRC_FILES := nonfree_init.cpp \ precomp.cpp \ sift.cpp \ surf.cppinclude $(BUILD_SHARED_LIBRARY)
在Android.mk中使用了OpenCV.mk的路徑和jni/include的路徑,我的工程是和OpenCV SDK放在同一檔案夾下的,因此可以這樣寫。兩處使用絕對路徑也可以,但是不能有空格。

在Application.mk中代碼如下

#APP_ABI := armeabi APP_ABI := armeabi-v7aAPP_STL := gnustl_staticAPP_CPPFLAGS := -frtti -fexceptionsAPP_PLATFORM := android-8

這裡可能有問題,APP_PLATFORM按照Andoird工程建立時最小SDK填寫,否則編譯不過。

    如果之前勾選了Auto Build,這裡工程會自動編譯,在libs下會產生兩個庫,為libnonfree.so和libopencv_java.so,這兩個庫就是需要的庫檔案了。使用這兩個庫檔案,就可以通過JNI技術在Android中使用SURF演算法。4. 在Android中使用SURF的例子    和2中一樣,首先建立一個帶有NDK工程的Android工程,並建立jni檔案夾,用javah產生native的類標頭檔(如何產生類檔案請參看另一邊博文),並將剛才編譯好的libnonfree.so和libopencv_java.so拷貝值jni檔案夾下(當然你也可以把這兩個東西放到OpenCV的庫檔案夾下,一勞永逸,只要能在連結的時候能搜尋到就行了)。編寫好native方法的c++實現,這裡我實現了利用SURF的特徵點檢測和描述符產生。代碼如下:
#include "NativeSurf.h"#include <opencv2/opencv.hpp>#include <stdio.h>#include <opencv2/nonfree/features2d.hpp>#include <opencv2/nonfree/nonfree.hpp>using namespace cv;using namespace std;void KeyPoint2Mat(vector<KeyPoint>& keypoints, Mat& mat){int i = 0;int size = keypoints.size();mat.create(size,1,CV_32FC(7));float* buff = (float*)mat.data;for(i=0;i<size;i++){KeyPoint kp = keypoints[i];buff[7*i+0] = kp.pt.x;buff[7*i+1] = kp.pt.y;buff[7*i+2] = kp.size;buff[7*i+3] = kp.angle;buff[7*i+4] = kp.response;buff[7*i+5] = kp.octave;buff[7*i+6] = kp.class_id;}}JNIEXPORT void JNICALL Java_com_ruif_nativeSurf_NativeSurf_SurfDetect  (JNIEnv *, jclass, jlong imgObj, jlong keyPointsObj, jlong descriptorObj){//Create MatsMat* img = (Mat*)imgObj;//imgMat* descriptor = (Mat*)descriptorObj;//DescriptorMat* keyPointsMat = (Mat*)keyPointsObj;vector<KeyPoint> keyPointvec;SurfFeatureDetector surfDetector(1000);SurfDescriptorExtractor surfExtractor;surfDetector.detect(*img,keyPointvec);surfExtractor.compute(*img,keyPointvec,*descriptor);KeyPoint2Mat(keyPointvec,*keyPointsMat);}

編寫Android.mk檔案如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := nonfreeLOCAL_SRC_FILES := libnonfree.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE    := opencv_java_prebuiltLOCAL_SRC_FILES := libopencv_java.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)include ../OpenCV-2.4.5-android-sdk/sdk/native/jni/OpenCV.mkLOCAL_MODULE    := SurfLOCAL_CFLAGS    := -Werror -O3 -ffast-mathLOCAL_LDLIBS    += -llog -ldl LOCAL_SHARED_LIBRARIES := nonfree opencv_java_prebuiltLOCAL_SRC_FILES := Surf.cppinclude $(BUILD_SHARED_LIBRARY)

編寫Application.mk檔案如下:

APP_ABI := armeabi-v7aAPP_STL := gnustl_staticAPP_CPPFLAGS := -frtti -fexceptionsAPP_PLATFORM := android-8

此時你會發現各種語法錯誤和不能解析的變數。其實他們並不影響編譯,所有的標頭檔在Android.mk和Application.mk中已經聲明,編譯仍然會成功,但是自己編寫程式時為了使用Eclipse的提示功能,需要對工程進行如下設定。

在C/C++ General->Paths and Symbols中設定Includes為:${NDKROOT}/platforms/android-14/arch-arm/usr/include${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.7/include${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.7/libs/armeabi-v7a/include../OpenCV-2.4.5-android-sdk/sdk/native/jni/include參見
OpenCV4Android文檔

 你會發現所有都正常了,此時工程結構組織如下:

   在libs下的libSurf.so庫就是我們需要使用的JNI庫。

   5.使用JNI庫    該JNI庫需要結合OpenCV使用,因此仍然需要調用OpenCV4Anroid庫,調用的方法參見
OpenCV文檔。需等待OpenCV庫載入完畢後才能載入我們編寫的庫。2.4.5中應該不用添加initial_nonfree()這個函數了。運行能夠成功。
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {        @Override        public void onManagerConnected(int status) {            switch (status) {                case LoaderCallbackInterface.SUCCESS:                {                Log.i(Unity.TAG,"OpenCV loaded successfully");                System.loadLibrary("nonfree");                System.loadLibrary("opencv_java");                System.loadLibrary("Surf");                isOpenCVLoad = true;                } break;                default:                {                Log.i(Unity.TAG,"OpenCV loaded Failed!");                    super.onManagerConnected(status);                } break;            }        }    };

    一定要順序載入,否則會報錯。至此就能夠在JAVA中使用Native函數了。網上這方面資料很少,希望對大家有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.