注:本篇文章做者已再也不维护
,由于如今大都以Android Studio进行开发。后续只维护Android Studio篇。
若是你坚持使用Eclipse,请确保全部环境与本文一致。java
本教程是通过本人屡次踩坑,并结合网上众多OpenCV On Android的配置教程总结而来,尽但愿能帮助学习OpenCV的朋友们少走弯路。若是配置上遇到问题,可在评论中留言,我将尽力帮助解决。
linux
若是您使用的是Android Studio,请参考下一章OpenCV On Android最佳环境配置指南(Android studio篇)。android
若有转载,请标明出处c++
注:以上配置基本上为最新版本。其中,Eclipse可与Android Studio共用一个NDK,但SDK不能通用,不然你将不能在eclipse上正确建立Android项目。程序员
首先建立一个普通的Android应用,须要注意的是,咱们须要将Minimum Required SDK设置为API15及以上
,这样既能兼容市面上95%的Android手机,又不会引入潜在的错误。若是此处出现错误,请确保你的JDK、ADT和SDK是否配置正确。编程
这里我建立名为OpenCVDemo
的项目,包名为com.demo.opencv
,OK。windows
第一步:Eclipse菜单->File->Import->Android->Existing Android Code Into Workspace
,而后导入OpenCV Android SDK\sdk\java 这个目录。markdown
为了防止误操做OpenCV库,建议勾选Copy project into workspace
,将该库copy到你的工做文件夹,而后点击Finish。架构
若是导入后出现错误,请将Project build Target
设置为Android5.0
以上(由于通常是Camera2报错,Camera2只存在于Android5.0+)。具体步骤为:eclipse
项目鼠标右键,选择
Properties -> Android
,勾选 Android5.0 以上的版本便可,而后Apply and Close
。
这里我选择的是5.0.1。
第二步:仍是进入上一步的页面,点击Library
里的Add
按钮,添加 OpenCV 库,完成后,你的项目即可以调用到 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,内容以下:
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, 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 Manager.apk
。
位于OpenCV-android-sdk\apk目录下,选择合适的apk程序安装(通常选择OpenCV_3.2.0_Manager_3.20_armeabi.apk
)。
将项目编译打包成apk,安装到手机,运行,点击按钮show后,对图像进行灰度处理,效果以下图所示:
注意:
OpenCV was not initialised correctly.Application will be shut down
,多是你的OpenCV Manager程序与你的cpu架构不一样,选择合适的apk便可。OpenCV Manager
的状况,这是由于手机厂商作了限制,防止恶意软件相互唤醒(如百度全家桶),解决方法请自行百度(由于没有统一的方法)。安装一个额外的apk对用户来讲很是不友好,但使用C/C++编程,又对一些Java程序员又提升了实现难度,故咱们应该想一个一箭双鵰的方法,即帮助开发人员使用 Java 快速开发,又无需让用户安装额外的软件。
思路:
Java库实际上只是对NDK库进行java封装,将so文件放在OpenCV Manager内,经过AIDL进行交互,从而实现图像处理。
解决方案:
若是咱们将OpenCV Manager里面的so文件直接打包到咱们的应用里,不就能抛弃OpenCV Manager了吗?
没错,就是这样,而且 OpenCV 官方也给咱们提供了现成的so文件,只需将OpenCV-android-sdk\sdk\native\libs\[ARM架构]\
目录下(通常采用armeabi-v7a
便可)的libopencv_java3.so
,放到你的项目libs\[ARM架构]\
目录下,如图所示:
而后在你的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");
}
......下面内容不变
}
复制代码
编译并安装,这时候,你就能够将你的 OpenCV Manager 卸载掉了。运行结果与以前的无异。
注意
: 此方法并非完美的,由于在这个程序里,你只实现了图像的灰度处理,但却引入了libopencv_java3.so
这个so文件,apk足足有4.39M,相比以前的194k来讲,接近增加了20倍。除非你的应用比较大,而这个so文件的大小是固定的,此时采用此方法也是一个不错的选择。
第一步: 配置NDK路径
进入菜单->Window->Preferences->Android->NDK
,设置NDK Location
,注:请确保该路径下存在ndk-build.cmd
文件。以下图:
第二步: 配置JNI环境
这里咱们经过导入配置文件进行配置:
Android Tools->Add native support->输入合适的名称->肯定
,这里我直接使用默认名称。修改其中的路径为你ndk库对应的路径
。<?xml version="1.0" encoding="UTF-8"?>
<cdtprojectproperties>
<section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
<language name="c,cpp">
<includepath>D:\AndroidSDK\AndroidStudio\ndk-bundle\sysroot\usr\include</includepath>
<includepath>D:\AndroidSDK\AndroidStudio\ndk-bundle\sources\cxx-stl\gnu-libstdc++\4.9\include</includepath>
<includepath>D:\OpenCV\OpenCV-android-sdk\sdk\native\jni\include</includepath>
<includepath>D:\AndroidSDK\AndroidStudio\ndk-bundle\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\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
,环境就导入成功了。
第三步: 检查环境是否正确
不为灰色
(以下图),而且都能展开
。进入jni目录,打开OpenCVDemo.cpp,在#include<jni.h>
上使用Ctrl+鼠标左键
,若是eclipse能打开jni.h
文件,说明你的JNI环境就搭建成功了。
第四步: 配置OpenCV NDK环境
Android.mk
文件,注意修改OPENCV_ANDROID_SDK
为你的OpenCV路径,并阅读我添加的注释。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)
复制代码
Application.mk
文件,内容以下:APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := all
APP_PLATFORM := android-15
APP_OPTIM := debug
复制代码
至此,NDK环境就配置完毕。
布局文件仍是采用以前的布局文件,修改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;
}
}
}
}
复制代码
能够看到,MainActivity与以前修改不大。
而后是 OpenCV_NDK.java 内容以下:
public class OpenCV_NDK {
static {
System.loadLibrary("OpenCVDemo");
}
native void toGary(Object bitmap);
}
复制代码
是否是很是简单!
如今只须要为toGary()
这个native
方法生成头文件,这一步须要使用到javah
命令,具体用法,请参考百度。
而后将 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,我也比较推荐使用NDK开发OpenCV应用程序。
假设你已经看了前两种配置,习惯于Java开发,但又以为OpenCV Java库提供的方法不够,但愿使用混合开发,那恭喜你,这一部分就是你所须要的。
这部份内容不多,总结起来就两部分:
OPENCV_BULID_TYPE
由NDK
修改成JAVA_AND_NDK
。通过上述步骤,在编译时,系统会将你的native
代码生成libOpenCVDemo.so
文件,同时也会将libopencv_java3.so
放入你的libs
目录下。如图:
这样就轻易实现了java和c\c++混合处理图像,同时不用安装OpenCV Manager,而且自动导入libopencv_java3.so
。注意:加载so文件的代码必须写
。
本教程致力于帮助OpenCV新人快速配置,可能有不足之处,接受你们的建议与批评,后续将进行补充和改进。
同时欢迎你们一块儿探讨Android图像处理的知识,共同进步。