这篇指南用于帮助你在你的Android项目中使用OpenCV。
请记住这篇指南是基于Windows 7所写的,尽管它应该适用于OpenCV4Android SDK所支持的其他OS平台。
这篇指南假设你已经安装并配置了下列程序:
JDK
Android SDK and NDK
Eclipse IDE
ADT and CDT plugins for Eclipse
关于上面的程序,如有任何需要帮助的,你可以参考我们的_Introduction into Android Development_指南。
这份指南也假设你已经在你的开发机上安装了OpenCV4Android SDK,并在你的测试设备上安装了对应OpenCV Manager。关于这些,如果你有任何需要帮助的,可以参考我们的OpenCV4Android SDK指南。
如果你完全按照这些步骤做了,但仍然遇到了error,请通过OpenCV4Android讨论组或OpenCVQ&A forum和我们联系。我们将尽力为你提供帮助。
在你的Android项目中使用OpenCV库
在这一节中我们将解释如何在已有的项目中使用OpenCV。自Android的2.4.2 release开始,_OpenCV Manager_被用于给apps提供OpenCV的最好的可用版本。你可以在此处获取更多信息:Android OpenCV Manager和这些slides中。
Java
Application Development with Async Initialization
建议在应用开发中使用异步的方式来初始化。它使用OpenCV Manager来访问目标系统中外部安装(大概指库不是安装在应用程序中的)的OpenCV库。
把OpenCV库添加进你的workspace中。 使用菜单_File -> Import -> Existing project in your workspace_.
点_Browse_按钮并定位到OpenCV4Android SDK (OpenCV-2.4.9-android-sdk/sdk)。
在应用程序项目中添加一个对OpenCV Java SDK的引用:Project -> Properties -> Android -> Library -> Add 选择OpenCV Library - 2.4.9.
在大多数情况下,OpenCV Manager可能自动的由Google Play安装了。对于那些Google Play不可用的情况,比如模拟器,开发板,等等,你可以使用adb工具手动安装它。参考How to select the proper version of OpenCV Manager来获取详细信息。
有一个简单的代码片段实现了异步初始化。它演示了基本的原理。参考“15-puzzle” OpenCV示例来获取更多信息。
public class Sample1Java extends Activity implements CvCameraViewListener {
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
@Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback);
}
...
}
在这个例子中,应用程序以异步的方式与OpenCV Manager协同工作。OnManagerConnected将在初始话结束时,在UI线程中被调用。请注意,在调用这个回调之前,不允许使用OpenCV调用或者加载OpenCV-dependent native库。请在OpenCV初始化成功之后再加载你自己的依赖于OpenCV的native库。默认的BaseLoaderCallback实现将application context看作是Activity,并会在初始化失败时调用Activity.finish()方法来退出。要覆写这一行为,你需要覆写BaseLoaderCallback类的finish()方法并实现你自己的初始化方法。
Application Development with Static Initialization
以这种方法,所有的OpenCV binaries会被包含进你的应用包中。这种方法主要设计来在开发的时候使用。对于产品代码,这种方法是不推荐的,在release包中建议通过上面描述的异步初始化与OpenCV Manager通信。
- 以与添加上面的异步初始化部分相同的方式将OpenCV library工程添加到你的workspace中。使用菜单_File -> Import -> Existing project in your workspace_, 点击 _Browse_按钮并选择OpenCV SDK path (OpenCV-2.4.9-android-sdk/sdk).
![Add dependency from OpenCV library](http://static.oschina.net/uploads/img/201407/07095253_5q59.png)
在应用程序工程中添加一个对OpenCV4Android SDK的引用_Project -> Properties -> Android -> Library -> Add_ 选中OpenCV Library - 2.4.9;
如果你的应用程序没有没有JNI部分,可以只是把对应的OpenCV native libs从<OpenCV-2.4.9-android-sdk>/sdk/native/libs/<target_arch> to复制到你的工程的libs/<target_arch>目录下。
在应用程序中有JNI部分的情况下,则你需要修改你的Android.mk文件而不是手动的libraries复制:把下面的两行代码添加在"include $(CLEAR_VARS)"之后及"include path_to_OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk"之前。
结果看起来应该像下面这样:
随后OpenCV libraries将在JNI编译期间被复制到你的应用的libs目录下。
Eclipse将会自动地把libs目录下的所有libraries包含进应用程序包中(APK)。
在你的应用程序中启用OpenCV的最后一步是在调用OpenCV API之前进行Java初始化。这可以通过在,比如,在Activity类的static部分完成:
如果你的应用程序包含其他OpenCV-dependent native libraries的话,你应该在OpenCV初始化之后加载它们:
Native/C++
要把OpenCV作为native部分,来构建你自己的Android应用,则应该依照下面的步骤来做:
你可以在你的工程的jni/Android.mk中使用一个环境变量来指定OpenCV包的位置,或者只是硬编码绝对或相对路径。
为当前应用程序所写的jni/Android.mk应该使用这类文件的通用规则来写。
要获取详细的信息请参考Android NDK包中的Android NDK文档,在文件<path_where_NDK_is_placed>/docs/ANDROID-MK.html中。
下面的这一行:
应该被插入jni/Android.mk文件中这一行的后面:
有些变量可以被用来定制OpenCV stuff,但当你的应用程序通过OpenCV Manager API使用异步初始化initialization时,则不需要使用它们。
注意
这些变量应该在"include .../OpenCV.mk"行之前设置:
复制必须的OpenCV动态库到工程的libs目录下以使它们被包含进APK中。
跳过把OpenCV camera相关libs复制到项目的libs目录下。
执行对OpenCV的静态链接。默认情况下使用动态链接,并且工程的JNI lib会依赖于libopencv_java.so。
应该有Application.mk文件,并且其中应该包含这几行:
也要包含如下的这一行:
应该指定应用程序的目标平台。有些情况下,依赖于OpenCV,当编译一个应用程序的JNI库时,会有一个linkage error (比如"In function 'cv::toUtf16(std::basic_string<...>... undefined reference to'mbstowcs'")出现。Application.mk中下面的这一行通常可以解决它:
在(重)编译Java部分并创建一个APK之前,_手动_使用ndk-build调用或者设置 Eclipse CDT Builder 来编译native JNI lib。
Hello OpenCV Sample
创建一个简单的OpenCV-centric应用程序的过程。它将能够访问camera输出,处理它并显示结果。
打开Eclipse IDE,创建一个新的干净的workspace,创建一个新的Android工程_File ‣ New ‣ Android Project_
相应地设置name,target,及minSDKVersion。编译OpenCV4Android SDK的最小的SDK版本是11。最小的设备API Level (for application manifest)是8。
允许Eclipse创建默认的activity。将activity命名为HelloOpenCvActivity。
选择full screen layout的Blank Activity。将layout命名为HelloOpenCvLayout。
把OpenCV library工程导入到你的workspace中。
在你的工程属性中引用OpenCV library。
编辑你的layout xml文件,并使用下面的layout:
给AndroidManifest.xml文件添加如下的permissions:
在AndroidManifest.xml中设置application theme来隐藏标题栏及系统按钮。
把OpenCV library初始化的部分加入你的activity。通过加入所需的imports来解决errors。
![](http://static.oschina.net/uploads/space/2014/0707/112209_2Jb1_919237.png)
- 定义你的activity实现CvCameraViewListener2接口,并通过定义遗漏的方法来解决activity有关的errors。为这个activity定义onCreate,onDestroy和onPause并根据下面的代码片段实现它们。通过添加所需的imports来解决errors。
![](http://static.oschina.net/uploads/space/2014/0707/112344_zJyI_919237.png)
- 在设备或模拟器上运行你的应用程序。
让我们讨论一些最重要的步骤。每一个有UI的Android应用必须实现Activity和View。通过第一步,我们创建了空的activity和默认的view layout。最简单的OpenCV-centric应用必须实现OpenCV初始化,创建它自己view来显示来自于camera的preview,并实现CvCameraViewListener2接口来从camera获取framew并处理它。
首先我们使用xml layout来创建我们应用程序的view。我们的layout只由一个full screen 组件opencv.android.JavaCameraView组成。这个类是在OpenCV库中实现的。它继承自CameraBridgeViewBase,而后者则继承自SurfaceView并使用了标准的Android camera API。你也可以使用org.opencv.android.NativeCameraView类,它实现了相同的接口,但使用了VideoCapture来作为camera访问的后端。opencv:show_fps="true" andopencv:camera_id="any"选项启用FPS消息,并允许使用设备上的任何的camera。应用程序会首先尝试使用后置camera。
创建了layout之后,我们需要实现Activity类。OpenCV初始化过程已经在上面讨论过了。在这个例子中我们使用了异步的初始化。CvCameraViewListener接口的实现允许你在从camera获取了frame之后而在把会渲染在屏幕上之前执行一定的处理。最重要的函数是onCameraFrame。它是回调函数,当从camera提取了frame时会被调用。回调的输入是CvCameraViewFrame类的对象,其表示从camera获取的frame。
注意
不要保存或在onCameraFrame回调之外使用CvCameraViewFrame对象。这个对象没有它自己的状态,并且在回调之外它的行为是不可预测的!
它有rgba()和gray()方法,以分别允许以RGBA的形式和单通道灰度Mat获取frame。它期望onCameraFrame函数返回将在屏幕上绘制的RGBA frame。
Done.