Android Camera2相机预览画面放大缩小(数码变焦DigitalZoom)功能实现

一、前言

Android自定义相机开发中,常常会有通过手势放大或缩小相机预览画面的需求,即数码变焦DigitalZoom。

二、接口说明

1. 获取最大的放大倍数

float maxZoom = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);

怎么理解这个值呢?

假设正常预览画面(即没有缩放)矩形为 activity_rect,放大后的预览画面矩形为 crop_rect,那么它们宽高的比值最大就只能为 maxZoom,例如我测试中获取的该值为 10.0。(PS:activity_rect的宽高为分子,crop_rect的宽高是分母)

2. 获取未缩放的正常预览画面大小

Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);

这个大小要用来计算我们最终放大后显示的画面大小。

3. 相机预览请求构造者设置显示的画面区域

mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);

计算得到的 zoomRect,通过上述接口设置给预览。

关于 SCALER_CROP_REGION ,详情可以参考:https://developer.android.com/reference/android/hardware/camera2/CaptureRequest#SCALER_CROP_REGION

三、代码实现

1. 相机View处理触碰事件

private float mOldDistance;

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getPointerCount() == 2) { // 当触碰点有2个时,才去放大缩小
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_POINTER_DOWN:
                // 点下时,得到两个点间的距离为mOldDistance
                mOldDistance = getFingerSpacing(event);
                break;
            case MotionEvent.ACTION_MOVE:
                // 移动时,根据距离是变大还是变小,去放大还是缩小预览画面
                float newDistance = getFingerSpacing(event);
                if (newDistance > mOldDistance) {
                    mCameraProxy.handleZoom(true);
                } else if (newDistance < mOldDistance) {
                    mCameraProxy.handleZoom(false);
                }
                // 更新mOldDistance
                mOldDistance = newDistance;
                break;
            default:
                break;
        }
    }
    return super.onTouchEvent(event);
}

private static float getFingerSpacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return (float) Math.sqrt(x * x + y * y);
}

上面我们只处理了触碰事件,预览放大或缩小的逻辑由 mCameraProxy 的 handleZoom(boolean isZoomIn) 实现。

2. handleZoom() 实现

private final int MAX_ZOOM = 100; // 放大的最大值,用于计算每次放大/缩小操作改变的大小
private int mZoom = 0; // 缩放
private float mStepWidth; // 每次改变的宽度大小
private float mStepHeight; // 每次改变的高度大小

// 每次切换摄像头计算一次就行,结果缓存到成员变量中
private void initZoomParameter() {
    Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    Log.d(TAG, "sensor_info_active_array_size: " + rect);
    // max_digital_zoom 表示 active_rect 除以 crop_rect 的最大值
    float max_digital_zoom = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
    Log.d(TAG, "max_digital_zoom: " + max_digital_zoom);
    // crop_rect的最小宽高
    float minWidth = rect.width() / max_digital_zoom;
    float minHeight = rect.height() / max_digital_zoom;
    // 因为缩放时两边都要变化,所以要除以2
    mStepWidth = (rect.width() - minWidth) / MAX_ZOOM / 2;
    mStepHeight = (rect.height() - minHeight) / MAX_ZOOM / 2;
}

public void handleZoom(boolean isZoomIn) {
    if (mCameraDevice == null || mCameraCharacteristics == null || mPreviewRequestBuilder == null) {
        return;
    }
    if (isZoomIn && mZoom < MAX_ZOOM) { // 放大
        mZoom++;
    } else if (mZoom > 0) { // 缩小
        mZoom--;
    }
    Log.v(TAG, "handleZoom: mZoom: " + mZoom);
    Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    int cropW = (int) (mStepWidth * mZoom);
    int cropH = (int) (mStepHeight * mZoom);
    Rect zoomRect = new Rect(rect.left + cropW, rect.top + cropH, rect.right - cropW, rect.bottom - cropH);
    Log.d(TAG, "zoomRect: " + zoomRect);
    mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
    startPreview(); // 需要重新 start preview 才能生效
}

再简单说明一下上面的代码,因为本身maxZoom的值并不会很大,如果直接使用 1~maxZoom 的 int 值去放大缩小,画面变化就很剧烈,所以设置了一个 MAX_ZOOM = 100 去把这个过程划分成了100份,这个值可以自己设定。所以 mZoom 的判定范围也就变成了 0~MAX_ZOOM 。

再说计算 mStepWidth 和 mStepHeight 的代码。原Rect的宽是 rect.width(),放大到最大时 zoomRect 的宽是 rect.width() / maxZoom,因为有左右两边,所以它们的差值需要除以2,然后划分成 MAX_ZOOM 份,需要再除以 MAX_ZOOM 。

最后,放大时我们让 mZoom 自增1,缩小时让 mZoom 自减1,根据 mZoom 就可以得到剪裁的宽高大大小了。

四、工程地址

完整的代码可见:
https://github.com/afei-cn/CameraDemo/blob/master/app/src/main/java/com/afei/camerademo/camera/Camera2Proxy.java

相关使用实例可见:

自定义Camera系列之:SurfaceView + Camera2

自定义Camera系列之:TextureView + Camera2

自定义Camera系列之:GLSurfaceView + Camera2

  • 16
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: 很抱歉,目前我无法得知Android 13中的Camera Vendor extensions中Google开发了哪些自己的算法。不过,Camera Vendor extensions是提供给设备厂商的API扩展,允许他们在其设备上实现自定义的相机功能和算法。这些扩展可以包括Google开发的算法,也可以是厂商自己开发的算法。由于Android 13尚未正式发布,因此目前还无法确定其中具体包含哪些算法。 ### 回答2: 在Android 13的Camera Vendor extensions中,Google开发了一系列自己的算法。其中包括: 1. Google HDR(高动态范围)算法:该算法利用多帧曝光和图像融合技术,将不同曝光水平的多张照片合成一张具有更广泛动态范围的高质量图像。这有助于在弱光条件下捕获更多细节,同时避免图像的过度曝光或过度阴影。 2. Google Super Res Zoom(超级解析度变焦)算法:该算法利用多张照片的细节信息,通过图像处理技术实现更高质量的数字变焦效果。它可以在相机硬件的限制下提供更清晰、更详细的变焦图像。 3. Google Night Sight(夜光模式)算法:该算法通过利用多帧图像叠加以及图像去噪技术,可在低光条件下拍摄出明亮、低噪声的照片。它可以提高夜间拍摄的细节可见度,并减少噪点和模糊。 4. Google Portrait Light(人像光影)算法:该算法利用深度信息和图像处理技术,可以在后期编辑中调整人像照片中的光照效果。用户可以通过调整光照的方向和强度,轻松创造出更出色的人像照片效果。 需要注意的是,这些算法可能会根据不同的设备和相机硬件而有所差异,具体支持的功能和效果可能会有所不同。 ### 回答3: 在Android 13中的Camera Vendor extensions中,Google开发了几个自己的算法,其中包括: 1. Google Tensor:Google Tensor是一种用于加强图像处理能力的神经网络处理单元(NNPU),旨在提供更出色的图像处理和计算能力。它可以在低功耗设备上进行实时的复杂图像处理,如图像增强、实时滤镜等。 2. Google HDRNet:Google HDRNet是一种用于实现高动态范围(HDR)图像处理的技术。该算法通过在多个曝光下捕获图像并应用特定的图像处理技术,使得在现有设备上可以实现更高质量的HDR图像。 3. Google Super Res Zoom:Google Super Res Zoom是一种用于增强手机相机变焦能力的技术。该算法使用多帧对齐和图像合成技术,通过结合多个图像的细节信息,以实现更高质量的数字变焦效果。 这些由Google开发的算法在Android 13的Camera Vendor extensions中为移动设备带来了更优秀的图像处理能力和功能,提供给开发者和用户更多的创作和体验选择。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值