OpenCV  4.10.0
开源计算机视觉
正在加载...
正在搜索...
无匹配项
使用 OpenCV 进行 Android 开发

上一教程: Android 开发入门
下一教程: 如何在 Android 设备上运行深度网络

原始作者Alexander Panov、Rostislav Vasilikhin
兼容性OpenCV >= 4.9.0

创建本教程是为了帮助你在 Android 项目中使用 OpenCV 库。

此指南已在 Ubuntu 上检查过,但不包含依赖于平台的部分,因此应该与 Android Studio 和 OpenCV4Android SDK 支持的任何操作系统兼容。

本教程假定你已安装并配置以下内容

  • Android Studio
  • JDK
  • Android SDK 及 NDK
  • 可选:从 GitHub 上的官方 发布页面SourceForge 下载 OpenCV for Android SDK。高级:或者可以根据 wiki 上的说明 从源代码构建 SDK。

如果你对上述任何内容需要帮助,可以参阅我们的 Android 开发入门 指南。

如果你在仔细按照这些步骤操作后遇到任何错误,请随时通过 OpenCV 论坛 联系我们。我们将尽力帮助你解决问题。

带 SDK 的 Hello OpenCV 示例

在本部分中,我们将创建一个简单的应用,除了加载 OpenCV 外什么也不做。在下一部分中,我们将对其进行扩展以支持相机。

除了本说明,还可以使用一些视频指南,例如 这个

  1. 打开 Android Studio 并通过选择Empty Views Activity 创建一个空项目
  1. 设置项目
    • 选择Java 语言
    • 选择Groovy DSL 构建配置语言
    • 选择Minimum SDK,其版本号不低于在 OpenCV 4 Android 构建期间使用的版本号
      • 如果你不知道,可以在文件 OpenCV-android-sdk/sdk/build.gradle 中的 android -> defaultConfig -> minSdkVersion 中找到
  1. 单击File -> New -> Import module... 并选择 OpenCV SDK 路径
  1. 将模块名称设置为 OpenCV,然后按 Finish
  1. OpenCV 还提供实验性的 Kotlin 支持。请将 Android Kotlin 插件添加到 MyApplication/OpenCV/build.gradle 文件

    plugins {
    id 'org.jetbrains.kotlin.android' version '1.7.10' #version may differ for your setup
    }

    像这样:

    如果不执行此操作,您可能会收到错误

    任务失败,出现异常。
    -----------
    * 所在位置
    构建文件 '/home/alexander/AndroidStudioProjects/MyApplication/opencv/build.gradle',行:4
    * 出错原因
    在评估项目“:opencv”时出现问题。
    > 找不到 ID 为“kotlin-android”的插件。

    在这里发现了修复方法 here

  2. OpenCV 项目使用 buildConfig 功能。在 MyApplication/OpenCV/build.gradle 文件中启用它,改为 android

    buildFeatures{
    buildConfig true
    }

    如下所示:

    如果不执行此操作,您可能会收到错误

    JavaCameraView.java:15: 错误:找不到符号导入 org.opencv.BuildConfig; ^ 符号:类 BuildConfig 位置:包 org.opencv

    在这里发现了修复方法 herehere

  3. 将模块添加到项目中
    • 点击文件 -> 项目结构... -> 依赖关系 -> 所有模块 -> +(添加依赖关系按钮) -> 模块依赖关系
  • 选择 app
  • 选择 OpenCV
  1. 在使用任何 OpenCV 函数之前,您必须先加载库。如果您的应用程序包含其他依赖于 OpenCV 的本机库,则应在初始化 OpenCV 之后加载这些库。添加以下代码以在应用程序启动时加载库
    if (OpenCVLoader.initLocal()) {
    Log.i(TAG, "OpenCV 加载成功");
    } else {
    Log.e(TAG, "OpenCV 初始化失败!");
    (Toast.makeText(this, "OpenCV 初始化失败!", Toast.LENGTH_LONG)).show();
    return;
    }
    如下所示:
  1. 选择一台设备,在该设备上检查示例,然后通过按运行按钮运行代码

具有 Maven Central 的 Hello OpenCV 示例

自 OpenCV 4.9.0 起,OpenCV for Android 包可以通过 Maven Central 获得,并且可以自动安装为 Gradle 依赖项。在本节中,我们将创建一个简单的应用程序,除了使用 Maven Central 加载 OpenCV 外,不做任何其他事情。

  1. 打开 Android Studio 并通过选择Empty Views Activity 创建一个空项目
  1. 设置项目
    • 选择Java 语言
    • 选择Groovy DSL 构建配置语言
    • 选择最小 API 级别,其版本号不低于 OpenCV 支持的版本号。对于 4.9.0,最小 API 等级为 21。
  1. 编辑 build.gradle,并将 OpenCV 库添加到依赖关系列表,如下所示
    dependencies {
    implementation 'org.opencv:opencv:4.9.0'
    }
    4.9.0可以替换为 正式发布 中的所有版本。
  2. 在使用任何 OpenCV 函数之前,您必须先加载库。如果您的应用程序包含其他依赖于 OpenCV 的本机库,则应在初始化 OpenCV 之后加载这些库。添加以下代码以在应用程序启动时加载库
    if (OpenCVLoader.initLocal()) {
    Log.i(TAG, "OpenCV 加载成功");
    } else {
    Log.e(TAG, "OpenCV 初始化失败!");
    (Toast.makeText(this, "OpenCV 初始化失败!", Toast.LENGTH_LONG)).show();
    return;
    }
    如下所示:
  1. 选择一台设备,在该设备上检查示例,然后通过按运行按钮运行代码

摄像头视图示例

在本节中,我们将扩展在前一节中创建的空 OpenCV 应用程序以支持摄像头。我们将获取摄像头帧并将其显示在屏幕上。

  1. 告诉系统我们需要相机权限。将以下代码添加到文件 MyApplication/app/src/main/AndroidManifest.xml
    <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"/>
    类似于此:
  1. 转到 activity_main.xml 布局并删除文本为“Hello World!”的 TextView

也可以通过从 XML 文件中删除 TextView 块在代码或拆分模式下执行此操作。

  1. 将摄像头视图添加到布局中

    1. 将模式添加到布局说明中
      xmlns:opencv="http://schemas.android.com/apk/res-auto"
    2. TextView 替换为 org.opencv.android.JavaCameraView 小部件
      <org.opencv.android.JavaCameraView
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:visibility="gone"
      android:id="@+id/tutorial1_activity_java_surface_view"
      opencv:show_fps="true"
      opencv:camera_id="any" />
    3. 如果您收到布局警告,请将 android:layout_widthandroid:layout_height 属性的 fill_parent 值替换为 match_parent

    您将得到类似此类的代码

    <FrameLayout 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" >
    <!-- [camera_view] -->
    <org.opencv.android.JavaCameraView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:visibility="gone"
    android:id="@+id/tutorial1_activity_java_surface_view"
    opencv:show_fps="true"
    opencv:camera_id="any" />
    <!-- [camera_view] -->
    </FrameLayout>
  2. org.opencv.android.CameraActivity 继承主类。CameraActivity 实现摄像头权限请求和一些 CV 应用程序需要的其他实用工具。我们需要覆盖感兴趣的方法是 onCreateonDestroyonPauseonResumegetCameraViewList
  3. 实现接口 org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2 onCameraFrame 方法应返回内容为渲染的 Mat 对象。样本只返回用于预览的摄像头帧:return inputFrame.rgba();
  4. 分配 org.opencv.android.CameraBridgeViewBase 对象
    • 应在应用启动时创建 (onCreate 方法)并应设置此类为监听器
    • 应在暂停/继续时(onPauseonResume 方法)将其禁用/启用
    • 应用结束时应将其禁用(onDestroy 方法)
    • 应在 getCameraViewList 中返回
  5. 可选择禁止手机调暗屏幕或锁定屏幕

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

最后你将获得类似此处的源代码

package org.opencv.samples.tutorial1;
import org.opencv.android.CameraActivity;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.Toast;
import java.util.Collections;
import java.util.List;
public class Tutorial1Activity extends CameraActivity implements CvCameraViewListener2 {
private static final String TAG = "OCVSample::Activity";
private CameraBridgeViewBase mOpenCvCameraView;
public Tutorial1Activity() {
Log.i(TAG, "Instantiated new " + this.getClass());
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
if (OpenCVLoader.initLocal()) {
Log.i(TAG, "OpenCV 加载成功");
} else {
Log.e(TAG, "OpenCV 初始化失败!");
(Toast.makeText(this, "OpenCV 初始化失败!", Toast.LENGTH_LONG)).show();
return;
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.tutorial1_surface_view);
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
@Override
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onResume()
{
super.onResume();
if (mOpenCvCameraView != null)
mOpenCvCameraView.enableView();
}
@Override
protected List<? extends CameraBridgeViewBase> getCameraViewList() {
return Collections.singletonList(mOpenCvCameraView);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onCameraViewStarted(int width, int height) {
}
@Override
public void onCameraViewStopped() {
}
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
return inputFrame.rgba();
}
}

就是它!现在,您可以在设备上运行代码进行检查。

我们来讨论一些最重要的步骤

每个具有 UI 的 Android 应用程序都必须实现 Activity 和 View。第一步,我们创建空白 Activity 和默认视图布局。最简单的以 OpenCV 为中心的应用程序必须执行 OpenCV 初始化、创建一个用于显示来自摄像头的预览的视图并实现 CvCameraViewListener2 接口以从摄像头获取帧并对其进行处理。

首先,我们使用 XML 布局创建我们的应用程序视图。我们的布局仅包含一个 org.opencv.android.JavaCameraView 类的全屏组件。此 OpenCV 类是从 CameraBridgeViewBase 继承的,它扩展了 SurfaceView,并且实际上使用了标准 Android 摄像头 API。

CvCameraViewListener2 接口允许您在从摄像头获取帧之后和在屏幕上呈现帧之前,添加一些处理步骤。最重要的方法是 onCameraFrame。这是一个回调函数,在从摄像头中检索到帧时会调用该函数。它期望 onCameraFrame 函数返回将在屏幕上绘制的 RGBA 帧。

回调以 CvCameraViewFrame 类对象的格式将来自摄像头的帧传递给我们类。此对象具有 rgba()gray() 方法,可让用户以 Mat 类对象的形式获取彩色帧或单通道灰度帧。

注意
请勿在 onCameraFrame 回调之外保存或使用 CvCameraViewFrame 对象。此对象没有自己的状态,在回调之外的行为不可预测!