Zoom Camera2 Preview using TextureView

后端 未结 5 1952
清歌不尽
清歌不尽 2020-12-03 03:45

i have a Problem with my Preview Zoom for the Camera2 API. I am using a TextureView.

I want to zoom only the preview Stream that was showed in the TextureView.

5条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-03 04:33

    Thanks to @arin 's answer, I made an improved version.

    His code is basically working, but there are 2 problems:
    1) Readability - actually I don't know what is going on calculating the Rect zoom
    2) In my Android 7.1.1 device, the preview will freeze if the zoom is big to a certain extent. Since I solved this problem with the code below, I am pretty sure it is because the original code allowed over-zooming beyond camera's maximum zoom ratio.
    (In fact, I don't know why he needs to apply *10 on the ratio returned by CameraCharacteristics)

    Below are my codes: (I do this all inside my custom TextureView, which also stores my Camera2 objects and logics):

    Related Member variables:

    protected CameraCharacteristics cameraCharacteristics;
    protected CameraCaptureSession captureSession;
    protected CaptureRequest.Builder previewRequestBuilder;
    
    //Zooming
    protected float fingerSpacing = 0;
    protected float zoomLevel = 1f;
    protected float maximumZoomLevel;
    protected Rect zoom;
    

    Right after you get CameraCharacteristics from CameraManager, probably in some initial setup:

    maximumZoomLevel = cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
    

    override onTouchEvent:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        try {
            Rect rect = cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
            if (rect == null) return false;
            float currentFingerSpacing;
    
            if (event.getPointerCount() == 2) { //Multi touch.
                currentFingerSpacing = getFingerSpacing(event);
                float delta = 0.05f; //Control this value to control the zooming sensibility
                if (fingerSpacing != 0) {
                    if (currentFingerSpacing > fingerSpacing) { //Don't over zoom-in
                        if ((maximumZoomLevel - zoomLevel) <= delta) {
                            delta = maximumZoomLevel - zoomLevel;
                        }
                        zoomLevel = zoomLevel + delta;
                    } else if (currentFingerSpacing < fingerSpacing){ //Don't over zoom-out
                        if ((zoomLevel - delta) < 1f) {
                            delta = zoomLevel - 1f;
                        }
                        zoomLevel = zoomLevel - delta;
                    }
                    float ratio = (float) 1 / zoomLevel; //This ratio is the ratio of cropped Rect to Camera's original(Maximum) Rect
                    //croppedWidth and croppedHeight are the pixels cropped away, not pixels after cropped
                    int croppedWidth = rect.width() - Math.round((float)rect.width() * ratio);
                    int croppedHeight = rect.height() - Math.round((float)rect.height() * ratio);
                    //Finally, zoom represents the zoomed visible area
                    zoom = new Rect(croppedWidth/2, croppedHeight/2,
                            rect.width() - croppedWidth/2, rect.height() - croppedHeight/2);
                    previewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
                }
                fingerSpacing = currentFingerSpacing;
            } else { //Single touch point, needs to return true in order to detect one more touch point
                return true;
            }
            captureSession.setRepeatingRequest(previewRequestBuilder.build(), captureCallback, null);
            return true;
        } catch (final Exception e) {
            //Error handling up to you
            return true;
        }
    }
    

    And the getFingerSpacing method:

    private 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);
    }
    

    Finally don't forget to set the crop region when you actually take the photo. My code is base on this Camera2Basic, I do this inside the captureStillPicture() method:

            //Zoom
            if (zoom != null) {
                captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
            }
    

提交回复
热议问题