转换输出

CameraX 用例的输出由两部分组成:缓冲区和转换信息。缓冲区是一个字节数组,而转换信息指明在向最终用户显示缓冲区之前应如何对其进行剪裁和旋转。转换的应用方式取决于缓冲区的格式。

ImageCapture

对于 ImageCapture 用例,剪裁矩形缓冲区会先应用,然后再保存到磁盘,并且旋转信息会保存在 Exif 数据中。应用无需执行任何其他操作。

预览

对于 Preview 用例,您可以通过调用 SurfaceRequest.setTransformationInfoListener() 获取转换信息。每次更新转换信息时,调用方都会收到一个新的 SurfaceRequest.TransformationInfo 对象。

转换信息的应用方式取决于 Surface 的来源,通常比较琐碎。如果目标只是显示预览,请使用 PreviewViewPreviewView 是自动处理转换信息的自定义视图。对于需要修改预览流(例如,使用 OpenGL 修改)的高级用途,请查看 CameraX 核心测试应用中的代码示例。

转换坐标

另一个常见任务是处理坐标(而不是缓冲区),例如预览时围绕检测到的人脸绘制一个框。在这种情况下,您需要将检测到的人脸的坐标从图片分析转换为预览。

以下代码段会创建一个矩阵,将用于图片分析的坐标映射到 PreviewView 坐标。如需使用 Matrix 转换 (x, y) 坐标,请参阅 Matrix.mapPoints()

Kotlin

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
}

Java

Matrix getMappingMatrix(ImageProxy imageProxy, PreviewView previewView) {
   Rect cropRect = imageProxy.getCropRect();
   int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
   Matrix matrix = new Matrix();

   // A float array of the source vertices (crop rect) in clockwise order.
   float[] source = {
       cropRect.left,
       cropRect.top,
       cropRect.right,
       cropRect.top,
       cropRect.right,
       cropRect.bottom,
       cropRect.left,
       cropRect.bottom
   };

   // A float array of the destination vertices in clockwise order.
   float[] destination = {
       0f,
       0f,
       previewView.getWidth(),
       0f,
       previewView.getWidth(),
       previewView.getHeight(),
       0f,
       previewView.getHeight()
   };

   // 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.
   int vertexSize = 2;
   // The destination needs to be shifted 1 vertex for every 90° rotation.
   int shiftOffset = rotationDegrees / 90 * vertexSize;
   float[] tempArray = destination.clone();
   for (int toIndex = 0; toIndex < source.length; toIndex++) {
       int fromIndex = (toIndex + shiftOffset) % source.length;
       destination[toIndex] = tempArray[fromIndex];
   }
   matrix.setPolyToPoly(source, 0, destination, 0, 4);
   return matrix;
}