zoukankan      html  css  js  c++  java
  • Camera2点击对焦实现2

    https://www.aliyun.com/jiaocheng/22218.html

      • 阿里云  >  教程中心   >  android教程  >  Camera2点击对焦实现  
      • Camera2点击对焦实现
      • 发布时间:2018-01-18 来源:网络 上传者:用户

        关键字: 对焦 Camera2 实现 点击

        发表文章
      • 摘要:android从5.0开始,废弃了原有的Camera接口,提供了全新的Camera2接口。Camera2接口为了给app提供更强大更低级的摄像头控制,将整个的摄像头框架及流程进行了修改。在使用Camera2时,发现手工对焦的实现逻辑与旧的Camera实现该逻辑有较大不同,本文就谈下如何使用Camera2进行手工对焦。1.操作摄像头进行对焦mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS,newMeteri

      • android从5.0开始,废弃了原有的Camera接口,提供了全新的Camera2接口。Camera2接口为了给app提供更强大更低级的摄像头控制,将整个的摄像头框架及流程进行了修改。在使用Camera2时,发现手工对焦的实现逻辑与旧的Camera实现该逻辑有较大不同,本文就谈下如何使用Camera2进行手工对焦。


        1. 操作摄像头进行对焦 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[] {new MeteringRectangle(rect, 1000)}); 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[] {new MeteringRectangle(rect, 1000)}); 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO); 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START); 
        mPreviewRequest = mPreviewRequestBuilder.build(); 
        try { 
        mCaptureSession.setRepeatingRequest(mPreviewRequest, mAfCaptureCallback, mBackgroundHandler); 
        } catch (CameraAccessException e) { 
        Log.e(TAG, "setRepeatingRequest failed, " + e.getMessage()); 

        主要步骤:


        指定自动对焦和自动嚗光测量的区域,这个区域就是手指点击的图像区域。 
        指定自动对焦模式为 CONTROL_AF_MODE_AUTO 模式,非点击对焦的时候,模式应该为CONTROL_AF_MODE_CONTINUOUS_PICTURE 或者 CONTROL_AF_MODE_CONTINUOUS_VIDEO。 
        将对焦的状态修改为开始对焦 
        触发连续获取图像数据 
        2. 对焦完成恢复正常的预览模式 
        if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState 
        || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) { 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO); 
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); 
        mPreviewRequest = mPreviewRequestBuilder.build(); 
        try { 
        mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler); 
        } catch (CameraAccessException e) { 
        Log.e(TAG, "setRepeatingRequest failed, errMsg: " + e.getMessage()); 


        点击对焦完成后,将对焦模式修改为 CONTROL_AF_MODE_CONTINUOUS_VIDEO。


        3. 计算自动对焦区域 

        CONTROL_AF_REGIONS 的参数是指定用来测量对焦的区域,摄像头设备使用这个区域来测量光度情况进行对焦,因此该区域坐标系基于摄像头成像区域的坐标系。那么app接收到的图像数据与成像区域的关系如何呢?


        手机摄像头成像区域是固定的,因此系统对于app中需要采集不同分辨率的需求做法是:将成像区域按照需要的分辨率比例进行居中裁剪,然后缩放到对应的尺寸。


        Camera2通过不同的接口,给应用层提供了这方面的信息:



        SENSOR_INFO_PIXEL_ARRAY_SIZE 表示的是摄像头成像区域所使用的内存大小。 
        SENSOR_INFO_ACTIVE_ARRAY_SIZE 表示真正接收光线的区域,因此成像的区域是该参数指定的区域,当然该矩形区域的坐标系基于SENSOR_INFO_PIXEL_ARRAY_SIZE 。 
        SCALER_CROP_REGION 表示最终的输出内容是基于 SENSOR_INFO_ACTIVE_ARRAY_SIZE 裁剪的部分,而该值指定裁剪的区域。 

        Camera2点击对焦实现 
        摄像头输出裁剪区域 

        如图:整个区域(2000 x 1500)是整个成像所使用的内存区域,蓝色部分(crop region)是输出内容是使用的裁剪区域(根据我的测试结果发现,crop region基本等于成像区域大小),绿色的和橘黄色的部分就是不同分辨率所使用的区域。


        了解该裁剪流程之后,就可以知道如何计算对焦区域了:


        一般app拿到摄像头来的数据之后,会将摄像头进行合适的旋转,然后根据屏幕比例居中裁剪图像数据,再进行显示。所以我们先将屏幕上面点击区域的坐标转化为app收到的图像区域的坐标: 
        // 先取相对于view上面的坐标 
        double x = event.getX(), y = event.getY(), tmp; 
        // 取出来的图像如果有旋转角度的话,则需要将宽高交换下 
        int realPreviewWidth = mPreviewSize.width, realPreviewHeight = mPreviewSize.height; 
        if (90 == mDisplayRotate || 270 == mDisplayRotate) { 
        realPreviewWidth = mPreviewSize.height; 
        realPreviewHeight = mPreviewSize.width; 

        // 计算摄像头取出的图像相对于view放大了多少,以及有多少偏移 
        double imgScale = 1.0, verticalOffset = 0, horizontalOffset = 0; 
        if (realPreviewHeight * viewWidth > realPreviewWidth * viewHeight) { 
        imgScale = viewWidth * 1.0 / realPreviewWidth; 
        verticalOffset = (realPreviewHeight - viewHeight / imgScale) / 2; 
        } else { 
        imgScale = viewHeight * 1.0 / realPreviewHeight; 
        horizontalOffset = (realPreviewWidth - viewWidth / imgScale) / 2; 

        // 将点击的坐标转换为图像上的坐标 
        x = x / imgScale + horizontalOffset; 
        y = y / imgScale + verticalOffset; 
        if (90 == mDisplayRotate) { 
        tmp = x; x = y; y = mPreviewSize.height - tmp; 
        } else if (270 == mDisplayRotate) { 
        tmp = x; x = mPreviewSize.width - y; y = tmp; 

        app取到的图像是按照裁剪区域(crop region)按照预览尺寸的比例进行居中裁剪的,所以需要计算app取到的图像相对于裁剪区域进行了多少缩放,以及有多少位移: 
        // 计算取到的图像相对于裁剪区域的缩放系数,以及位移 
        Rect cropRegion = mPreviewRequest.get(CaptureRequest.SCALER_CROP_REGION); 
        if (null == cropRegion) { 
        Log.e(TAG, "can't get crop region"); 
        cropRegion = mActiveArraySize; 

        int cropWidth = cropRegion.width(), cropHeight = cropRegion.height(); 
        if (mPreviewSize.height * cropWidth > mPreviewSize.width * cropHeight) { 
        imgScale = cropHeight * 1.0 / mPreviewSize.height; 
        verticalOffset = 0; 
        horizontalOffset = (cropWidth - imgScale * mPreviewSize.width) / 2; 
        } else { 
        imgScale = cropWidth * 1.0 / mPreviewSize.width; 
        horizontalOffset = 0; 
        verticalOffset = (cropHeight - imgScale * mPreviewSize.height) / 2; 

        将点击区域相对于app取到的图像坐标,转化为相对于成像区域的坐标: 
        // 将点击区域相对于图像的坐标,转化为相对于成像区域的坐标 
        x = x * imgScale + horizontalOffset + cropRegion.left; 
        y = y * imgScale + verticalOffset + cropRegion.top; 
        按照对焦区域为成像区域的0.1倍计算对焦的矩形: 
        double tapAreaRatio = 0.1; 
        Rect rect = new Rect(); 
        rect.left = clamp((int) (x - tapAreaRatio / 2 * cropRegion.width()), 0, cropRegion.width()); 
        rect.right = clamp((int) (x + tapAreaRatio / 2 * cropRegion.width()), 0, cropRegion.width()); 
        rect.top = clamp((int) (y - tapAreaRatio / 2 * cropRegion.height()), 0, cropRegion.height()); 
        rect.bottom = clamp((int) (y + tapAreaRatio / 2 * cropRegion.height()), 0, cropRegion.height()); 
        4. 总结 

        Camera2相对于就的Camera api来说,使用复杂度提升不少,但是提供更多的操作空间。同时,由于从Android 5.0就开始提供Camera2的接口,而有些机器并不一定支持全部的Camera2特性,所以需要通过 android.info.supportedHardwareLevel 查询支持的程度:


        LEGACY:app调用Camera2的接口时,由框架将其转调给Camera API1来实现对应的功能,因此不支持Camera2的某些特性,如:每帧控制。 
        FULL:设备支持所有的Camera2接口。 
        LIMITED:设备支持部分的Camera2接口。 

        demo地址在这,demo中并没有查询级别,如果demo跑得不正常时,可以检查下支持级别是否是FULL。


        文中的理解来自于下面几篇文章,有任何问题,欢迎指教:


        http://source.android.com/devices/camera/camera3_crop_reprocess.html 
        https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html#SCALER_CROP_REGION 
        https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SENSOR_INFO_ACTIVE_ARRAY_SIZE
        https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SENSOR_INFO_PIXEL_ARRAY_SIZE



      • 以上是

    Camera2点击对焦实现

        的内容,更多 

    对焦 Camera2 实现 点击 

        的内容,请您使用右上方搜索功能获取相关信息。
      •  1 2 3 4 
      • 相关文章
  • 相关阅读:
    Vue 面试题汇总
    SSIS 通过OData源连接Dynamic 365 Online
    SQL Server AlwaysOn
    SQL Server AlwaysOn
    SQL Server AlwaysOn
    SQL Server AlwaysOn
    OGG同步ORACLE至SQLSERVER(转)
    Power BI Online管理数据源
    SSRS 动态设置分组依据及行组个数
    查看Reporting Services服务器中用户查询报表历史记录
  • 原文地址:https://www.cnblogs.com/jukan/p/9896470.html
Copyright © 2011-2022 走看看