CameraX 用例的输出由两部分组成:缓冲区和转换信息。缓冲区是一个字节数组,而转换信息指明在向最终用户显示缓冲区之前应如何对其进行剪裁和旋转。转换的应用方式取决于缓冲区的格式。
ImageCapture
对于 ImageCapture
用例,剪裁矩形缓冲区会先应用,然后再保存到磁盘,并且旋转信息会保存在 Exif 数据中。应用无需执行任何其他操作。
预览
对于 Preview
用例,您可以通过调用 SurfaceRequest.setTransformationInfoListener()
获取转换信息。每次更新转换信息时,调用方都会收到一个新的 SurfaceRequest.TransformationInfo
对象。
转换信息的应用方式取决于 Surface
的来源,通常比较琐碎。如果目标只是显示预览,请使用 PreviewView
。PreviewView
是自动处理转换信息的自定义视图。对于需要修改预览流(例如,使用 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; }