טרנספורמציה של הפלט

הפלט של תרחיש לדוגמה ב-CameraX הוא דו-שכבתי: מאגר נתונים והמידע על הטרנספורמציה. מאגר הנתונים הוא מערך בייטים, והמידע על הטרנספורמציה הוא אופן החיתוך והסיבוב של מאגר הנתונים לפני שהוא מוצג למשתמשי הקצה. אופן החלת הטרנספורמציה תלוי בפורמט של המאגר.

ImageCapture

בתרחיש לדוגמה ImageCapture, מאגר ה-rect של החיתוך מוחל לפני השמירה בדיסק והסיבוב נשמר בנתוני ה-Exif. אין צורך לבצע פעולה נוספת באפליקציה.

תצוגה מקדימה

בתרחיש לדוגמה Preview, אפשר לקבל את פרטי הטרנספורמציה באמצעות קריאה ל-SurfaceRequest.setTransformationInfoListener(). בכל פעם שהטרנספורמציה מתעדכנת, מבצע הקריאה מקבל אובייקט SurfaceRequest.TransformationInfo חדש.

אופן החלת פרטי הטרנספורמציה תלוי במקור של Surface, ובדרך כלל הוא לא פשוט. אם המטרה היא רק להציג את התצוגה המקדימה, צריך להשתמש ב-PreviewView. PreviewView היא תצוגה מותאמת אישית שמטפלת באופן אוטומטי בטרנספורמציה. לשימושים מתקדמים, כשצריך לערוך את מקור הווידאו של התצוגה המקדימה, למשל באמצעות OpenGL, אפשר לעיין בדוגמת הקוד באפליקציית הבדיקה של הליבה של CameraX.

טרנספורמציה של קואורדינטות

משימה נפוצה נוספת היא לעבוד עם הקואורדינטות במקום עם המאגר, למשל לצייר תיבה סביב הפנים שזוהו בתצוגה המקדימה. במקרים כאלה, צריך להמיר את הקואורדינטות של הפנים שזוהו מניתוח התמונה לתצוגה המקדימה.

קטע הקוד הבא יוצר מטריקס שממפה קואורדינטות של ניתוח תמונה לקווי אורך ורוחב של PreviewView. כדי להמיר את הקואורדינטות (x, y) באמצעות Matrix, אפשר לעיין במאמר 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;
}