OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)

前文曾具体探讨了关于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-build
Android 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.cpp
jni/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-build
Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 16 in ./AndroidManifest.xml
[armeabi-v7a] Compile++ thumb: ProcessImg <= DetectFace_JNI.cpp
jni/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
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 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

时间: 2024-10-13 07:10:17

OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)的相关文章

android 自定义控件中获取属性的三种方式(转)

第一种方法,直接设置属性值,通过attrs.getAttributeResourceValue拿到这个属性值. (1)在xml文件中设置属性值 <com.example.activity.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/smile1" iconSrc="

Android Button点击事件的三种方式

一.在XML中 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <!-- 现行排序 -->> xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"<!-- 全屏覆盖 -->> android:lay

Android 引用文件(.db)的三种方式

1.assets —— 资产目录(该目录中的文件会被直接打包到 apk 文件中).获取该目录下的文件的方式是: InputStream is = getContext().getAssets().open("naddress.db"); 2.res 下的 raw 的目录.获取该目录下的文件的方式是: InputStream is = getContext().getResources().openRawResource(R.raw.naddress); 3.采用类加载器使用一个资源文件

Android设置ScrollView回到顶部的三种方式 (转)

一.ScrollView.scrollTo(0,0)  直接置顶,瞬间回到顶部,没有滚动过程,其中Y值可以设置为大于0的值,使Scrollview停在指定位置; 二.ScrollView.fullScroll(View.FOCUS_UP)  类似于手动拖回顶部,有滚动过程; 三.ScrollView.smoothScrollTo(0, 0) 类似于手动拖回顶部,有滚动过程,其中Y值可以设置为大于0的值,使Scrollview停在指定位置. 转自:http://blog.csdn.net/xuan

android中填充界面布局的三种方式

改变原来界面布局的三种方式: 1.第一种方式: LayoutInflater li = LayoutInflater.from(this); 具体代码: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activ

android中给用户提醒的三种方式

一.Toast // 弹出吐司   Toast.makeText(getApplicationContext(), "吐司", 0).show(); 二.对话框:    1.确定取消对话框  public void click1(View view){        //对话框的创建器        AlertDialog.Builder builder = new Builder(this);        builder.setTitle("我是对话框");  

Android之LayoutInflater三种方式分析

获取LayoutInflater有三种不同的方式,那么这三种方式有什么区别呢? 源码: ① LayoutInflater inflater = LayoutInflater.from(context);  (LayoutInflater类) <span style="font-size:14px;">public static LayoutInflater from(Context context) { LayoutInflater LayoutInflater = (La

Android开发之onClick事件的三种写法(转)

1 package a.a; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.widget.Button; 7 import android.widget.EditText; 8 9 public class AActivity extends Activity { 10 /** Called when the activity is

android解析XML总结-SAX、Pull、Dom三种方式

在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX.Pull.Dom解析方式.最近做了一个android版的CSDN阅读器,用到了其中的两种(sax,pull),今天对android解析xml的这三种方式进行一次总结. xml示例(channels.xml)如下: <?xml version="1.0" encoding="utf-8"?> <channel> <item id="0&q