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

一、Camera 简化思路

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

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


二、Camera 工具类

  • CameraIdResult.java
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
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,代表没有获取到

java 复制代码
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)图像不被拉伸
java 复制代码
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 方法)

java 复制代码
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);
}
相关推荐
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭2 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石3 小时前
12/21java基础
java
拭心3 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
李小白663 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp3 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea