阅读(1516) (0)

Android开发项目中使用OpenCV库

2017-08-25 13:59:50 更新

本教程的创建旨在帮助您在Android项目中使用OpenCV库。

本指南是用Windows 7编写的,虽然它应该与OpenCV4Android SDK支持的任何其他操作系统配合使用。

本教程假设您已经安装并配置了以下内容:

  • JDK
  • Android SDK和NDK
  • Eclipse IDE
  • Eclipse的ADT和CDT插件

如果您需要上述任何方面的帮助,您可以参考我们的Android开发入门指南。

本教程还假定您的开发机器上已经安装了OpenCV4Android SDK,并且相应地在测试设备上安装了OpenCV Manager。如果您需要任何帮助,可以咨询我们的OpenCV4Android SDK教程。

如果您在彻底按照这些步骤后遇到任何错误,请随时通过W3Cschool官方或OpenCV Q&A论坛与我们联系。我们将竭尽全力帮助您。

在您的Android项目中使用OpenCV库

在本节中,我们将介绍如何使一些现有项目使用OpenCV。从Android 2.4.2版本开始,OpenCV Manager用于为应用程序提供最佳可用版本的OpenCV。

Java的

应用程序开发与异步初始化

使用异步初始化是应用程序开发的推荐方法。它使用OpenCV Manager来访问目标系统中外部安装的OpenCV库。

1、将OpenCV库项目添加到您的工作区。在工作区中使用菜单File - > Import - > Existing project。

按浏览按钮,找到OpenCV4Android SDK(OpenCV-2.4.9-android-sdk/sdk)。

Android开发项目中使用OpenCV库

2、在项目 - >属性 - > Android - >库 - >添加选择OpenCV库 - 2.4.9中的应用程序项目中添加对OpenCV Java SDK的引用。

Android开发项目中使用OpenCV库

在大多数情况下,OpenCV Manager可能会从Google Play自动安装。对于这种情况,当Google Play不可用时,即仿真器,开发板等,您可以使用adb工具手动安装。看Manager Selection详情。

有一个非常基础的代码片段实现异步初始化。它显示基本原则。有关详细信息,请参阅“15拼图”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的本机库。在OpenCV成功初始化之后,加载自己的依赖于OpenCV的本地库。默认BaseLoaderCallback实现将应用程序上下文视为Activity,并在初始化失败的情况下调用Activity.finish()方法退出。要覆盖此行为,您需要覆盖BaseLoaderCallback类的finish()方法,并实现您自己的finalization方法。

静态初始化应用开发

根据这种方法,所有OpenCV二进制文件都包含在应用程序包中。它主要用于开发目的。对于生产代码,不建议使用此方法,因此推荐使用发行包,通过上述异步初始化与OpenCV Manager进行通信。

1、将OpenCV库项目添加到工作空间中,与上述异步初始化相同。使用菜单文件 - >导入 - >工作区中的现有项目,按浏览按钮并选择OpenCV SDK路径(OpenCV-2.4.9-android-sdk/sdk)。

Android开发项目中使用OpenCV库

2、在应用程序项目中,在项目 - >属性 - > Android - >库 - > Add中添加OpenCV4Android SDK的参考选择OpenCV Library - 2.4.9;

Android开发项目中使用OpenCV库

3、如果您的应用程序项目没有JNI部分,只需将相应的OpenCV本机库从<OpenCV-2.4.9-android-sdk>/sdk/native/libs/<target_arch>您的项目目录复制到文件夹即可libs/<target_arch>。

在具有JNI部分的应用程序项目的情况下,而不是手动库复制,您需要修改您的Android.mk文件:在“include $(CLEAR_VARS)”之后添加以下两个代码行,然后在“include path_to_OpenCV-2.4.9 -Android-SDK / SDK /本地/ JNI / OpenCV.mk”

OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on

结果应如下所示:

include $(CLEAR_VARS)
# OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
include ../../sdk/native/jni/OpenCV.mk

之后,libs在JNI build.v期间,OpenCV库将被复制到您的应用程序文件夹

Eclipse将自动将libs文件夹中的所有库包含到应用程序包(APK)中。

4、在应用程序中启用OpenCV的最后一步是调用OpenCV API之前的Java初始化代码。例如,可以在Activity类的静态部分中完成:

static {
    if (!OpenCVLoader.initDebug()) {
        // Handle initialization error
    }
}

如果您的应用程序包含其他基于OpenCV的本机库,则应 OpenCV初始化加载它们:

static {
    if (!OpenCVLoader.initDebug()) {
        // Handle initialization error
    } else {
        System.loadLibrary("my_jni_lib1");
        System.loadLibrary("my_jni_lib2");
    }
}

Native/C++

要构建您自己的Android应用程序,使用OpenCV作为本机部分,应采取以下步骤:

  1. 您可以使用环境变量来指定OpenCV包的位置,也可以在jni/Android.mk项目中硬编码绝对或相对路径。
  2. 该文件jni/Android.mk应使用通用规则此文件的当前应用程序被写入。有关详细信息,请参阅文件中的Android NDK归档的Android NDK文档<path_where_NDK_is_placed>/docs/ANDROID-MK.html。
  3. 以下行:
include C:\Work\OpenCV4Android\OpenCV-2.4.9-android-sdk\sdk\native\jni\OpenCV.mk

应在此行后插入jni/Android.mk文件:

include $(CLEAR_VARS)

   4、OpenCV Manager 可以使用多个变量来定制OpenCV,但是当您的应用程序通过OpenCV Manager API使用异步初始化时,您无需使用它们。

注意
这些变量应该在“include ... / OpenCV.mk”行之前设置
OPENCV_INSTALL_MODULES:=on

将必要的OpenCV动态库复制到项目libs文件夹中,以便将它们包含在APK中。

OPENCV_CAMERA_MODULES:=off

跳过本机OpenCV相机相关的libs复制到项目libs文件夹。

OPENCV_LIB_TYPE:=STATIC

执行与OpenCV的静态链接。默认使用动态链接,项目JNI lib依赖于libopencv_java.so。

    5、该文件Application.mk应该存在并应包含行:

APP_STL:= gnustl_static
APP_CPPFLAGS:= -frtti -fexceptions

另外,像这样的一行:

APP_ABI:= armeabi-v7a

应该指定应用程序目标平台。

在某些情况下,根据OpenCV构建应用程序JNI库时,会发生链接错误(如“函数”cv :: toUtf16(std :: basic_string <...> ...未定义的引用“mbstowcs”)以下行Application.mk通常会修复它:

APP_PLATFORM:= android-9

   6、或者使用手动的 ndk-build调用或者设置Eclipse CDT Builder来构建本地JNI库,然后(重新)构建Java部分并创建一个APK。

Hello OpenCV Sample

以下是引导您创建简单的以OpenCV为中心的应用程序的过程的基本步骤。它将能够访问摄像机输出,处理和显示结果。

  • 打开Eclipse IDE,创建一个新的干净工作区,创建一个新的Android项目文件 - >新建 - > Android项目
  • 相应地设置名称,目标,包和minSDKVersion。使用OpenCV4Android SDK构建的最小SDK版本为11.最小设备API级别(应用程序清单)为8。
  • 允许Eclipse创建默认活动。让我们将活动命名为HelloOpenCvActivity。
  • 选择全屏布局的空白活动。让我们命名布局HelloOpenCvLayout。
  • 将OpenCV库项目导入到您的工作区。
  • 在项目属性中引用OpenCV库。

Android开发项目中使用OpenCV库

  • 将您的布​​局文件编辑为xml文件,并在其中传递以下布局:
< LinearLayout  xmlns:android = “http://schemas.android.com/apk/res/android”
    xmlns:tools = “http://schemas.android.com/tools”
    xmlns:opencv = “http://schemas.android.com/apk/res-auto”
    android:layout_width = “match_parent”
    android:layout_height = “match_parent” >
    < org.opencv.android.JavaCameraView
        android:layout_width = “fill_parent”
        android:layout_height = “fill_parent”
        android:visibility = “gone”
        android:id = “@ + id / HelloOpenCvView”
        opencv:show_fps = “true”
        opencv:camera_id = “any” />
</ LinearLayout >
  • 将以下权限添加到AndroidManifest.xml文件中:
</ application >
< uses-permission  android:name = “android.permission.CAMERA” />
< uses-feature  android:name = “android.hardware.camera”  android:required = “false” />
< uses-feature  android:name = “android.hardware.camera.autofocus”  android:required = “false” />
< uses-feature  android:name = “android.hardware.camera.front”  android:required = “false” />
< uses-feature  android:name = “android.hardware.camera.front.autofocus”  android:required = “false” />
  • 在AndroidManifest.xml中设置应用程序主题以隐藏标题和系统按钮。
<application
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
  • 将OpenCV库初始化添加到您的活动中。通过添加必需的导入来修正错误
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);
}
  • 定义您的活动实现CvCameraViewListener2接口,并通过定义错过的方法来修复与活动相关的错误。对于此活动,定义onCreate,onDestroy和onPause,并根据下面的代码段来实现它们。通过添加必需的导入来修正错误
private CameraBridgeViewBase mOpenCvCameraView;
@Override
public void onCreate(Bundle savedInstanceState) {
    Log.i(TAG, "called onCreate");
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.HelloOpenCvLayout);
    mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.HelloOpenCvView);
    mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
    mOpenCvCameraView.setCvCameraViewListener(this);
}
@Override
public void onPause()
{
    super.onPause();
    if (mOpenCvCameraView != null)
        mOpenCvCameraView.disableView();
}
public void onDestroy() {
    super.onDestroy();
    if (mOpenCvCameraView != null)
        mOpenCvCameraView.disableView();
}
public void onCameraViewStarted(int width, int height) {
}
public void onCameraViewStopped() {
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    return inputFrame.rgba();
}
  • 在设备或模拟器上运行应用程序。

让我们讨论一些最重要的步骤。每个使用UI的Android应用程序都必须实现活动和查看。通过第一步,我们创建空白活动和默认视图布局。最简单的以OpenCV为中心的应用程序必须实现OpenCV初始化,创建自己的视图来显示来自相机的预览,并实现CvCameraViewListener2接口从相机获取帧并处理它。

首先,我们使用xml布局创建我们的应用程序视图。我们的布局由org.opencv.android.JavaCameraView类中唯一的全屏组件组成。这个类在OpenCV库中实现。它继承自CameraBridgeViewBase,它扩展了SurfaceView并使用了标准的Android相机API。

创建布局后,我们需要实现Activity类。OpenCV初始化过程已经在上面讨论过了。在本例中,我们使用异步初始化。CvCameraViewListener接口的实现允许您在从相机抓取并在屏幕上渲染之前添加处理步骤。最重要的功能是onCameraFrame。它是回调函数,它在从摄像机检索帧时被调用。回调输入是表示来自相机的帧的CvCameraViewFrame类的对象。

注意
不要保存或使用CvCameraViewFrame对象从onCameraFrame回调。这个对象没有自己的状态,它的回调行为是不可预测的!

它具有rgba()和gray()方法,可以分别获取帧为RGBA和一个通道灰度Mat。它期望onCameraFrame函数返回将在屏幕上绘制的RGBA帧。