Android Camera2获取图像的最简编程

news/2024/11/24 9:30:21/

通过Android官方的Camera2Basic工程源码,总结出的Android摄像头获取图像的最简编程实现:

步骤1: 申请权限
因摄像头是一个隐私性非常强的设备,所以需要弹框向用户申请权限。
在工程配置文件AndroidManifest.xml中标明使用权限:

    <uses-permission android:name="android.permission.CAMERA"/>

在代码中弹框申请权限:

        String [] permissions = {Manifest.permission.CAMERA,};ActivityCompat.requestPermissions(this, permissions, 0);

步骤2: 准备子线程
因摄像头相关的操作是非常消耗资源的耗时工作,因此最好在一个子线程里执行。

        HbgThread = new HandlerThread("CameraThread");//创建HandlerThread对象,指定线程名bgThread.start();//子线程启动,注意它的run方法是没有指定,需要通过Handler把run方法代码交过来执行bgHandler = new Handler(bgThread.getLooper());//创建用于与bgThread通信的Handler对象,通过它的post方法把任务发到子线程执行// bgHandler.post(new Runnable() {  ... } );//摄像头操作相关的方法函数只需要提供bgHandler对象就会自动post相关的操作代码在bgThread里执行

步骤3. 打开摄像头
创建Android摄像头打开操作的回调方法对象,用于指定摄像头成功打开后、关闭后和打开失败后作什么操作。

    private CameraDevice.StateCallback cameraCallback = new CameraDevice.StateCallback() {@Override //摄像头成功打开后的操作public void onOpened(@NonNull CameraDevice cameraDevice) {Log.e("myinfo", "摄像头成功打开");}@Override //摄像头关闭后的操作public void onDisconnected(@NonNull CameraDevice cameraDevice) {}@Override //摄像头出错后的操作public void onError(@NonNull CameraDevice cameraDevice, int i) {}};

获取当前Android系统的摄像头管理器,并打开指定的摄像头。

        //获取当前系统的摄像头管理器CameraManager cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);String [] ids;//获取当前系统里所有摄像头设备的IDids = cameraManager.getCameraIdList();//输出所有摄像头设备的ID, 一般"0"表示前摄像头, "1"表示后摄像头for (int i = 0; i < ids.length; i++)Log.e("myinfo", "id = " + ids[i]);//打开摄像头,指定摄像头打开操作的回调方法对象,并传入可下发任务到子线程执行的Handler对象cameraManager.openCamera(ids[0], cameraCallback, bgHandler);

步骤4. 创建摄像头设备的捕捉会话对象
摄像头设备的捕捉会话对象用于向摄像头申请捕捉图像、打开闪光灯等操作的命令通道。
首先创建摄像头设备会话对象的回调方法对象,用于指定会话通道配置成功或失败后作什么操作。

    private CameraCaptureSession.StateCallback captureCallback = new CameraCaptureSession.StateCallback() {@Override //会话对象创建配置成功后的操作public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {Log.e("myinfo", "摄像头会话创建成功!");}@Override //会话对象创建配置失败后的操作public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {}};

在摄像头成功打开后触发的回调方法onOpened中创建一个接收图像数据的ImageReader对象,
并创建一个摄像头会话对象,指定使用会话的回调方法对象,并传入可下发任务到子线程执行的Handler对象:

    private CameraDevice.StateCallback cameraCallback = new CameraDevice.StateCallback() {@Override //摄像头成功打开后的操作public void onOpened(@NonNull CameraDevice cameraDevice) {Log.e("myinfo", "摄像头成功打开");//创建接收摄像头图像的ImageReader对象,指定图像分辨率、编码格式、图像队列中最多存多少张图像imageReader = ImageReader.newInstance(800, 600, ImageFormat.JPEG, 3);camDevice = cameraDevice;//记录已成功打开的摄像头设备对象//创建会话对象camDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureCallback, bgHandler);}...}       

步骤5. 发出捕捉图像请求
为ImageReader对象创建一个监听器对象,指定当接收到摄像头图像后作什么操作。

    private ImageReader.OnImageAvailableListener imgListener = new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader imageReader) { //由bgThread子线程执行的代码}};

在会话对象创建并配置成功后触发的onConfigured方法中发出捕捉图像请求, 并设置ImageReader对象使用imgListener监听器对象。

    private CameraCaptureSession.StateCallback captureCallback = new CameraCaptureSession.StateCallback() {@Override //会话对象创建配置成功后的操作public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {Log.e("myinfo", "摄像头会话创建成功!");//创建捕捉请求对象,指定请求摄像的预览图像CaptureRequest.Builder builder = camDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);builder.addTarget(imageReader.getSurface());//指定捕捉到图像数据由imageReader对象处理//当ImageReader对象接收到图像后触发OnImageAvailableListener方法,并由bgThread子线程执行方法里的代码imageReader.setOnImageAvailableListener(imgListener, bgHandler);//通过会话对象提交请求,并且设置是循环的请求cameraCaptureSession.setRepeatingRequest(builder.build(), null, bgHandler);}...}

步骤6. 处理捕捉到的摄像头图像
当ImageReader对象接收到图像后触发OnImageAvailableListener方法,在此方法处理图像数据,如进行网络传输、存储、显示等操作。

    private ImageReader.OnImageAvailableListener imgListener = new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader imageReader) { //由bgThread子线程执行的代码Image img = imageReader.acquireNextImage();//获取出图像ByteBuffer buffer = img.getPlanes()[0].getBuffer();//获取图像数据byte [] bytes = new byte[buffer.remaining()];buffer.get(bytes);//图像数据存入bytes数组里img.close();//关闭图像//把bytes数组图像数据转成Bitmap图像,并在ImageView组件上显示Bitmap map = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);//让主线程设置显示图像imageView.post(new Runnable() {@Overridepublic void run() {imageView.setImageBitmap(map);}});}};

获取摄像头图像并在ImageView组件上显示的完整工程代码:

public class MainActivity extends AppCompatActivity {private ImageView imageView;private Button btnStart;private HandlerThread bgThread;//可通过Handler下发任务的子线程private Handler bgHandler;//用于与bgThread通信的Handler对象private ImageReader imageReader;//用于接收图像的对象名private CameraDevice camDevice; //记录已打开的摄像头设备对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView = findViewById(R.id.imageView);btnStart = findViewById(R.id.btnStart);btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {initializeCamera(); //摄像头初始化}});requestPermissions();//弹框请求权限}private ImageReader.OnImageAvailableListener imgListener = new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader imageReader) { //由bgThread子线程执行的代码Image img = imageReader.acquireNextImage();//获取出图像ByteBuffer buffer = img.getPlanes()[0].getBuffer();//获取图像数据byte [] bytes = new byte[buffer.remaining()];buffer.get(bytes);//图像数据存入bytes数组里img.close();//关闭图像//把bytes数组图像数据转成Bitmap图像Bitmap map = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);//让主线程设置显示图像imageView.post(new Runnable() {@Overridepublic void run() {imageView.setImageBitmap(map);}});}};private CameraCaptureSession.StateCallback captureCallback = new CameraCaptureSession.StateCallback() {@Override //会话对象创建配置成功后的操作public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {Log.e("myinfo", "摄像头会话创建成功!");try {//3.创建捕捉请求对象,指定请求摄像的预览图像CaptureRequest.Builder builder = camDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);builder.addTarget(imageReader.getSurface());//指定捕捉到图像数据由imageReader对象处理//当ImageReader对象接收到图像后触发OnImageAvailableListener方法,并由bgThread子线程执行方法里的代码imageReader.setOnImageAvailableListener(imgListener, bgHandler);//通过会话对象提交请求,并且设置是循环的请求cameraCaptureSession.setRepeatingRequest(builder.build(), null, bgHandler);}catch (Exception e) {e.printStackTrace();}}@Override //会话对象创建配置失败后的操作public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {}};private CameraDevice.StateCallback cameraCallback = new CameraDevice.StateCallback() {@Override //摄像头成功打开后的操作public void onOpened(@NonNull CameraDevice cameraDevice) {Log.e("myinfo", "摄像头成功打开");//创建接收摄像头图像的ImageReader对象,指定图像分辨率、编码格式、图像队列中最多存多少张图像imageReader = ImageReader.newInstance(800, 600, ImageFormat.JPEG, 3);camDevice = cameraDevice;//记录已成功打开的摄像头设备对象try {//2.创建会话对象camDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureCallback, bgHandler);}catch (Exception e) {e.printStackTrace();}}@Override //摄像头关闭后的操作public void onDisconnected(@NonNull CameraDevice cameraDevice) {}@Override //摄像头出错后的操作public void onError(@NonNull CameraDevice cameraDevice, int i) {}};@SuppressLint("MissingPermission")public void initializeCamera() {  //初始化摄像头bgThread = new HandlerThread("CameraThread");//创建HandlerThread对象,指定线程名bgThread.start();//子线程启动,注意它的run方法是没有指定,需要通过Handler把run方法代码交过来执行bgHandler = new Handler(bgThread.getLooper());//创建用于与bgThread通信的Handler对象,通过它的post方法把任务发到子线程执行// bgHandler.post(new Runnable() {  ... } );//摄像头操作相关的方法函数只需要提供bgHandler对象就会自动post相关的操作代码在bgThread里执行//获取当前系统的摄像头管理器CameraManager cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);String [] ids;try {//获取当前系统里所有摄像头设备的IDids = cameraManager.getCameraIdList();//输出所有摄像头设备的ID, 一般"0"表示前摄像头, "1"表示后摄像头for (int i = 0; i < ids.length; i++)Log.e("myinfo", "id = " + ids[i]);//1.打开摄像头cameraManager.openCamera(ids[0], cameraCallback, bgHandler);} catch (Exception e) {e.printStackTrace();}}public void requestPermissions() {String [] permissions = {Manifest.permission.CAMERA,};ActivityCompat.requestPermissions(this, permissions, 0);}
}

http://www.ppmy.cn/news/584798.html

相关文章

Android应用程序开发需要哪些编程语言?

开发一款Android上的应用程序通常需要以下编程语言&#xff1a; Java&#xff1a;Java是Android开发的主要编程语言。几乎所有的Android应用程序都使用Java进行核心开发。你可以使用Java编写应用程序的业务逻辑、界面设计和数据处理等。 刚好我这里有嵌入式、plc、单片机的资料…

简析电力用户预付费模式转变及前景

【摘要】随着电力市场发展水平的不断提高以及电力体制改革事业的不断推进&#xff0c;电力企业面临的电费回收风险越来越大&#xff0c;管理也更加复杂。积极采用电力用户预付费模式&#xff0c;促进预付费系统的建设&#xff0c;不仅能够提升企业的电力服务水平&#xff0c;同…

黑苹果识别Intel 蓝牙驱动

本人是黑苹果使用i ntel nuc 8 打开 链接 https://github.com/OpenIntelWireless/IntelBluetoothFirmware/releases 下载 IntelBluetooth.zip 并解压出.kext 文件 打开 Clover Configuator 然后 open Partition 找到 EFI/CLOVER/kexts/Other 目录 把解压的文件放进去 最后…

计算机无法安装蓝牙驱动,win7电脑蓝牙驱动安装失败怎么解决_win7电脑蓝牙驱动安装失败的解决方法 - 系统家园...

在我们日常使用win7系统电脑时&#xff0c;应该有很多用户遇到过蓝牙驱动安装失败的情况&#xff0c;那么win7电脑蓝牙驱动安装失败怎么解决呢&#xff1f;下面小编就为大家带来win7电脑蓝牙驱动安装失败的解决方法&#xff0c;感兴趣的小伙伴快来看看吧。 win7电脑蓝牙驱动安装…

ArchLinux安装蓝牙驱动

基础 #安装 sudo pacman -S bluez bluez-utils #开机启动 sudo systemctl enable bluetooth.service #立即开启 sudo systemctl start bluetooth.service蓝牙图形化管理工具安装 sudo pacman -S bluedevil图形化的蓝牙管理软件2 安装软件 pacman -S blueman运行程序 blue…

linux查看蓝牙驱动版本号,linux蓝牙驱动代码阅读笔记

昨天看了一下介绍蓝牙协议文档,今天索性对照看了看kernel里的代码(bluez),这里记点笔记,还是继承了老毛病,只关注整体流程而忽略细节,先了解个大概,等真正需要时再仔细分析。 net/hci_core.c HCI在主机端的驱动主要是为上层提供一个统一的接口,让上层协议不依赖于具体硬…

为ubuntu 18.04添加蓝牙驱动

目录 背景方法 背景 从网上买的能直接插ubuntu 1804的usb蓝牙太少了&#xff0c;而且还贵。我就直接从JD下单的一个便宜的USB蓝牙&#xff0c;结果插上机器没有驱动起不来。我的PC是个3年前的老机器&#xff0c;实在是不想升级系统&#xff0c;于是捣鼓半天捣鼓好了&#xff0…

js精度问题之bignumber.jsdecimal.js的基本使用

一、背景 JavaScript中存在精度缺失问题 为什么&#xff1f; 主要是由于浮点数的表示方式以及计算机的二进制运算原理导致的 JavaScript使用IEEE 754标准定义了浮点数的表示和计算规则。在这种表示方式中&#xff0c;浮点数由符号位、指数位和尾数位组成。尾数位的长度是固…