AndroidCamera-TouchToFocusMeteringZoom icon indicating copy to clipboard operation
AndroidCamera-TouchToFocusMeteringZoom copied to clipboard

后置摄像头聚焦位置与实际点击位置不符合

Open waylife opened this issue 7 years ago • 4 comments

后置摄像头聚焦位置与实际点击位置不符合,需要做更进一步的坐标系变换

我在此代码基础上做了一定改动,有需要的同学可以自取。

仅三个函数有改动

    private void handleFocusMetering(MotionEvent event, Camera camera) {
        int viewWidth = getWidth();
        int viewHeight = getHeight();
        Camera.Parameters parameters = camera.getParameters();
        android.hardware.Camera.CameraInfo camInfo =
                new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, camInfo);
        int displayOrientation = camInfo.orientation;
        boolean mirror = (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT ? true : false); //
        Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f, viewWidth, viewHeight, mirror, displayOrientation);
        Rect meteringRect = calculateTapArea(event.getX(), event.getY(), 2.0f, viewWidth, viewHeight, mirror, displayOrientation);
        Log.i(TAG, String.format("handleFocusMetering: mirror=%s,displayOrientation=%s,focusRect=%s", mirror, displayOrientation, focusRect.toString()));

        camera.cancelAutoFocus();
        Camera.Parameters params = camera.getParameters();
        if (params.getMaxNumFocusAreas() > 0) {
            List<Camera.Area> focusAreas = new ArrayList<>();
            focusAreas.add(new Camera.Area(focusRect, 800));
            params.setFocusAreas(focusAreas);
        } else {
            Log.i(TAG, "focus areas not supported");
        }
        if (params.getMaxNumMeteringAreas() > 0) {
            List<Camera.Area> meteringAreas = new ArrayList<>();
            meteringAreas.add(new Camera.Area(meteringRect, 800));
            params.setMeteringAreas(meteringAreas);
        } else {
            Log.i(TAG, "metering areas not supported");
        }
        final String currentFocusMode = params.getFocusMode();
        params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
        camera.setParameters(params);

        camera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                Camera.Parameters params = camera.getParameters();
                params.setFocusMode(currentFocusMode);
                camera.setParameters(params);
            }
        });
    }

private static Rect calculateTapArea(float x, float y, float coefficient, int width, int height, boolean mirror, int displayOrientation) {
        float focusAreaSize = 300;
        int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
        int centerX = (int) (x / width * 2000 - 1000);
        int centerY = (int) (y / height * 2000 - 1000);

        int halfAreaSize = areaSize / 2;
        RectF rectF = new RectF(clamp(centerX - halfAreaSize, -1000, 1000)
                , clamp(centerY - halfAreaSize, -1000, 1000)
                , clamp(centerX + halfAreaSize, -1000, 1000)
                , clamp(centerY + halfAreaSize, -1000, 1000));
        Matrix matrix = new Matrix();
        prepareMatrix(matrix, mirror, displayOrientation);
        matrix.mapRect(rectF);
        return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
    }

    public static void prepareMatrix(Matrix matrix, boolean mirror, int displayOrientation) {
        if (matrix == null) {
            return;
        }
        Matrix _matrix = new Matrix();

        matrix.reset();

        // Need mirror for front camera.
        _matrix.setScale(mirror ? -1 : 1, 1);
        // This is the value for android.hardware.Camera.setDisplayOrientation.
        _matrix.postRotate(displayOrientation);
        _matrix.invert(matrix);//求逆矩阵
    }

    private static int clamp(int x, int min, int max) {
        if (x > max) {
            return max;
        }
        if (x < min) {
            return min;
        }
        return x;
    }

参考 谷歌官方相机https://android.googlesource.com/platform/packages/apps/Camera 项目中的FocusOverlayManager

waylife avatar Jan 26 '18 15:01 waylife

另外发现好多手机前置摄像头都不支持对焦,也就是走了 Log.i(TAG, "focus areas not supported");这条分支。

waylife avatar Jan 26 '18 15:01 waylife

另外,请注意上述代码没有在生成环境中稳定使用,对于可能出现的问题概不负责。

waylife avatar Jan 26 '18 15:01 waylife

谢谢你的反馈~

之前有注意到触摸对焦位置有偏移的问题,并进行了修正,但不知还存在问题,班门弄斧了。

zhantong avatar Jan 29 '18 04:01 zhantong

我是发现右上角和左下角好像对换了,不过我吧xy坐标对换一下发现x轴上有镜像的情况,又做了x镜像。不过楼主的方式比较正规,我是没考虑屏幕方向了,固定竖屏

121657026 avatar Jun 04 '20 03:06 121657026