Girar una matriz de bytes YUV en Android

Estoy buscando rotar una vista previa de marco YUV recibida de una vista previa Callblack, hasta ahora he fundado esta publicación que mantiene un algoritmo para girar la vista previa de marco, pero está ensuciando los píxeles de la cámara de vista previa girados

Otra forma de rotar la imagen será crear un jpg de la imagen YUV, crear un bitmap, rotar un bitmap y obtener la matriz de bytes del bitmap, pero realmente necesito el formato en YUV (NV21).

FYI. La razón por la que estoy preguntando esto es porque tengo una aplicación de cámara que admite rotación, pero las vistas previas de cuadros vuelven solo en modo horizontal.

El siguiente método puede rotar una matriz de bytes YUV420 90 grados.

 private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) { byte [] yuv = new byte[imageWidth*imageHeight*3/2]; // Rotate the Y luma int i = 0; for(int x = 0;x < imageWidth;x++) { for(int y = imageHeight-1;y >= 0;y--) { yuv[i] = data[y*imageWidth+x]; i++; } } // Rotate the U and V color components i = imageWidth*imageHeight*3/2-1; for(int x = imageWidth-1;x > 0;x=x-2) { for(int y = 0;y < imageHeight/2;y++) { yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x]; i--; yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)]; i--; } } return yuv; } 

(Tenga en cuenta que esto solo podría funcionar si el ancho y la altura es un factor de 4)

Estas son las opciones para girar una esquina diferente (90, 180, 270):

 public static byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) { byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2]; // Rotate the Y luma int i = 0; for (int x = 0; x < imageWidth; x++) { for (int y = imageHeight - 1; y >= 0; y--) { yuv[i] = data[y * imageWidth + x]; i++; } } // Rotate the U and V color components i = imageWidth * imageHeight * 3 / 2 - 1; for (int x = imageWidth - 1; x > 0; x = x - 2) { for (int y = 0; y < imageHeight / 2; y++) { yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x]; i--; yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)]; i--; } } return yuv; } private static byte[] rotateYUV420Degree180(byte[] data, int imageWidth, int imageHeight) { byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2]; int i = 0; int count = 0; for (i = imageWidth * imageHeight - 1; i >= 0; i--) { yuv[count] = data[i]; count++; } i = imageWidth * imageHeight * 3 / 2 - 1; for (i = imageWidth * imageHeight * 3 / 2 - 1; i >= imageWidth * imageHeight; i -= 2) { yuv[count++] = data[i - 1]; yuv[count++] = data[i]; } return yuv; } public static byte[] rotateYUV420Degree270(byte[] data, int imageWidth, int imageHeight) { byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2]; int nWidth = 0, nHeight = 0; int wh = 0; int uvHeight = 0; if (imageWidth != nWidth || imageHeight != nHeight) { nWidth = imageWidth; nHeight = imageHeight; wh = imageWidth * imageHeight; uvHeight = imageHeight >> 1;// uvHeight = height / 2 } // ??Y int k = 0; for (int i = 0; i < imageWidth; i++) { int nPos = 0; for (int j = 0; j < imageHeight; j++) { yuv[k] = data[nPos + i]; k++; nPos += imageWidth; } } for (int i = 0; i < imageWidth; i += 2) { int nPos = wh; for (int j = 0; j < uvHeight; j++) { yuv[k] = data[nPos + i]; yuv[k + 1] = data[nPos + i + 1]; k += 2; nPos += imageWidth; } } return rotateYUV420Degree180(yuv, imageWidth, imageHeight); } 

Así es como lo hice

Este bloque de código está configurado en otra parte

  Camera.Size size Rect rectangle = new Rect(); rectangle.bottom = size.height; rectangle.top = 0; rectangle.left = 0; rectangle.right = size.width; 

Este es el método que hace el trabajo

  private Bitmap rotateBitmap(YuvImage yuvImage, int orientation, Rect rectangle) { ByteArrayOutputStream os = new ByteArrayOutputStream(); yuvImage.compressToJpeg(rectangle, 100, os); Matrix matrix = new Matrix(); matrix.postRotate(orientation); byte[] bytes = os.toByteArray(); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); return Bitmap.createBitmap(bitmap, 0 , 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } 

comprime el YUVImage en un JPEG para que el bitmap pueda manejarlo. Gire el bitmap y luego expórtelo. Para volver a un JPEG que es como yo lo quería, utilicé esta línea

 image.compress(Bitmap.CompressFormat.JPEG, 50, outputStream);