簡體   English   中英

Android Camera2 API,如何使用變換矩陣使預覽圖像覆蓋整個屏幕?

[英]Android Camera2 API, how does one get the preview image to cover the whole screen using transformation matrices?

考慮以下代碼:

        @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;

請注意,從打開例程中的 CameraCharacteristics 時設置了 sensorOrientation。

我試圖在三星 Galaxy S7 上正確顯示方向時感覺不舒服。 結果是傳感器從手機旋轉了 90°。 上面的代碼考慮了報告的傳感器方向並計算所需的正確旋轉角度。 現在的問題是,當手機從縱向旋轉到橫向時,相機預覽圖像並沒有覆蓋整個屏幕。 請參閱下面的屏幕截圖。

縱向

景觀方向

所以現在的問題是我如何讓相機預覽覆蓋屏幕而不是它的一部分? 上面的代碼改編自這里的答案:

Android Camera2 預覽偶爾旋轉 90 度

但是,我沒有第二組寬度和高度可供使用,我不確定從哪里獲取它們。 我嘗試過的是獲取相機分辨率並將其映射,但這非常失敗。 部分問題是我對轉換及其工作方式並不十分熟悉。 我知道它們通常由具有大量矩陣數學的矩陣處理,但我已經有一段時間沒有看到甚至玩過這樣的代碼(上次是在兩年前的課堂上。)想法? 建議?

謝謝。

編輯:我希望該應用程序或多或少地在縱向模式下使用,但我必須處理橫向模式,以防用戶旋轉設備。

好吧,看來我最終回答了我自己的問題。 最初,我從Android Camera2 preview的答案開始, 偶爾旋轉 90 度 這段代碼有一個錯誤。 特別是縮放。 有了這個,以及其他一些變化,我就可以讓它工作了。 鏈接的答案說在你打開相機之前打電話,我最初是這樣做的。 那么會發生的情況是,當方向從縱向變為橫向(反之亦然)時,系統將重新啟動 Activity。 但是,如果您快速翻轉設備使其仍然處於橫向但顛倒狀態,那么圖像似乎旋轉了 180°,因為最終旋轉仍然是橫向並且系統不會重新啟動 Activity。 因此,將代碼放置在表面更改的回調例程中可確保在方向更改時隨時調用代碼,無論活動是否重新啟動。

這是修改后的代碼:

        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°。 因此,通過一些實驗,我想出了一個表格,該表格將根據傳感器旋轉角度為最終旋轉角度添加一個常數。 以下是方向的定義。 ORIENTATIONS_SENSOR 是前面提到的表。

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° 的設備的其他人來驗證我的計算是否正確。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM