出力を変換する

CameraX ユースケースの出力には、バッファと変換情報の 2 つがあります。バッファはバイト配列であり、変換情報はエンドユーザーに表示する前にバッファをどのように切り抜き、回転させるかを示します。変換の適用方法は、バッファの形式によって異なります。

ImageCapture

ImageCapture のユースケースでは、切り抜き範囲のバッファが適用され、ディスクに保存されます。回転については Exif データに保存されます。アプリ側で追加の操作を行う必要はありません。

プレビュー

Preview のユースケースでは、SurfaceRequest.setTransformationInfoListener() を呼び出すことで変換情報を取得できます。変換が更新されるたびに、呼び出し元は新しい SurfaceRequest.TransformationInfo オブジェクトを受け取ります。

変換情報の適用方法は Surface のソースによって異なるため、通常は自明ではありません。単にプレビューを表示することが目標の場合は、PreviewView を使用します。PreviewView は、変換を自動的に処理するカスタムビューです。高度な用途の場合、OpenGL などでプレビュー ストリームを編集する必要があるときは、CameraX コアテスト アプリのコードサンプルをご覧ください。

座標を変換する

もう 1 つの一般的なタスクは、検出された顔の周囲にボックスを描画するなど、バッファの代わりに座標を使用することです。このような場合、検出された顔の座標を画像解析からプレビューに変換する必要があります。

次のコード スニペットは、画像解析座標から PreviewView 座標にマッピングする行列を作成します。(x, y) 座標を Matrix で変換する方法については、Matrix.mapPoints() をご覧ください。

fun getCorrectionMatrix(imageProxy: ImageProxy, previewView: PreviewView): Matrix {
    val cropRect = imageProxy.cropRect
    val rotationDegrees = imageProxy.imageInfo.rotationDegrees
    val matrix = Matrix()

    // A float array of the source vertices (crop rect) in clockwise order.
    val source = floatArrayOf(
        cropRect.left.toFloat(),
        cropRect.top.toFloat(),
        cropRect.right.toFloat(),
        cropRect.top.toFloat(),
        cropRect.right.toFloat(),
        cropRect.bottom.toFloat(),
        cropRect.left.toFloat(),
        cropRect.bottom.toFloat()
    )

    // A float array of the destination vertices in clockwise order.
    val destination = floatArrayOf(
        0f,
        0f,
        previewView.width.toFloat(),
        0f,
        previewView.width.toFloat(),
        previewView.height.toFloat(),
        0f,
        previewView.height.toFloat()
    )

    // The destination vertexes need to be shifted based on rotation degrees. The
    // rotation degree represents the clockwise rotation needed to correct the image.

    // Each vertex is represented by 2 float numbers in the vertices array.
    val vertexSize = 2
    // The destination needs to be shifted 1 vertex for every 90° rotation.
    val shiftOffset = rotationDegrees / 90 * vertexSize
    val tempArray = destination.clone()
    for (toIndex in source.indices) {
        val fromIndex = (toIndex + shiftOffset) % source.size
        destination[toIndex] = tempArray[fromIndex]
    }
    matrix.setPolyToPoly(source, 0, destination, 0, 4)
    return matrix
}