Android自定义Camera如何选择合适的摄像头尺寸

前言

前面我们讲到了如何预览摄像头及拍照,但在实际的应用中我们发现预览的画面往往都会有一定程度的拉伸,这是因为SurfaceView和我们的摄像头尺寸不匹配导致的,本篇文章将讨论如何解决这个问题

官方api

Android 获取摄像头是否可用 安卓查看摄像头型号_Math


其实官方文档也为我们明确的指出了正确的处理办法,我们一起看一下第2、3步:

第二步,我们可以通过getParameters()来获取已存在的配置,

第三步,如果需要,可以通过setParameters(Parameters)来修改摄像头的配置

修改摄像头尺寸

第一步,获取摄像头所支持的尺寸

List<Camera.Size> list = parameters.getSupportedPreviewSizes();
		for (Camera.Size size : list){
            Log.e("Camera.Size", size.width + "," + size.height + "," + (float)size.width/size.height);
            /**
             * 先把所有的尺寸,和宽高比打出来让大家有一个认识
             */
        }

Android 获取摄像头是否可用 安卓查看摄像头型号_List_02


Android 获取摄像头是否可用 安卓查看摄像头型号_android_03


可以看到摄像头支持的画面尺寸是非常多的,比如宽高比有1.3333334,0.8181818,1.2222222,1.5, 0.75等,而宽高比为1.3333334的分辨率从低到高有[160,120],[320, 240],[384,288],[480,360],[576,432],[680,480],[1280,960],[1440,1080],[2048,1536]等

第二步,选择合适的宽高比
如果当前的用户视图为宽=230,高=120

setCameraSize(mCamera, 230, 120);
private void setCameraSize(Camera camera, float needW, float needH) {
        if(null == camera ) return;
        Camera.Parameters parameters = camera.getParameters();
        List<Camera.Size> list = parameters.getSupportedPreviewSizes();
        /**
         * 这个返回的是所有camera支持的尺寸,需要注意的是并不是所有我们需要的尺寸摄像头都支持,
         * 比如我现在的画布尺寸是宽230高120,这个尺寸摄像头是绝对不支持的所以我们需要在摄像头
         * 支持的所有尺寸中选择以一个最接近我们目标的
         */
        float needRatio = needW/needH;
        Log.e("我需要的宽高比为", String.valueOf(needRatio));
        LinkedHashMap<Float, Camera.Size> map = new LinkedHashMap<>();
        float bestRatio = 0;
        for (Camera.Size size : list){
            Log.e("Camera.Size", size.width + "," + size.height + "," + (float)size.width/size.height);
            /**
             * 先把所有的尺寸打出来让大家有一个认识
             */
            map.put((float)size.width/size.height, size);
            /**
             * 将所有的尺寸根据宽高比,存入map
             */
            if(bestRatio == 0 || Math.abs(needRatio - (float)size.width/size.height) < Math.abs(needRatio - bestRatio)) {
                bestRatio = (float)size.width/size.height;
            }
        }
        Log.e("最佳的Camera.Size", String.valueOf(bestRatio));

//        parameters.setPreviewSize();
        camera.setParameters(parameters);
    }

最后输出的结果为
我需要的宽高比为: 1.9166666
最佳的Camera.Size: 1.8962963
由此可以得出,我们目前最合适的摄像头尺寸有且只有一个,那就是[2048,1080,1.8962963]
那么如果返回的最佳宽高比包含多个分辨率,我们该怎么处理呢?

第三步,选择合适的分辨率

如果当前的用户视图为宽=320,高=240

setCameraSize(mCamera, 320, 240);
private void setCameraSize(Camera camera, float needW, float needH) {
        if(null == camera ) return;
        Camera.Parameters parameters = camera.getParameters();
        List<Camera.Size> list = parameters.getSupportedPreviewSizes();
        /**
         * 这个返回的是所有camera支持的尺寸,需要注意的是并不是所有我们需要的尺寸摄像头都支持,
         * 比如我现在的画布尺寸是宽230高120,这个尺寸摄像头是绝对不支持的所以我们需要在摄像头
         * 支持的所有尺寸中选择以一个最接近我们目标的
         */
        float needRatio = needW/needH;
        Log.e("我需要的宽高比为", String.valueOf(needRatio));
        LinkedHashMap<Float, Camera.Size> map = new LinkedHashMap<>();
        float bestRatio = 0;
        for (Camera.Size size : list){
            Log.e("Camera.Size", size.width + "," + size.height + "," + (float)size.width/size.height);
            /**
             * 先把所有的尺寸打出来让大家有一个认识
             */
            /**
             * 将当前宽高比的首位,存入map
             */
            if(!map.containsKey((float)size.width/size.height))
                map.put((float)size.width/size.height, size);

            if(bestRatio == 0 || Math.abs(needRatio - (float)size.width/size.height) < Math.abs(needRatio - bestRatio)) {
                bestRatio = (float)size.width/size.height;
            }
        }
        Camera.Size beatSize = map.get(bestRatio);
        Log.e("最佳的Camera.Size", beatSize.width + "---" + beatSize.height);

        parameters.setPreviewSize(beatSize.width, beatSize.height);
        camera.setParameters(parameters);
    }

最后出的最佳尺寸为:2048—1536
这里选择的策略是,如果宽高比相同,则输出分辨率最高的一个,需要注意的是这样会使用户预览时的体验较好,但是也会使最后输出的图片占用空间较大,开发者需要对最后的图片进行压缩。