android CameraX构建相机拍照

news2024/9/21 14:46:41

Android CameraX 是一个 Jetpack 支持库,旨在简化相机应用的开发工作。它提供了一致且易用的API接口,适用于大多数Android设备,并可向后兼容至Android 5.0(API级别21)。

CameraX解决了在多种设备上实现相机功能时所遇到的兼容性问题,大大减少了需要编写的设备专属代码量。同时,它还通过提供一种基于用例的、具有生命周期感知能力的方式,简化了相机功能的开发。

导入需要的包

    implementation("androidx.camera:camera-core:1.3.4")
    implementation("androidx.camera:camera-camera2:1.3.4")
    implementation("androidx.camera:camera-lifecycle:1.3.4")
    implementation("androidx.camera:camera-video:1.3.4")
    implementation("androidx.camera:camera-view:1.3.4")

配置简单layout和PhotoActivity

新建一个activity_photo.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:xhead="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#005dd7"
    android:orientation="vertical">
  <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:layout_margin="20dp"
        android:background="@drawable/shape_common_dialog_bg"
        android:orientation="vertical">

    <androidx.camera.view.PreviewView
        android:layout_width="640dp"
        android:layout_height="600dp"
        android:id="@+id/viewFinder" />

    <Button
        android:layout_marginTop="10dp"
        android:background="@drawable/shape_login_button"
        android:id="@+id/image_capture_button"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:elevation="2dp"
        android:text="拍照" />
</LinearLayout>
public class PhotoActivity implements View.OnClickListener {

	//图片捕获
   private ImageCapture imageCapture;
	//
    private ProcessCameraProvider cameraProvider;
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_photo);
    }

请求必要的权限

应用需要获得用户授权才能打开相机。
首先在AndroidManifest.xml中声明
<uses-permission android:name="android.permission.CAMERA" />
所以在onCreate(@Nullable Bundle savedInstanceState)方法中增加:

 protected void onCreate(@Nullable Bundle savedInstanceState){
 String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
        if (allPermissionsGranted(permissions, this)) {
            startCamera();
        } else {
            ActivityCompat.requestPermissions(this, permissions, REQUEST_CAMERA_PERMISSION);
        }
}
        
        public boolean allPermissionsGranted(String[] permissions, Context context) {
        for (String permission : permissions) {
            int checkSelfPermission = ContextCompat.checkSelfPermission(context, permission);
            if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, permissions, REQUEST_CAMERA_PERMISSION);
            }
        }
        return true;
    }

当然用户存在不同意的情况,此时可以重写 onRequestPermissionsResult 方法以处理权限请求结果:

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限已被授予,可以执行相机相关操作
                startCamera();
            } else {
                // 权限被拒绝,提示用户需要授权
                Toast.makeText(this, "需要相机权限才能使用此功能", Toast.LENGTH_SHORT).show();
            }
        }
    }

实现 Preview 用例,开始拍照

我们打开前置摄像头:

 private void startCamera() {
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

        cameraProviderFuture.addListener(() -> {
            try {
                cameraProvider = cameraProviderFuture.get();
                //前置摄像头
                CameraSelector cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA;
                Preview preview = new Preview.Builder().build();

                // 构建预览用例
                preview.setSurfaceProvider(bd.viewFinder.getSurfaceProvider());

                // 构建图片捕获用例
                imageCapture = new ImageCapture.Builder().build();

                // 将用例绑定到相机
                cameraProvider.bindToLifecycle(
                        PersonPhotoActivity.this,
                        cameraSelector,
                        preview,
                        imageCapture);
            } catch (ExecutionException | InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, ContextCompat.getMainExecutor(this));

    }
  • ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this); 这行代码的作用是获取一个ProcessCameraProvider的实例,这个实例可以与宿主的生命周期绑定,从而无需手动管理相机的打开和关闭。
  • cameraProviderFuture注册了一个监听器,当cameraProviderFuture完成时,会执行注册的Runnable。在这个Runnable中,首先通过cameraProviderFuture.get()获取到cameraProvider实例。然后,创建一个用于预览的Preview对象,并将其Surface设置到对应的预览界面上。同时,还创建了一个ImageCapture对象用于图片捕获。
  • 使用cameraProvider.bindToLifecycle()方法将相机与当前Activity的生命周期绑定,并指定使用的摄像头、预览、以及图片捕获的配置。这样,相机就会在Activity的生命周期内自动进行资源的申请和释放

在avd虚拟机中显示

配置avd的前置摄像头为虚拟模式:
在这里插入图片描述
启动项目查看页面:
在这里插入图片描述

拍照

当拍照按钮被点击时调用takePhoto 方法,这里我们建立了一个file对象临时保存当前照片,之后我们就可以自由使用该照片:

 @Override
    public void onClick(View view) {
        if (view.getId() == R.id.image_capture_button) {
            takePhoto(view);
        }
    }
 private void takePhoto(View view) {
        File file = new File(getContext().getExternalCacheDir() + File.separator + System.currentTimeMillis() + ".png");
        //创建包文件的数据,比如创建文件
        ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
        //开始拍照
        imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this),
                new ImageCapture.OnImageSavedCallback() {
                    @Override
                    public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                        // 关闭相机并释放资源
                        cameraProvider.unbindAll();
                        // file.getPath()
						//做业务
						//。。。。
                    }

                    @Override
                    public void onError(@NonNull ImageCaptureException exception) {
                        Log.d(TAG, Objects.requireNonNull(exception.toString()));
                        Toast.makeText(PersonPhotoActivity.this, "照片保存失败", Toast.LENGTH_SHORT).show();
                    }
                });
    }

代码分析:

  1. 创建一个ImageCapture.OutputFileOptions对象,用于指定照片的输出选项,这里将照片保存到刚刚创建的File对象中。
  2. 调用imageCapture的takePicture方法开始拍照。传入outputFileOptions作为参数,以及一个回调函数OnImageSavedCallback。
  3. 在OnImageSavedCallback的onImageSaved方法中,当照片成功保存后,关闭相机并释放资源。然后可以进行其他业务操作,如显示照片等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLM代理应用实战:构建Plotly数据可视化代理

如果你尝试过像ChatGPT这样的LLM&#xff0c;就会知道它们几乎可以为任何语言或包生成代码。但是仅仅依靠LLM是有局限的。对于数据可视化的问题我们需要提供一下的内容 描述数据:模型本身并不知道数据集的细节&#xff0c;比如列名和行细节。手动提供这些信息可能很麻烦&#…

javascipt学习笔记一

JavaScript基础day1 一、编程语言 1.编程 编程&#xff1a;就是让计算机为解决某个问题而使用某种编程设计语言编写程序代码&#xff0c;最终得到结果的过程 计算机程序&#xff1a; 就是计算机所执行的一系列的指令集合。 2.计算机语言 计算机语言指的是用于人与计算机之间通…

Manim的代码练习02:在manim中Dot ,Arrow和NumberPlane对象的使用

Dot&#xff1a;指代点对象或者表示点的符号。Arrow&#xff1a;指代箭头对象&#xff0c;包括直线上的箭头或者向量箭头等。NumberPlane&#xff1a;指代数轴平面对象&#xff0c;在Manim中用来创建包含坐标轴的数学坐标系平面。Text&#xff1a;指代文本对象&#xff0c;用来…

国产数据库VastBase与C/C++程序适配

背景 2022年底的项目&#xff0c;记录一下。 某项目后台使用C程序开发&#xff0c;使用的是OCI连接Oracle数据库。现需要做去O国产化适配改造。 本文聊聊C/C应用程序如何使用VastBase替换Oracle。 编译适配 开发包获取 从VastBase官方或接口人处获取OCI开发包&#xff0c;包含…

品牌产业出海指南如何搭建国际化架构的跨境电商平台?

在“品牌&产业出海指南 – 成功搭建跨境电商平台”系列中&#xff0c;我们将从电商分销系统、跨境平台商城/多商户商城系统和国际化架构三个方面对帮助您梳理不同平台模式的优缺点、应用场景、开发重点和运营建议。 在“品牌&产业出海指南 – 成功搭建跨境电商平台”系…

verITAS:大规模验证图像转换

1. 引言 斯坦福大学Trisha Datta、Binyi Chen 和 Dan Boneh 2024年论文《VerITAS: Verifying Image Transformations at Scale》&#xff0c;开源代码实现见&#xff1a; https://github.com/zk-VerITAS/VerITAS&#xff08;RustPython&#xff09; 依赖https://github.com/a…

Java的高级特性

类的继承 继承是从已有的类中派生出新的类&#xff0c;新的类能拥有已有类的属性和行为&#xff0c;并且可以拓展新的属性和行为 public class 子类 extends 父类{子类类体 } 优点 代码的复用 提高编码效率 易于维护 使类与类产生关联&#xff0c;是多态的前提 缺点 类缺乏独…

纯vue+js实现数字0到增加到指定数字动画效果功能

关于数字增加动画效果网上基本上都是借助第三方插件实现的,就会导致有的项目安装插件总会出问题,所有最好使用原生vue+js实现,比较稳妥 纯vue+js实现数字0到增加到指定数字动画效果功能 vue+js 实现数字增加动画功能 效果图 其中,关于数字变化的间隔时间,延时效果都可…

Linux环境下激活使用Navicat

Linux环境下激活使用Navicat 解压navicat15-premium-linux.zip文件&#xff0c;存放目录自行定义&#xff0c;此处我解压到/home/admin/Downloads&#xff0c;下载地址&#xff1a;https://www.123pan.com/s/hyS7Vv-zJCR.html # 在桌面创建临时目录 mkdir ~/Desktop/navicat…

Flutter和React Native(RN)的比较

Flutter和React Native&#xff08;RN&#xff09;都是用于构建跨平台移动应用程序的流行框架。两者都具有各自的优势和劣势&#xff0c;选择哪个框架取决于您的具体需求和项目。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 以下是…

算法学习笔记(8.5)-零钱兑换问题二

目录 Question&#xff1a; 动态规划思路&#xff1a; 代码实现&#xff1a; 空间优化代码 Question&#xff1a; 给定n种硬币&#xff0c;第i种硬币的面值为coins[i-1],目标金额为amt&#xff0c;每种硬币可以重复选取&#xff0c;问凑出目标金额的硬币组合数量。 动态规划思路…

教你如何白嫖ioDraw

ioDraw推出了这个活动&#xff0c;大家看看~ 领取页面 邀请奖励 您和好友都将获得7天的会员权益 邀请攻略 活动介绍 1. 每成功邀请一个新用户&#xff0c;邀请者与被邀请者均可获得7天会员 2. 每年最高可得350天 3. 新用户是指首次登录ioDraw的用户 获取邀请链接步骤 1. 浏…

VS2019配置OpenGL的库

OpenGL环境的配置&#xff08;GLUT安装教程&#xff09;_opengl官网-CSDN博客 我是根据这篇来配置的&#xff0c;然后&#xff1a; 引用的头文件不是<OpenGL/glut.h>而是<GL/glut.h>&#xff0c;然后就可以运行了。

CCSI: 数据无关类别增量学习的持续类特定印象| 文献速递-基于深度学习的多模态数据分析与生存分析

Title 题目 CCSI: Continual Class-Specific Impression for data-free class incremental learning CCSI: 数据无关类别增量学习的持续类特定印象 01 文献速递介绍 当前用于医学影像分类任务的深度学习模型表现出令人鼓舞的性能。这些模型大多数需要在训练之前收集所有的…

【tomcat】Tomcat如何扩展Java线程池原理

池化技术 在后端中&#xff0c;对于经常使用池化就是来提升系统性能&#xff0c;比如数据库连接池、线程池连接池等&#xff0c;本质都是利用空间换时间的来提升性能&#xff0c;用来避免资源的频繁创建和销毁&#xff0c;以此提高资源的复用率&#xff0c;所以合理设置系统所…

springboot个人健康信息管理小程序-计算机毕业设计源码

摘要 在当今这个数字化、信息化的时代&#xff0c;个人健康管理已成为人们生活中不可或缺的一部分。随着生活节奏的加快&#xff0c;越来越多的人开始关注自己的身体状况&#xff0c;希望能够及时了解并调整自己的生活习惯&#xff0c;以达到最佳的健康状态。为此&#xff0c;我…

Codeforces Round 957 (Div. 3) D,F

D. Test of Love 很容易想到dp&#xff0c;对于dp的转移方程也比较好写&#xff0c;当前点只能从当前点前面m个点转移过来&#xff0c;那么思考转移的条件&#xff0c;对于前面的点 j j j &#xff0c;如果 j j j 是水并且 i i i 和 j j j 不相邻&#xff0c;那么不能进行转…

初始化列表和explicit关键字和static成员

初始化列表 1.初始化和赋值的概念&#xff1a; 首先我们先来了解一下成员变量初始化和赋值的概念&#xff0c;初始化是是对成员变量进行一次赋值&#xff0c;注意是只能一次赋值&#xff0c;而赋值是可以多次进行赋值的。 2.初始化列表的引出&#xff1a; 我们知道了初始化…

ftp pool 功能分析及 golang 实现

本文探究一种轻量级的 pool 实现 ftp 连接。 一、背景 简要介绍&#xff1a;业务中一般使用较多的是各种开源组件&#xff0c;设计有点重&#xff0c;因此本文探究一种轻量级的 pool 池的思想实现。 期望&#xff1a;设置连接池最大连接数为 N 时&#xff0c;批量执行 M 个 F…

Transformer模型:Decoder的self-attention mask实现

前言 这是对Transformer模型Word Embedding、Postion Embedding、Encoder self-attention mask、intra-attention mask内容的续篇。 视频链接&#xff1a;20、Transformer模型Decoder原理精讲及其PyTorch逐行实现_哔哩哔哩_bilibili 文章链接&#xff1a;Transformer模型&…