Android Camera2 API,如何使用转换矩阵获得覆盖整个屏幕的预览图像?

Android Camera2 API,如何使用转换矩阵获得覆盖整个屏幕的预览图像?,android,matrix,camera,transform,orientation,Android,Matrix,Camera,Transform,Orientation,考虑以下代码: @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { int rotation = getWindowManager().getDefaultDisplay().getRotation(); if (rotation != prevRotation) { int angle = ORIENTATIONS_REAL

考虑以下代码:

        @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        if (rotation != prevRotation) {
            int angle = ORIENTATIONS_REAL.get(rotation);
            Log.d(LOGTAG, "Rotation = " + angle);
            if (angle == 90 || angle == 270) {
                angle = ORIENTATIONS.get(rotation);
                float centerX = cameraRectF.centerX();
                float centerY = cameraRectF.centerY();
                int rotAngle = (angle + sensorOrientation + 180) % 360; // Formula correct
                transformMatrix.postRotate(rotAngle, centerX, centerY);
            } else {
                transformMatrix.reset();
            }
            textureView.setTransform(transformMatrix);
            prevRotation = rotation;
        }
    }
以下是一些定义:

    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private static final SparseIntArray ORIENTATIONS_REAL = new SparseIntArray();
static {
    ORIENTATIONS_REAL.append(Surface.ROTATION_0, 0);
    ORIENTATIONS_REAL.append(Surface.ROTATION_90, 90);
    ORIENTATIONS_REAL.append(Surface.ROTATION_180, 180);
    ORIENTATIONS_REAL.append(Surface.ROTATION_270, 270);
}

private Size imageDimensions = null;
private Matrix transformMatrix = new Matrix();
private RectF previewRectF = null;
private RectF cameraRectF = null;
private int sensorOrientation = 0;

private TextureView textureView = null;
private SurfaceTexture surfaceTexture = null;
private Button buttonTakePicture = null;

// Some misc stuff
private int prevRotation = 0;
请注意,传感器方向是在打开例行程序中从摄像机特性设置的

我一直在尝试在三星Galaxy S7上正确显示方向。结果表明,传感器已从手持电话旋转90°。上述代码考虑了报告的传感器方向,并计算所需的正确旋转角度。现在的问题是,当手机从纵向旋转到横向时,相机预览图像不会覆盖整个屏幕。请参见下面的屏幕截图

现在的问题是,如何让相机预览覆盖屏幕,而不是只覆盖屏幕的一部分?上述代码是根据此处的答案改编的:

然而,我没有第二套宽度和高度可供使用,我也不知道从哪里获得它们。我尝试过的是把相机的分辨率转换成地图,但是失败的非常惊人。部分问题是我对转换及其工作方式不太熟悉。我知道它们通常是由矩阵处理的,有很多矩阵数学,但我已经有一段时间没有看到或甚至没有玩过这样的代码了(上次是在2年前的一节课上)?建议

谢谢


编辑:我希望该应用程序或多或少在纵向模式下使用,但我必须处理横向模式,以防用户旋转设备。

嗯,看起来我最终回答了自己的问题。最初,我是从我的答案开始的。这段代码有一个bug。特别是缩放。有了这些,再加上一些其他的改变,我就能让它工作了。链接的答案是在你打开摄像机之前打电话,这是我最初做的。因此,当方向从纵向变为横向(反之亦然)时,系统将重新启动活动。但是,如果您快速翻转设备,使其仍处于横向但倒置状态,则图像将显示为向外旋转180°,因为最终旋转仍为横向,并且系统不会重新启动活动。因此,将代码放在surface changed回调例程中可以保证,无论活动是否重新启动,只要方向发生变化,都会调用代码

以下是修订后的代码:

        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            if (rotation != prevRotation) {
            prevRotation = rotation;
            RectF cameraRectF = new RectF(0, 0, imageDimensions.getWidth(), imageDimensions.getHeight());
            RectF textureRectF = new RectF(0, 0, textureView.getHeight(), textureView.getWidth());
            float centerX = cameraRectF.centerX();
            float centerY = cameraRectF.centerY();
            if (rotation != Surface.ROTATION_0) {
                textureRectF.offset(centerX - textureRectF.centerX(), centerY - textureRectF.centerY());
                transformMatrix.setRectToRect(cameraRectF, textureRectF, Matrix.ScaleToFit.FILL);
                float scale = Math.max(
                        (float) textureRectF.right / cameraRectF.right,
                        (float) textureRectF.bottom / cameraRectF.bottom);
                transformMatrix.postScale(scale, scale, centerX, centerY);
                if (rotation != Surface.ROTATION_180) {
                    int angle = (ORIENTATIONS_REAL.get(rotation) + sensorOrientation +
                            ORIENTATIONS_SENSOR.get(sensorOrientation)) % 360;
                    transformMatrix.postRotate(angle, centerX, centerY);
                } else {
                    transformMatrix.postRotate(180, centerX, centerY);
                }
            } else {
                transformMatrix.reset();
            }
        }
        textureView.setTransform(transformMatrix);
    }
我的代码还考虑了传感器的方向,所以它应该可以在任何设备上工作。我有三个不同的设备,其中两个报告传感器方向为90°。第三个设备报告传感器方向为0°。因此,通过一点实验,我提出了一个表格,根据传感器的旋转角度为最终旋转角度增加一个常数。以下是方向的定义。方向传感器见上述表格

private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private static final SparseIntArray ORIENTATIONS_REAL = new SparseIntArray();
static {
    ORIENTATIONS_REAL.append(Surface.ROTATION_0, 0);
    ORIENTATIONS_REAL.append(Surface.ROTATION_90, 90);
    ORIENTATIONS_REAL.append(Surface.ROTATION_180, 180);
    ORIENTATIONS_REAL.append(Surface.ROTATION_270, 270);
}
private static final SparseIntArray ORIENTATIONS_SENSOR = new SparseIntArray();
static {
    ORIENTATIONS_SENSOR.append(0, 180);
    ORIENTATIONS_SENSOR.append(90, 90);
    ORIENTATIONS_SENSOR.append(180, 0);
    ORIENTATIONS_SENSOR.append(270, -90);
}
虽然我只能从表中测试0°和90°,但我邀请其他拥有报告传感器方向为180°和270°的设备的人验证我的计算是否正确