4-4.Andorid Camera 之简化编码模板(获取摄像头 ID、选择最优预览尺寸)

news2024/9/17 4:30:40

一、Camera 简化思路

  1. 在 Camera 的开发中,其实我们通常只关注打开相机、图像预览和关闭相机,其他的步骤我们不应该花费太多的精力

  2. 为此,应该提供一个工具类,它有处理相机的一些基本工具方法,包括获取摄像头 ID、选择最优预览尺寸以及打印相机参数信息


二、Camera 工具类

  • CameraIdResult.java
public class CameraIdResult {
    private int qzCameraId = -1; // 前置摄像头 id
    private int hzCameraId = -1; // 后置摄像头 id

    public CameraIdResult() {
    }

    public CameraIdResult(int qzCameraId, int hzCameraId) {
        this.qzCameraId = qzCameraId;
        this.hzCameraId = hzCameraId;
    }

    public int getQzCameraId() {
        return qzCameraId;
    }

    public void setQzCameraId(int qzCameraId) {
        this.qzCameraId = qzCameraId;
    }

    public int getHzCameraId() {
        return hzCameraId;
    }

    public void setHzCameraId(int hzCameraId) {
        this.hzCameraId = hzCameraId;
    }
}
  • MyCameraTool.java
public class MyCameraTool {

    public static final String TAG = MyCameraTool.class.getSimpleName();

    /**
     * 得到摄像头 Id 对象
     *
     * @return 摄像头 Id 对象,它有前置摄像头 Id 和后置摄像头 Id
     */
    public static CameraIdResult getCameraIdResult() {
        CameraIdResult cameraIdResult = new CameraIdResult();

        int numberOfCameras = Camera.getNumberOfCameras();
        Log.i(TAG, "------------------------------ 摄像头个数:" + numberOfCameras);

        for (int cameraId = 0; cameraId < numberOfCameras; cameraId++) {
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            Camera.getCameraInfo(cameraId, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                Log.i(TAG, "------------------------------ 前置摄像头,cameraId 为:" + cameraId);
                cameraIdResult.setQzCameraId(cameraId);
            }
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                Log.i(TAG, "------------------------------ 后置摄像头,cameraId 为:" + cameraId);
                cameraIdResult.setHzCameraId(cameraId);
            } else {
                Log.i(TAG, "------------------------------ 其他摄像头,cameraId 为:" + cameraId);
            }
        }

        return cameraIdResult;
    }

    /**
     * 根据 SurfaceView 的尺寸和相机支持的预览尺寸来选择最优的预览尺寸
     *
     * @param sizes 相机支持的预览尺寸列表
     * @param w     SurfaceView 的宽度
     * @param h     SurfaceView 的高度
     * @return 最优的预览尺寸,如果没有合适的尺寸则返回 null
     */
    public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        if (sizes == null) return null;

        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) h / w;
        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;
        int targetHeight = h;

        // 遍历所有支持的预览尺寸
        for (Camera.Size size : sizes) {

            // 检查宽高比是否接近目标宽高比
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;

            // 计算当前尺寸与目标尺寸的宽度差异
            // 如果差异小于当前最小差异,则更新最优尺寸和最小差异
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // 如果找不到接近目标宽高比的尺寸,则选择最接近目标高度的尺寸
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }

        return optimalSize;
    }

    /**
     * 打印相机参数信息
     *
     * @param parameters 相机参数对象
     */
    public static void showParameters(Camera.Parameters parameters) {
        Camera.Size previewSize = parameters.getPreviewSize();
        Log.i(TAG, "============================== getPreviewSize");
        Log.i(TAG, "---------- " + previewSize.width + " - " + previewSize.height);

        List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
        Log.i(TAG, "============================== supportedPreviewSizes");
        Log.i(TAG, "============================== supportedPreviewSizes size: " + supportedPreviewSizes.size());
        for (Camera.Size supportedPreviewSize : supportedPreviewSizes) {
            Log.i(TAG, "---------- " + supportedPreviewSize.width + " - " + supportedPreviewSize.height);
        }

        Camera.Size pictureSize = parameters.getPictureSize();
        Log.i(TAG, "============================== getPictureSize");
        Log.i(TAG, "---------- " + pictureSize.width + " - " + pictureSize.height);

        List<Camera.Size> supportedPictureSizes = parameters.getSupportedPictureSizes();
        Log.i(TAG, "============================== getSupportedPictureSizes");
        Log.i(TAG, "============================== getSupportedPictureSizes: " + supportedPictureSizes.size());
        for (Camera.Size supportedPictureSize : supportedPictureSizes) {
            Log.i(TAG, "---------- " + supportedPictureSize.width + " - " + supportedPictureSize.height);
        }

        String focusMode = parameters.getFocusMode();
        Log.i(TAG, "============================== getFocusMode");
        Log.i(TAG,"---------- " + focusMode);

        String whiteBalance = parameters.getWhiteBalance();
        Log.i(TAG, "============================== getWhiteBalance");
        Log.i(TAG,"---------- " + whiteBalance);

        int exposureCompensation = parameters.getExposureCompensation();
        Log.i(TAG, "============================== getExposureCompensation");
        Log.i(TAG,"---------- " + exposureCompensation);

        String flashMode = parameters.getFlashMode();
        Log.i(TAG, "============================== getFlashMode");
        Log.i(TAG,"---------- " + flashMode);
    }
}

三、Camera 工具类解析

1、获取取摄像头 ID
  1. 该方法用于获取取摄像头 ID,它会返回一个 cameraIdResult 对象

  2. cameraIdResult 对象有两个属性为 qzCameraId 和 hzCameraId,分别代表前置摄像头 ID 和后置摄像头 ID,如果 qzCameraId 或 hzCameraId 的值为 -1,代表没有获取到

public static CameraIdResult getCameraIdResult() {
    CameraIdResult cameraIdResult = new CameraIdResult();

    int numberOfCameras = Camera.getNumberOfCameras();
    Log.i(TAG, "------------------------------ 摄像头个数:" + numberOfCameras);

    for (int cameraId = 0; cameraId < numberOfCameras; cameraId++) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, cameraInfo);
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            Log.i(TAG, "------------------------------ 前置摄像头,cameraId 为:" + cameraId);
            cameraIdResult.setQzCameraId(cameraId);
        }
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            Log.i(TAG, "------------------------------ 后置摄像头,cameraId 为:" + cameraId);
            cameraIdResult.setHzCameraId(cameraId);
        } else {
            Log.i(TAG, "------------------------------ 其他摄像头,cameraId 为:" + cameraId);
        }
    }

    return cameraIdResult;
}
2、选择最优预览图像尺寸
  • 该方法用于选择最优预览图像尺寸,设置最优预览图像尺寸,能保证在预览图像时(例如,SurfaceView)图像不被拉伸
public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    if (sizes == null) return null;

    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;
    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;
    int targetHeight = h;

    // 遍历所有支持的预览尺寸
    for (Camera.Size size : sizes) {

        // 检查宽高比是否接近目标宽高比
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;

        // 计算当前尺寸与目标尺寸的宽度差异
        // 如果差异小于当前最小差异,则更新最优尺寸和最小差异
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    // 如果找不到接近目标宽高比的尺寸,则选择最接近目标高度的尺寸
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }

    return optimalSize;
}
3、打印相机参数信息
  • 该方法用于打印相机参数信息,用于了解设备,并根据业务做更合适的设置
  1. 例如,根据 supportedPreviewSizes 可以对预览图像的大小做更合适的设置(SurfaceView、setPreviewSize 方法)

  2. 再例如,根据 getSupportedPictureSizes 可以对拍照时图片的大小做更合适的设置(setPictureSize 方法)

public static void showParameters(Camera.Parameters parameters) {
    Camera.Size previewSize = parameters.getPreviewSize();
    Log.i(TAG, "============================== getPreviewSize");
    Log.i(TAG, "---------- " + previewSize.width + " - " + previewSize.height);

    List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
    Log.i(TAG, "============================== supportedPreviewSizes");
    Log.i(TAG, "============================== supportedPreviewSizes size: " + supportedPreviewSizes.size());
    for (Camera.Size supportedPreviewSize : supportedPreviewSizes) {
        Log.i(TAG, "---------- " + supportedPreviewSize.width + " - " + supportedPreviewSize.height);
    }

    Camera.Size pictureSize = parameters.getPictureSize();
    Log.i(TAG, "============================== getPictureSize");
    Log.i(TAG, "---------- " + pictureSize.width + " - " + pictureSize.height);

    List<Camera.Size> supportedPictureSizes = parameters.getSupportedPictureSizes();
    Log.i(TAG, "============================== getSupportedPictureSizes");
    Log.i(TAG, "============================== getSupportedPictureSizes: " + supportedPictureSizes.size());
    for (Camera.Size supportedPictureSize : supportedPictureSizes) {
        Log.i(TAG, "---------- " + supportedPictureSize.width + " - " + supportedPictureSize.height);
    }

    String focusMode = parameters.getFocusMode();
    Log.i(TAG, "============================== getFocusMode");
    Log.i(TAG,"---------- " + focusMode);

    String whiteBalance = parameters.getWhiteBalance();
    Log.i(TAG, "============================== getWhiteBalance");
    Log.i(TAG,"---------- " + whiteBalance);

    int exposureCompensation = parameters.getExposureCompensation();
    Log.i(TAG, "============================== getExposureCompensation");
    Log.i(TAG,"---------- " + exposureCompensation);

    String flashMode = parameters.getFlashMode();
    Log.i(TAG, "============================== getFlashMode");
    Log.i(TAG,"---------- " + flashMode);
}

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

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

相关文章

从零开始写论文:如何借助ChatGPT生成完美摘要?

AIPaperGPT&#xff0c;论文写作神器~ https://www.aipapergpt.com/ 在写论文的过程中&#xff0c;摘要是一个非常重要的部分&#xff0c;它能够帮助读者快速理解论文的核心内容&#xff0c;决定是否进一步阅读全文。但是许多学生在写摘要的时候常常感到困惑&#xff0c;不知…

Oracle 19c数据库:Windows详细安装与配置指南

Oracle 19c的安装和配置是一个相对复杂但系统化的过程&#xff0c;本文演示如何在 Windows 系统下安装 Oracle数据库&#xff0c;安装足够的磁盘空间&#xff08;一般需要5~6个G&#xff0c;所以选剩余空间大的盘&#xff09;。以下是一个详细的步骤指南&#xff0c;包括准备工…

多线程 | CompletableFutureAPI简单介绍

文章目录 1. 案例Future方案CompletableFuture方案 2. CompletableFuture方法一览使用new方法supplyAsync方法runAsync方法为什么仍需要CompletableFuture其他API介绍whenCompletethenApplythenAcceptthenComposethenCombineallOf&anyOfsupplyAsync 3. 注意点4. 总结 本文从…

游戏厅计费系统电玩计时系统软件 佳易王计时定时语音提醒管理系统操作教程

一、前言 游戏厅计费系统电玩计时系统软件 佳易王计时定时语音提醒管理系统操作教程 1、佳易王电玩店ps5计时计费软件&#xff0c;可以设置定时语音提醒。 2、软件为免安装版&#xff0c;解压即可。 二、软件程序部分功能图文说明 1、在设置定时语音提醒的时候&#xff0c;只…

第49课 Scratch入门篇:骇客任务背景特效

骇客任务背景特效 故事背景: 骇客帝国特色背景在黑色中慢慢滚动着! 程序原理: 1 、 角色的设计技巧  2 、克隆体的应用及特效的使用 开始编程 1、使用 黑色的背景: ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7d74c872f06b4d9fbc88aecee634b074.png#pic_c…

以太坊入门

1. 以太坊简介 Vitalik Buterin 在 2013 年 11 月提出了以太坊的概念&#xff0c;其关键思想是&#xff1a;开发一种图灵完备&#xff08;Turing-Complete) 的语言&#xff0c;以允许开发用于区块链和去中心化应用的任意程序&#xff08;智能合约&#xff09;。该概念与比特比相…

驱动(RK3588S)第七课时:单节点设备树

目录 需求一、设备树的概念1、设备树的后缀名&#xff1a;2、设备树的语法格式3、设备树的属性&#xff08;重要&#xff09;4、设备树格式举例 二、设备树所用函数1、如何在内核层种获取设备树节点&#xff1a;2、从设备树上获取 gpio 口的属性3、获取节点上的属性只针对于字符…

【0324】Postgres内核 Shared Buffer Access Rules (共享缓冲区访问规则)说明

0. 章节内容 1. 共享磁盘缓冲区访问机制 (shared disk buffers) 共享磁盘缓冲区有两套独立的访问控制机制:引用计数(a/k/a pin 计数)和缓冲区内容锁。(实际上,还有第三级访问控制:在访问任何属于某个关系表的页面之前,必须持有该关系表的适当类型的锁。这里不讨论关系…

[Linux Kernel Block Layer第一篇] block layer架构设计

目录 1. single queue架构 2. multi-queue架构&#xff08;blk-mq) 3. 问题 随着SSD快速存储设备的发展&#xff0c;内核社区越发发现&#xff0c;存储的性能瓶颈从硬件存储设备转移到了内核block layer&#xff0c;主要因为当时的内核block layer是single hw queue的架构&…

【C语言】插入排序、希尔排序——动图展示

目录 1. 插入排序1.1 基本概念1.2 实现思路1.3 代码部分 2. 希尔排序2.1 为什么会有希尔排序&#xff1f;2.2 基本概念2.3 实现思想1&#xff09;单组排序2&#xff09;多组排序 2.4 代码部分 3. 总结 1. 插入排序 1.1 基本概念 把待排序的记录逐个插入到一个已经排好序的有序…

PMP–一、二、三模–分类–14.敏捷–技巧–看板面板与燃尽图燃起图

文章目录 技巧一模14.敏捷--方法--看板&#xff08;类似卡片&#xff09;1、 [单选] 根据项目的特点&#xff0c;项目经理建议选择一种敏捷方法&#xff0c;该方法限制团队成员在任何给定时间执行的任务数。此方法还允许团队提高工作过程中问题和瓶颈的可见性。项目经理建议采用…

微软出品的一款管理多个远程桌面连接的工具

RDCMan&#xff08;Remote Desktop Connection Manager&#xff09;是微软官方出品的一款用于管理多个远程桌面连接的工具。它可以帮助用户集中管理和分类远程桌面&#xff0c;特别适用于需要同时管理大量服务器或在不同计算机间切换操作的场景。 RDCMan的主要功能包括&#x…

使用WebP解决网站加载速度问题,这些细节你需要了解

说到网页的图片格式,大家最常想到的可能是JPEG、PNG,毕竟这些老牌格式陪伴我们这么多年。然而,近几年,有一个格式悄悄崭露头角,那就是WebP。很多人可能听说过,但到底它好在哪?你的网站或者项目是不是也应该用WebP呢?别着急,今天咱们就来好好聊聊WebP这个图片格式的前世…

SOMEIP_ETS_095: SD_Check_subscribe_eventgroup_ttl_expired

测试目的&#xff1a; 验证DUT&#xff08;Device Under Test&#xff09;能够检测到测试器&#xff08;Tester&#xff09;的订阅已过期&#xff08;ttl 3秒&#xff09;&#xff0c;并且在TTL过期后不响应测试器触发的事件。 描述 本测试用例旨在确保DUT能够识别测试器的…

Kettle使用命令pan/kitchen执行任务时传参问题

在用windows任务执行kettle的kjb或ktr文件时&#xff0c;可通过bat命令传递参数&#xff0c;测试了很久&#xff0c;特此记录一下。 一、pan\kitchen 参数说明 Options: /rep : Repository name /user : Repository username /pass : Repository password…

【射频通信电路基础第二讲】射频通信电路基础知识——射频接插件、金属导线的趋肤效应、射频传输线及其特性、衰减电路等

一、射频接插件 参考https://blog.csdn.net/weixin_43813325/article/details/112340937 1、BNC&#xff1a;阻抗一般为50/75Ω&#xff0c;频带宽 2、SMA/SMB&#xff1a;损耗小&#xff0c;价格高昂 SMA接口有两种形式&#xff0c;分别如下所示&#xff0c;常规SMA“外螺纹…

AT32F415的OTA升级

AT32F415的OTA升级 项目简介IAP实现原理AT32中的内置FLASH分配情况AT32中的实现过程跳转到APP的程序代码删除APP区域的FLASH空间代码写APP的bin数据到FLASH空间代码 项目简介 在物联网应用开发过程中&#xff0c;不可避免的会需要用到软件升级&#xff0c;一般情况下&#xff…

C# Hash算法之MD5、SHA

MD5我们用的还是比较多的&#xff0c;一般用来加密存储密码。但是现在很多人觉MD5可能不太安全了&#xff0c;所以都用上了SHA256等来做加密&#xff08;虽然我觉得都差不多,MD5还是能玩&#xff09;。 还是跟上一篇说的一样&#xff0c;当一个算法的复杂度提高的同时肯定会带…

linux dlopen手册翻译

名称 dlclose, dlopen, dlmopen 打开和关闭一个共享对象 简介 #include <dlfcn.h> void *dlopen(const char*filename, int flags); int dlclose(void *handle);#define _GNU_SOURCE #include <dlfcn.h> void *dlmoopen(Lmid_t lmid, const char *filename, int…

【C++ Primer Plus习题】12.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "Stack.h"…