创建的空 OpenCV 安卓应用程序以支持摄像头

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

告诉系统我们需要相机权限。将以下代码添加到文件MyApplication/app/src/main/AndroidManifest.xml

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

TextView这也可以在代码或拆分模式下通过从 XML 文件中删除块来完成。

  1. 将相机视图添加到布局中:

    在布局描述中添加方案:

xmlns:opencv = "http://schemas.android.com/apk/res-auto"

TextView用小部件替换org.opencv.android.JavaCameraView

XML 复制代码
    <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" />
  1. 如果你收到布局警告,请用for和properties替换fill_parentmatch_parent``android:layout_width``android:layout_height

您将获得如下代码:

XML 复制代码
<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>
  1. 从 继承主类。CameraActivity 实现相机权限请求和org.opencv.android.CameraActivityCV 应用程序所需的一些其他实用程序。我们想要重写的方法包括onCreateonDestroy、和onPause``onResume``getCameraViewList
  2. 实现接口org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2 onCameraFrame方法应该返回Mat带有内容的对象以供渲染。示例仅返回相机帧以供预览:return inputFrame.rgba();
  3. 分配org.opencv.android.CameraBridgeViewBase对象:
    • 它应该在应用程序启动时创建(onCreate方法),并且该类应该设置为监听器
    • 在暂停/恢复(onPauseonResume方法)时应该禁用/启用它
    • 应在应用程序完成时禁用(onDestroy方法)
    • 应归还getCameraViewList
  4. 您可以选择禁止手机调暗屏幕或锁定:
java 复制代码
 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

最终的源码:

java 复制代码
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 loaded successfully");
        } else {
            Log.e(TAG, "OpenCV initialization failed!");
            (Toast.makeText(this, "OpenCV initialization failed!", 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。首先,我们创建空白活动和默认视图布局。最简单的以 OpenCV 为中心的应用程序必须执行 OpenCV 初始化,创建一个视图来显示来自摄像头的预览,并实现CvCameraViewListener2接口以从摄像头获取帧并对其进行处理。

首先,我们使用 XML 布局创建应用程序视图。我们的布局仅包含一个类的全屏组件org.opencv.android.JavaCameraView。此 OpenCV 类继承自CameraBridgeViewBase扩展类SurfaceView,并在底层使用标准 Android 相机 API。

CvCameraViewListener2接口允许您在从相机抓取帧之后和在屏幕上渲染之前添加一些处理步骤。最重要的方法是onCameraFrame。这是一个回调函数,在从相机检索帧时调用。它期望该onCameraFrame函数返回将在屏幕上绘制的 RGBA 帧。

回调将相机中的帧作为类对象传递给我们的类CvCameraViewFrame。此对象具有rgba()gray()方法,可让用户获取彩色或单通道灰度帧作为Mat类对象。

笔记

不要保存或使用回调CvCameraViewFrame之外的对象onCameraFrame。此对象没有自己的状态,并且其在回调之外的行为不可预测!

相关推荐
飞哥数智坊8 小时前
GPT-5-Codex 发布,Codex 正在取代 Claude
人工智能·ai编程
倔强青铜三8 小时前
苦练Python第46天:文件写入与上下文管理器
人工智能·python·面试
虫无涯9 小时前
Dify Agent + AntV 实战:从 0 到 1 打造数据可视化解决方案
人工智能
Dm_dotnet11 小时前
公益站Agent Router注册送200刀额度竟然是真的
人工智能
算家计算11 小时前
7B参数拿下30个世界第一!Hunyuan-MT-7B本地部署教程:腾讯混元开源业界首个翻译集成模型
人工智能·开源
机器之心12 小时前
LLM开源2.0大洗牌:60个出局,39个上桌,AI Coding疯魔,TensorFlow已死
人工智能·openai
Juchecar13 小时前
交叉熵:深度学习中最常用的损失函数
人工智能
林木森ai13 小时前
爆款AI动物运动会视频,用Coze(扣子)一键搞定全流程(附保姆级拆解)
人工智能·aigc
聚客AI13 小时前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm
BeerBear15 小时前
【保姆级教程-从0开始开发MCP服务器】一、MCP学习压根没有你想象得那么难!.md
人工智能·mcp