OpenCV4Android釋疑: 透析Android以JNI調OpenCV的三種方式(讓OpenCVManager永不困擾)

來源:互聯網
上載者:User

標籤:ring   des   .net   地方   環境   dma   win   tool   string   

前文曾具體探討了關於OpenCV的使用,原本以為天下已太平。但不斷有人反應依舊配不好OpenCV4Android,不能得心應手的在Android上使用OpenCV。大量的精力都浪費在摸索配置上。尤其是OpenCVManager誕生之後。更讓人無語。大家第一個反應就是怎樣才幹不安裝OpenCVManager。由於要多安裝這個東西對客戶來說體驗太不好了。

咱家昨夜研究至兩點,今早七點起床。最終把頭緒理清了。

以下咱家以之前做過的一個基於OpenCV2.3.1。android通過jni調用opencv實現人臉檢測的執行個體來逐個回答,怎樣在Android上使用Java介面而不安裝OpenCVManager,及通過jni方式使用OpenCV的三種方式。

先來看JNI調OpenCV的三種方式。非常多人會驚訝腫麼JNI調OpenCV還會有3種方式。長久以來大量網上教程都說在Android上僅僅有Java和JNI兩種方式使用OpenCV,怎麼又冒出來3種使用JNI的方式。

經本人研究。確實有3種調JNI的方式,就連官網指導文檔都模稜兩可,所以讓非常多人不知所措。

這三種方式各自是:

1、使用靜態OpenCV庫的方式。

2、使用動態OpenCV庫的方式;

3、同一時候使用Java的API又使用JNI的介面的方式,此時編譯時間一般使用的是動態連結OpenCV庫的方式。

要說明的是,這三種方式均無需安裝OpenCVManager,差別在於mk檔案的不同。個人最推崇的就是第一種方式,第一種方式也是和OpenCV2.3.1在JNI調OpenCV使用全然吻合的一種方式。本文是以windows平台最新的OpenCV-2.4.9-android-sdk為基礎,使用2.4.9的OpenCV4Android須要使用NDK版本號碼為r9,本人使用的是android-ndk-r9d的版本號碼。之所以昨晚搗騰到2點,就是由於之前使用的ndk r7的版本號碼。怎麼編都編只是,因少東西報上千行錯誤。android-ndk-r9d安裝十分簡單,僅僅須要解壓縮配置一個環境變數就可以。

一、Android以JNI調OpenCV的第一種配置方法:

Application.mk檔案中的內容例如以下:

APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti -fexceptions 
APP_ABI:= armeabi-v7a 

這三種方式的Application.mk都一樣,所以往後不說了。在Application.mk裡還能夠配置APP_PLATFORM=17相似這樣的,當然不配置全然能夠。

Android.mk內容例如以下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)


OpenCV_INSTALL_MODULES:=on
OPENCV_CAMERA_MODULES:=off


OPENCV_LIB_TYPE:=STATIC


ifeq ("$(wildcard $(OPENCV_MK_PATH))","")
include D:\ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\OpenCV.mk
else  
include $(OPENCV_MK_PATH)  
endif 


LOCAL_MODULE    := ProcessImg 
LOCAL_SRC_FILES := DetectFace_JNI.cpp \
src/copyToAssets.cpp \
src/detectFace.cpp
LOCAL_LDLIBS    += -lm -llog 

include $(BUILD_SHARED_LIBRARY) 

逐一解釋下,OpenCV_INSTALL_MODULES:=on的意思是自己主動將依賴的OpenCV的so庫複製到libs目錄下,但非常遺憾的是,這個命令僅僅對OPENCV_CAMERA_MODULES有效。

僅僅有當OPENCV_CAMERA_MODULES:=on時。能夠看到他會自己主動將裡面的帶camera的so拷貝至project下的libs目錄下。include D:\ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\OpenCV.mk這句話比較關鍵,這是我安裝OpenCV-2.4.9-android-sdk的地方。我將其安裝到了D盤。而我的工作空間在E盤也是ok的。

而不用像OpenCV2.3.1使用時,限制這個解壓縮包的位置了。

LOCAL_MODULE    是要產生的庫的名字,LOCAL_SRC_FILES 是jni目錄下的cpp檔案。當中的src說明我的jni下還有個子目錄名字是“src”,這塊替換成自己的原始碼檔案就ok了。

為了測試的嚴謹性。在project裡將libs目錄的東西。和obj目錄下的東西全刪了。用cygwin進到project,輸入ndk-build,看到例如以下資訊:

[email protected] /cygdrive/e/WorkSpaces/OpenCV4Android/FaceDetectLiu2$ ndk-buildAndroid NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 16 in ./AndroidManifest.xml[armeabi-v7a] Cygwin         : Generating dependency file converter script[armeabi-v7a] Compile++ thumb: ProcessImg <= DetectFace_JNI.cppjni/DetectFace_JNI.cpp: In function ‘_jstring* Java_org_yan_processlib_LibProcessImg_processIplImg(JNIEnv*, jobject, jintArray, int, int)‘:jni/DetectFace_JNI.cpp:99:44: warning: converting ‘false‘ to pointer type for argument 2 of ‘jint* _JNIEnv::GetIntArrayElements(jintArray, jboolean*)‘ [-Wconversion-null]jni/DetectFace_JNI.cpp: In function ‘_jstring* Java_org_yan_processlib_LibProcessImg_processStaticImg(JNIEnv*, jobject, jintArray, int, int)‘:jni/DetectFace_JNI.cpp:133:44: warning: converting ‘false‘ to pointer type for argument 2 of ‘jint* _JNIEnv::GetIntArrayElements(jintArray, jboolean*)‘ [-Wconversion-null][armeabi-v7a] Compile++ thumb: ProcessImg <= copyToAssets.cpp[armeabi-v7a] Compile++ thumb: ProcessImg <= detectFace.cpp[armeabi-v7a] SharedLibrary  : libProcessImg.so[armeabi-v7a] Install        : libProcessImg.so => libs/armeabi-v7a/libProcessImg.so
上面兩個警告麼有關係,編譯成功。產生的libProcessImg.so的大小為4M,整個apk大小為1.99M。

注意,假設將mk裡的LOCAL_LDLIBS    += -lm -llog這一句錯誤的寫為:LOCAL_LDLIBS    := -lm -llog。即將“+=”錯寫成了“:=”將會看到例如以下大量錯誤:

$ ndk-buildAndroid NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 16 in ./AndroidManifest.xml[armeabi-v7a] Compile++ thumb: ProcessImg <= DetectFace_JNI.cppjni/DetectFace_JNI.cpp: In function ‘_jstring* Java_org_yan_processlib_LibProcessImg_processIplImg(JNIEnv*, jobject, jintArray, int, int)‘:jni/DetectFace_JNI.cpp:99:44: warning: converting ‘false‘ to pointer type for argument 2 of ‘jint* _JNIEnv::GetIntArrayElements(jintArray, jboolean*)‘ [-Wconversion-null]jni/DetectFace_JNI.cpp: In function ‘_jstring* Java_org_yan_processlib_LibProcessImg_processStaticImg(JNIEnv*, jobject, jintArray, int, int)‘:jni/DetectFace_JNI.cpp:133:44: warning: converting ‘false‘ to pointer type for argument 2 of ‘jint* _JNIEnv::GetIntArrayElements(jintArray, jboolean*)‘ [-Wconversion-null][armeabi-v7a] Compile++ thumb: ProcessImg <= copyToAssets.cpp[armeabi-v7a] Compile++ thumb: ProcessImg <= detectFace.cpp[armeabi-v7a] SharedLibrary  : libProcessImg.soD:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function icvGets(CvFileStorage*, char*, int):persistence.cpp(.text._ZL7icvGetsP13CvFileStoragePci+0x7e): error: undefined reference to ‘gzgets‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function icvXMLSkipSpaces(CvFileStorage*, char*, int):persistence.cpp(.text._ZL16icvXMLSkipSpacesP13CvFileStoragePci+0x1c4): error: undefined reference to ‘gzeof‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function icvYMLSkipSpaces(CvFileStorage*, char*, int, int) [clone .constprop.65]:persistence.cpp(.text._ZL16icvYMLSkipSpacesP13CvFileStoragePcii.constprop.65+0x122): error: undefined reference to ‘gzeof‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function icvPuts(CvFileStorage*, char const*):persistence.cpp(.text._ZL7icvPutsP13CvFileStoragePKc+0x32): error: undefined reference to ‘gzputs‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function icvClose(CvFileStorage*, std::string*):persistence.cpp(.text._ZL8icvCloseP13CvFileStoragePSs+0x132): error: undefined reference to ‘gzclose‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function cvOpenFileStorage:persistence.cpp(.text.cvOpenFileStorage+0x1ac): error: undefined reference to ‘gzrewind‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function cvOpenFileStorage:persistence.cpp(.text.cvOpenFileStorage+0x6d4): error: undefined reference to ‘gzclose‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function cvOpenFileStorage:persistence.cpp(.text.cvOpenFileStorage+0x75a): error: undefined reference to ‘gzopen‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function cvOpenFileStorage:persistence.cpp(.text.cvOpenFileStorage+0xd80): error: undefined reference to ‘gzclose‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../3rdparty/libs/armeabi-v7a/liblibpng.a(pngread.c.o): in function png_create_read_struct_2:pngread.c(.text.png_create_read_struct_2+0x112): error: undefined reference to ‘inflateInit_‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../3rdparty/libs/armeabi-v7a/liblibpng.a(pngread.c.o): in function png_read_row:pngread.c(.text.png_read_row+0x218): error: undefined reference to ‘inflate‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../3rdparty/libs/armeabi-v7a/liblibpng.a(pngread.c.o): in function png_read_destroy:pngread.c(.text.png_read_destroy+0x96): error: undefined reference to ‘inflateEnd‘D:/ProgramFile/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld.exe: D:/ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\/../3rdparty/libs/armeabi-v7a/liblibpng.a(pngwrite.c.o): in function png_write_flush:pngwrite.c(.text.png_write_flush+0x1c): error: undefined reference to ‘deflate‘
上兩張執行,各自是預覽介面檢測人臉和拍照後檢測:




二、Android以JNI調OpenCV的另外一種配置方法

Application.mk檔案同上。Android.mk檔案例如以下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

OpenCV_INSTALL_MODULES:=on
OPENCV_CAMERA_MODULES:=off
OPENCV_LIB_TYPE:=SHARE
ifeq ("$(wildcard $(OPENCV_MK_PATH))","")
include D:\ProgramFile\OpenCV-2.4.9-android-sdk\sdk\native\jni\OpenCV.mk
else  
include $(OPENCV_MK_PATH)  
endif 


LOCAL_MODULE    := ProcessImg 
LOCAL_SRC_FILES := DetectFace_JNI.cpp \
src/copyToAssets.cpp \
src/detectFace.cpp
LOCAL_LDLIBS    := -lm -llog 

OpenCV4Android釋疑: 透析Android以JNI調OpenCV的三種方式(讓OpenCVManager永不困擾)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.