Android自定义Camera如何选择合适的摄像头尺寸
前言
前面我们讲到了如何预览摄像头及拍照,但在实际的应用中我们发现预览的画面往往都会有一定程度的拉伸,这是因为SurfaceView和我们的摄像头尺寸不匹配导致的,本篇文章将讨论如何解决这个问题
官方api
其实官方文档也为我们明确的指出了正确的处理办法,我们一起看一下第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);
/**
* 先把所有的尺寸,和宽高比打出来让大家有一个认识
*/
}
可以看到摄像头支持的画面尺寸是非常多的,比如宽高比有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
这里选择的策略是,如果宽高比相同,则输出分辨率最高的一个,需要注意的是这样会使用户预览时的体验较好,但是也会使最后输出的图片占用空间较大,开发者需要对最后的图片进行压缩。
后记
通过上面讲到的几点,我们就基本解决了图像拉伸的问题,如果上面的操作,没有解决您的问题,你可以考虑了解一下openglES,通过openGLES来裁剪视频的尺寸,或者可以考虑一下,画布来适配相机的尺寸。
下篇文章我们一起来了解一下《如何翻转摄像头》。飞机票