前言

  不管在Camera1或者Camera2在适配不同手机/不同使用场景的情况下都需要计算摄像头里提供的分辨率列表中最合适的那一个分辨率.所以在需要大量机型适配的app,是不建议不经过计算直接自定义分辨率设置到预览或者拍照照片中,有概率会因为摄像头不支持你输入的自定义分辨率导致报错或者打不开摄像头.

  如果你的确有需求要自定义分辨率,那么使用场景只有一个那就是你是在开发Android设备,并且你输入的自定义分辨率确定在这个设备上不会报错.

  目前本人总结的2个分辨率计算方法有2个:

  •   求最佳比例正方形分辨率
  •   求最满足宽度的情况下,在找到最接近高度的分辨率.

  下面我就来解释这个2个计算方法.

求最佳比例正方形分辨率

  较为歪门邪道的方法,核心就是TextureView的宽高比与摄像头的高宽比做差值比较,注意这里一个是宽高一个是高宽,求出来的结果就是在指定指定比例最接近正方形的分辨率

  优点:因为是正方形的分辨率,所以在预览的时候不管是什么尺寸的TextureView的都能显示的不会变形.所以比较适合在小尺寸TextureView上

  缺点:在预览的时候其实无法完全显示完整(正方形不管怎么样都有可能上下或者左右超出View的大小),所以TextureView会自动忽略四周部分,只显示最中间的部分.这样拍照的时候就会发现预览与实际照片显示范围不一致.

  /**
* 获取匹配的大小 这里是Camera2获取分辨率数组的方式,Camera1获取不同,计算一样
* @return
*/
private Size getMatchingSize(){
Size selectSize = null;
float selectProportion = 0;
try {
float viewProportion = (float)mTextureView.getWidth() / (float)mTextureView.getHeight();//计算View的宽高比
CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCurrentCameraId);
StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] sizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
for (int i = 0; i < sizes.length; i++){
Size itemSize = sizes[i];
float itemSizeProportion = (float)itemSize.getHeight() / (float)itemSize.getWidth();//计算当前分辨率的高宽比
float differenceProportion = Math.abs(viewProportion - itemSizeProportion);//求绝对值
Log.e(TAG, "相减差值比例="+differenceProportion );
if (i == 0){
selectSize = itemSize;
selectProportion = differenceProportion;
continue;
}
if (differenceProportion <= selectProportion){ //判断差值是不是比之前的选择的差值更小
if (differenceProportion == selectProportion){ //如果差值与之前选择的差值一样
if (selectSize.getWidth() + selectSize.getHeight() < itemSize.getWidth() + itemSize.getHeight()){//选择分辨率更大的Size
selectSize = itemSize;
selectProportion = differenceProportion;
} }else {
selectSize = itemSize;
selectProportion = differenceProportion;
}
}
} } catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e(TAG, "getMatchingSize: 选择的比例是="+selectProportion);
Log.e(TAG, "getMatchingSize: 选择的尺寸是 宽度="+selectSize.getWidth()+"高度="+selectSize.getHeight());
return selectSize;
}

求最满足宽度的情况下,在找到最接近高度的分辨率

  这个是最正常的算法了,核心就是找到与屏幕宽度最接近的分辨率,然后在找最接近屏幕高度的分辨率.这里是屏幕宽度是最高优先级的,其次在满足高度.

  优点:预览图像与拍照照片的效果完全一致.

  缺点:

  1.   只能满足全屏幕预览的拍照情况下,各种奇葩自定义大小的TextureView你基本上不可能找到满足的宽度的分辨率.
  2.   因为需要让TextureView的高度跟随分辨率高度,所以预览的上面或者下面可能会有需要留出空白区域的情况.(可以用黑色背景View填充),全屏预览的时候可以忽略这个情况,因为基本上手机的摄像头都会有一个分辨率刚好与屏幕分辨率一致.但是不排除个别奇葩手机

  在看代码前这里说明一个重要知识!摄像头分辨率的宽度和高度与屏幕分辨率的宽度和高度的对应

  1.摄像头分辨率的宽度和高度其实是手机横屏下的才是正确方向.如下图所示

  

  2.屏幕的分辨率的宽度和高度依然是手机竖屏下的高度和宽度.

  

代码部分

private Size getMatchingSize2(){
Size selectSize = null;
try {
CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCurrentCameraId);
StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] sizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); //因为我这里是将预览铺满屏幕,所以直接获取屏幕分辨率
int deviceWidth = displayMetrics.widthPixels; //屏幕分辨率宽
int deviceHeigh = displayMetrics.heightPixels; //屏幕分辨率高
Log.e(TAG, "getMatchingSize2: 屏幕密度宽度="+deviceWidth);
Log.e(TAG, "getMatchingSize2: 屏幕密度高度="+deviceHeigh );
/**
* 循环40次,让宽度范围从最小逐步增加,找到最符合屏幕宽度的分辨率,
* 你要是不放心那就增加循环,肯定会找到一个分辨率,不会出现此方法返回一个null的Size的情况
* ,但是循环越大后获取的分辨率就越不匹配
*/
for (int j = 1; j < 41; j++) {
for (int i = 0; i < sizes.length; i++) { //遍历所有Size
Size itemSize = sizes[i];
Log.e(TAG,"当前itemSize 宽="+itemSize.getWidth()+"高="+itemSize.getHeight());
//判断当前Size高度小于屏幕宽度+j*5 && 判断当前Size高度大于屏幕宽度-j*5
if (itemSize.getHeight() < (deviceWidth + j*5) && itemSize.getHeight() > (deviceWidth - j*5)) {
if (selectSize != null){ //如果之前已经找到一个匹配的宽度
if (Math.abs(deviceHeigh-itemSize.getWidth()) < Math.abs(deviceHeigh - selectSize.getWidth())){ //求绝对值算出最接近设备高度的尺寸
selectSize = itemSize;
continue;
}
}else {
selectSize = itemSize;
} }
} }
} catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e(TAG, "getMatchingSize2: 选择的分辨率宽度="+selectSize.getWidth());
Log.e(TAG, "getMatchingSize2: 选择的分辨率高度="+selectSize.getHeight());
return selectSize;
}

Android开发 Camera2开发_2_预览分辨率或拍照分辨率的计算的更多相关文章

  1. Android开发实践:掌握Camera的预览方向和拍照方向

    http://ticktick.blog.51cto.com/823160/1592267?utm_source=tuicool&utm_medium=referral Android的Cam ...

  2. Android开发 Camera2开发_1_拍照功能开发

    介绍 google已经在Android5.1之后取消了对Camera1的更新,转而提供了功能更加强大的Camera2.虽然新版本依然可以使用Camera1但是,不管是各种机型适配还是拍照参数自定义都是 ...

  3. 李洪强iOS开发之苹果使用预览截图

    李洪强iOS开发之苹果使用预览截图 01 在预览的图片中选中你要截得区域  02 - command + C   03 - Command + N 04 - Command + S (保存)

  4. Android 开发 Camera2开发_3_处理预览和拍照偏暗问题

    通过调整曝光解决 参考:https://stackoverflow.com/questions/28429071/camera-preview-is-too-dark-in-low-light-and ...

  5. 玩转Android Camera开发(二):使用TextureView和SurfaceTexture预览Camera 基础拍照demo

    Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...

  6. 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

    杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级.后来随着我自己的使用,越来越发现不出个升级版的demo是不行了.有时候就连我自己用这个demo测一些性能. ...

  7. Android Camera开发:使用TextureView和SurfaceTexture预览Camera 基础拍照demo

    Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...

  8. Android Camera开发:使用GLSurfaceView预览Camera 基础拍照

    GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而且在预览Camera上有其独到之处.独到之处在哪?当使用Surfaceview无能为力.痛不欲生时就只有使用GLSur ...

  9. Android开发:实时处理摄像头预览帧视频------浅析PreviewCallback,onPreviewFrame,AsyncTask的综合应用(转)

    原文地址:http://blog.csdn.net/yanzi1225627/article/details/8605061# 很多时候,android摄像头模块不仅预览,拍照这么简单,而是需要在预览 ...

随机推荐

  1. 【JZOJ6294】动态数点

    description analysis 这题出的失败在只卡正解不卡暴力 比较好想的方法是枚举约数,向两边二分,但是这个不满足二分性 首先用\(ST\)表维护区间的\(\gcd\),不用线段树,这样查 ...

  2. 带撤销贪心——cf1148F好题

    自己不会做,看了题解懂得 从最高位依次往低位遍历,因为偶数个1是不改变符号的,所以带个贪心即可(可以看成是带撤销的..) 每轮循环用sum记录该位选择1可以减少的值 如果是负数,就不要改成1 如果是正 ...

  3. 微信小程序 主题皮肤切换(switch开关)

    示例效果: 功能点分析: 1.点击switch开关,切换主题皮肤(包括标题栏.底部tabBar):2.把皮肤设置保存到全局变量,在访问其它页面时也能有效果3.把设置保存到本地,退出应用再进来时,依然加 ...

  4. 17.splash_case02

    # 抓取<我不是药神>的豆瓣评论 import csv import time import requests from lxml import etree fw = open('doub ...

  5. linux xargs命令一(与find ls等命令组合)(转)

    -p 操作具有可交互性,每次执行comand都交互式提示用户选择 -i -i 选项告诉 xargs 可以使用{}代替传递过来的参数, 建议使用-I,其符合POSIX标准 -I 格式: xargs  - ...

  6. java-day04

    IntelliJ快捷键 导入包 alt + enter 删除光标所在行 ctrl + y 复制光标所在行 ctrl + d 格式代码 ctrl + alt + l 单行注释 ctrl + / 多行注释 ...

  7. js 仿微信投诉—引入vue.js,拆分组件为单个js

    效果 页面目录 index.html <!DOCTYPE html > <html> <head> <meta charset="UTF-8&quo ...

  8. 2019-7-2-asp-dotnet-core-通过图片统计-csdn-用户访问

    title author date CreateTime categories asp dotnet core 通过图片统计 csdn 用户访问 lindexi 2019-7-2 19:21:2 +0 ...

  9. Nand Flash 控制器中的硬件 ECC 介绍

    ECC 产生方法 ECC 是用于对存储器之间传送数据正确进行校验的一种算法,分硬件 ECC 和软件 ECC 算法两种,在 S3C2410 的 Nand Flash 控制器中实现了由硬件电路(ECC 生 ...

  10. IPMI 远程配置

    #重启ipmi服务 #重启ipmi服务 #将 channel 1 设置为静态 IP #设置 IP #设置 channel 1 掩码 #设置 channel 1 网关 #查看用户名及 ID #设置ID号 ...