本教程是通过本人屡次踩坑,并参考网上众多OpenCV On Android的配置教程总结而来,尽但愿能帮助学习移动图像处理的朋友们少走弯路。
这也是本人第一次在简书上发布文章,若有不足,但愿各位dalao可以指正,我也将及时修改。配置上若是遇到问题,也能够在评论里留言,我将尽力帮助解决。
若有转载,请标明出处http://www.jianshu.com/p/b260ebb1c180。
若是您使用的是android studio,请参考下一章OpenCV On Android环境配置最新&最全指南(Android studio篇)。java
电脑:Windows10
Java:jdk1.8.0_131
Eclipse:Neon.3 Release (4.6.3)
ADT:ADT-23.0.7
NDK:Android Studio2.3自带的最新NDK
OpenCV:V3.2.0
SDK:25.2.5 (单独下载,请不要与Android Studio同用,不然你将不能在eclipse上正确建立Android项目)linux
注:以上配置基本上为最新版本android
这里只需建立普通Eclipse Android项目工程,没什么重要的地方可说的,若是这都不会,建议先把Android基础学好。这里我建立的是名为OpenCVDemo的项目,包名为com.demo.opencv。c++
一、若是你只想用在应用层编写程序的话,请直接阅读下面OpenCV Java库使用指南;
二、若是只想在原生层快速进行图像处理的话,请直接跳到下面OpenCV NDK库使用指南;
三、若是想同时使用OpenCV Java库和Native库的话,请参考OpenCV 混合使用指南;
接下来我简要介绍二者的区别与优缺点。程序员
简而言之,若是使用OpenCV Java库,你只需在应用层使用Java语言编写代码,由OpenCV Java库经过AIDL链接OpenCV Manager进行图像处理。
若是你使用的OpenCV NDK库,就能在原生层使用C/C++编写代码,此时就涉及到JNI。
虽然二者使用的编程语言不一样,但最终结果都是在原生层实现图像处理功能,由于OpenCV Java库只是将原生代码(C/C++)用Java封装(JNI)好,并打包成so文件,存入OpenCV Manager里,外部应用经过AIDL进行调用,这就是为何使用Java库时必需要额外安装OpenCV Manager的缘由了。不过我将会在OpenCV Java库使用指南中介绍一个不须要安装OpenCV Manager的方法,弥补其不足,同时OpenCV 混合使用指南则提供一个更为简便的方法。编程
Java库的缺点:
若是使用Java库的话,手机上除了安装你编写的应用外,还须要额外安装OpenCV Manager文件,其位于OpenCV Android SDK/apk/目录下,请根据你编写的apk架构(若是你仅使用Java开发,则能够不用考虑apk架构)和你手机cup架构选择对应的apk文件,通常这两个选择armeabi架构便能兼容绝大多数的手机。
Java库的优势:
一、不须要C/C++的功底便能轻松实如今Android客户端的图像处理,很是适合只会Java语言的编程人员。
二、由于有两个应用(本身编写的程序和OpenCV Manager),你将得到更多的内存处理空间(一个Android应用默认分配内存上限为24M)。
三、Java库封装了几个摄像头显示控件,如:JavaCameraView,NativeCameraView(目前OpenCV3.2里该控件已经被取消),咱们使用少许代码就能实现摄像头数据采集->处理->显示等一系列操做。
NDK库的优势:
一、若是使用Native库的话,你能够彻底抛弃OpenCV Manager的安装,同时因为在底层进行图像处理,其处理速度会增长(但因为Android高版本的优化,加上OpenCV Java库其实也是在调用其原始层的库,因此这种差距并不明显)。
二、使用NDK库的话,需采用C\C++进行编程,此方法更便于从Visual Studio进行程序移植。
NDK库的缺点:
须要必定的C\C++功底,若是涉及到调用摄像头,需自行编写缓冲框架,避免数据帧堵塞。同时必须熟悉JNI的函数操做,什么时候释放内存和引用等等。若是你想在底层进行OpenGL ES渲染图像,还需对Android底层和OpenGL ES有必定了解(但前者并非必须的)。windows
第一步:Eclipse菜单->File->Import->Android->Existing Android Code Into Workspace(若是没此选项,请确保你的eclipse 上ADT是否配置正确),而后导入OpenCV Android SDK\ sdk\java这个项目。架构
为了防止误操做OpenCV库,建议勾选Copy project into workspace,将该库copy到你的工做文件夹。而后Finish,若是导入后出现报错,请将Project build Target设置为Android5.0以上(由于通常是Camera2报错,Camera2只存在于Android5.0+),具体方法是项目鼠标右键,选择Properties,而后点击Android,选择Android5.0以上的版本便可,而后OK,这里我选择的是6.0。框架
第二步:在你的项目右键也进入上图的页面,Library选择Add,添加OpenCV库(以下图),OK后,你的项目将可使用OpenCV Java函数了。eclipse
建立一个Java图像处理类OpenCV_Java .java(请忽略个人命名)
OpenCV_Java .java内容:
public class OpenCV_Java extends BaseLoaderCallback { private boolean isInit = false; private Context context; public OpenCV_Java(Context context){ super(context); this.context = context; } @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: isInit = true; break; default: isInit = false; super.onManagerConnected(status); break; } } public void toGary(Bitmap bitmap){ if(isInit){ Mat mat = new Mat(); Utils.bitmapToMat(bitmap, mat); Imgproc.cvtColor(mat, mat,Imgproc.COLOR_RGBA2GRAY ); Utils.matToBitmap(mat, bitmap); }else{ Toast.makeText(context, "OpenCV init error", Toast.LENGTH_LONG).show(); } } }
MainActivity.java内容:
public class MainActivity extends Activity implements OnClickListener { private ImageView imageView; private Bitmap bitmap; private Button showBtn, processBtn; private OpenCV_Java javaUtil = new OpenCV_Java(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.imageView); showBtn = (Button) findViewById(R.id.show); showBtn.setOnClickListener(this); processBtn = (Button) findViewById(R.id.process); processBtn.setOnClickListener(this); } @Override public void onResume() { super.onResume(); if (!OpenCVLoader.initDebug()) { OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_2_0, this, javaUtil); } else { javaUtil.onManagerConnected(LoaderCallbackInterface.SUCCESS); } } @Override public void onClick(View v) { if (v == showBtn) { bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); imageView.setImageBitmap(bitmap); } else { if (bitmap != null) {//避免二次处理 javaUtil.toGary(bitmap); imageView.setImageBitmap(bitmap); bitmap = null; } } } }
布局内容:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" > <Button android:id="@+id/show" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="show"/> <Button android:id="@+id/process" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="process"/> </LinearLayout> </RelativeLayout>
其位置位于OpenCV-android-sdk\apk目录下,选择合适的apk程序,通常选择OpenCV_3.2.0_Manager_3.20_armeabi.apk便可。
将项目编译打包成apk,安装到手机,运行,点击按钮show后,其效果如图所示:
点击按钮process,将其转化为灰度图,以下所示:
而后在你的MainActivity.java里面静态加载这个so库
public class MainActivity extends Activity implements OnClickListener { private ImageView imageView; private Bitmap bitmap; private Button showBtn, processBtn; private OpenCV_Java javaUtil = new OpenCV_Java(this); static{ System.loadLibrary("opencv_java3"); } @Override protected void onCreate(Bundle savedInstanceState) { ......下面内容不变
编译并安装,这时候,你就能够将你的OpenCV Manager卸载掉了。运行结果与以前的无异。
此方法并非完美的,由于在这个程序里,你只实现了彩色图像变灰度图像,但你却安装了这个原生库,apk足足有4.39M,相比以前的194k来讲,接近增加了20倍。但若是你的应用比较大,而这个so文件的大小是固定的,此时采用此方法将是一个不错的选择。
第一步:配置NDK环境
进入菜单->Window->Preferences->Android->NDK,设置NDK Location路径,注:请确保该路径下存在ndk-build.cmd文件。以下图:
第二步:配置JNI环境
这里我将使用简便方法快速配置:
一、在你的项目右键Android Tools->Add native support->输入合适的名称->肯定,这里我就直接使用默认的"OpenCVDemo"。
二、本地新建一个xml文件,将下面内容copy进去,修改其中的路径。
<?xml version="1.0" encoding="UTF-8"?> <cdtprojectproperties> <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths"> <language name="c,cpp"> <includepath>D:/Android/android-sdk/ndk-bundle/platforms/android-9/arch-arm/usr/include</includepath> <includepath>D:/Android/android-sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include</includepath> <includepath>D:/Android/android-sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi/include</includepath> <includepath>D:/Android/android-sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/include</includepath> <includepath>D:/Android/android-sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/include</includepath> <includepath>D:/OpenCV/OpenCV-android-sdk/sdk/native/jni/include</includepath> </language> </section> <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros"> <language name="c,cpp"> </language> </section> </cdtprojectproperties>
三、项目右键选择最后一个Properties,而后选择C/C++ General -> Path and Symbols,如图所示:
点击Import Settings->Browse,在电脑本地选择上面的xml文件,点击Finish,环境就导入成功了。
接下来查看环境是否正确。
一、查看路径是否存在:按照下图,将编译器切换到C/C++编辑器模式:
展开项目,查看Include目录下路径是否为灰色(以下图),而且都能展开,若是都知足,表示路径都存在。
二、查看环境是否正常。进入jni目录,打开OpenCVDemo.cpp,在#include<jni.h>这句代码上使用Ctrl+鼠标左键,若是eclipse能打开jni.h这个文件,说明你的JNI环境就搭建成功了。
第二步:配置OpenCV NDK环境
一、将下面内容copy进Android.mk文件,其中OPENCV_ANDROID_SDK 请设置为正确路径,同时请注意我在清单文件里的注释。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # ########################################################### #这里改为你的路径,分割线内其他内容不变 OPENCV_ANDROID_SDK := D:/OpenCV/opencv_android_sdk #OPENCV_BULID_TYPE := NDK #默认NDK环境,不会自动导入openCV_java3.so,故不支持OpenCV Java库 OPENCV_BULID_TYPE := JAVA_AND_NDK #将自动导入openCV_java3.so,来支持Java库(无需安装OpenCV Manager) ifeq ($(OPENCV_BULID_TYPE), JAVA_AND_NDK) OPENCV_LIB_TYPE := SHARED OPENCV_INSTALL_MODULES := on else OPENCV_LIB_TYPE := STATIC endif ifdef OPENCV_ANDROID_SDK ifneq ("","$(wildcard $(OPENCV_ANDROID_SDK)/OpenCV.mk)") include ${OPENCV_ANDROID_SDK}/OpenCV.mk else include ${OPENCV_ANDROID_SDK}/sdk/native/jni/OpenCV.mk endif else include ../../sdk/native/jni/OpenCV.mk endif # ########################################################### #动态连接日志库 LOCAL_LDLIBS += -llog -ljnigraphics LOCAL_MODULE := OpenCVDemo LOCAL_SRC_FILES := OpenCVDemo.cpp include $(BUILD_SHARED_LIBRARY)
二、在jni目录下增长Application.mk文件
其内容以下:
APP_STL := gnustl_static APP_CPPFLAGS := -frtti -fexceptions APP_ABI := armeabi APP_PLATFORM := android-8 APP_OPTIM := debug
到此为止,NDK环境配置完毕。
布局文件与上面的Java Demo无异,MainActivity.java内容以下:
public class MainActivity extends Activity implements OnClickListener { private ImageView imageView; private Bitmap bitmap; private Button showBtn, processBtn; private OpenCV_NDK nativeUtil = new OpenCV_NDK(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.imageView); showBtn = (Button) findViewById(R.id.show); showBtn.setOnClickListener(this); processBtn = (Button) findViewById(R.id.process); processBtn.setOnClickListener(this); } @Override public void onClick(View v) { if (v == showBtn) { bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); imageView.setImageBitmap(bitmap); } else { if (bitmap != null) { nativeUtil.toGary(bitmap); imageView.setImageBitmap(bitmap); bitmap = null; } } } }
这里能够看出并没有太大的改变。其中OpenCV_NDK.java内容以下:
public class OpenCV_NDK { static{ System.loadLibrary("OpenCVDemo"); } native void toGary(Object bitmap); }
是否是特别简单^_^。而后在控制台使用javah命令将其生成jni头文件,此处我用的一键生成(参考了《Android C高级编程 使用NDK》),Eclipse配置以下:
菜单Run->External Tools->External Tools Configurations,双击Program,右侧将产生新界面。配置以下:
Main选项卡里
Name:Generate C and C++ HeaderFile
Location:${system_path:javah}
Working Directory:${project_loc}/jni
Arguments:-classpath "${project_classpath};
${env_var:ANDROID_SDK_HOME}/platforms/android-14/android.jar" ${java_type_name}
切换到Refresh选项卡:
选中Refresh resource up completion,并在列表里选择The project containing the selected resource
切换到Common选项卡,勾选上External Tools。
配置完成(上面的配置按照实际状况修改,本人建议仍是使用javah命令生成头文件)
其中ANDROID_SDK_HOME是我在电脑环境配置里建立的一个变量,指向的是sdk路径。
而后将你的鼠标点中OpenCV_NDK.java,而后点击如图所示位置:
几秒后,将生成com_demo_opencv_OpenCV_NDK.h头文件(这个文件名跟你包名和类名有关)。
将OpenCVDemo.cpp修改成以下内容:
#include "com_demo_opencv_OpenCV_NDK.h" #include <opencv2/opencv.hpp> #include <android/bitmap.h> using namespace cv; JNIEXPORT void JNICALL Java_com_demo_opencv_OpenCV_1NDK_toGary (JNIEnv *env, jobject thiz, jobject bitmap){ AndroidBitmapInfo bitmapInfo; void* bitmapPixels; int width, height, ret; //解析bitmap if ((ret = AndroidBitmap_getInfo(env, bitmap, &bitmapInfo)) < 0) { return; } if (bitmapInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { return ; } if ((ret = AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels)) < 0) { return; } width = bitmapInfo.width; height = bitmapInfo.height; Mat bgra(height, width, CV_8UC4, bitmapPixels); Mat gary; cvtColor(bgra,gary,COLOR_RGBA2GRAY); cvtColor(gary,bgra,COLOR_GRAY2BGRA); AndroidBitmap_unlockPixels(env, bitmap); }
而后编译运行,结果与Java运行结果无异,无需安装OpenCV Manager,此方法编译的安装包只有951kb,图像处理时间本人并无计算,应该相差无几。
假设你已经看了前两种配置,习惯于Java开发,但又以为OpenCV Java库提供的方法不够,但愿使用混合开发,那恭喜你,这一部分就是你所须要的。这部份内容不多,总结起来就两部分:
一、导入OpenCV Java库并关联你的应用,参考OpenCV Java库使用指南(记得写静态加载so库的内容,但so文件不须要你手动导入)。
二、配置JNI环境与NDK环境,参考OpenCV NDK库使用指南。
三、修改Android.mk文件内容:OPENCV_BULID_TYPE := NDK为OPENCV_BULID_TYPE := JAVA_AND_NDK。
而后编译,这时候Android.mk会打包你的原生代码成libOpenCVDemo.so文件,并将其与libopencv_java3.so同时放入你的libs目录。
如图:
这样就轻易实现免安装OpenCV Manager,进行java和c++混合处理图像,同时免于手动导入libopencv_java3.so,注意:静态导入so的代码必须有。
本教程致力于帮助OpenCV新人快速配置,可能有不足之处,接受你们的建议与批评,后续将进行补充和改进。同时欢迎你们一块儿探讨Android图像处理的知识,共同进步。