Convierta la matriz de bytes NV21 en formato legible de mapa de bits

Hola estoy creando una pequeña aplicación de cámara que he implementado todas las cosas, pero tengo un problema que está convirtiendo NV21 matriz de bytes en formato jpeg
He encontrado muchas formas, pero todos ellos incluso no funcionan o funcionan en algunos dispositivos
En primer lugar he probado este fragmento y funciona en Xperia z2 5.2, pero en la galaxia s4 4.4.4

bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 

También esta manera trabaja en el mismo dispositivo y falla en el otro

  int pich = camera.getParameters().getPreviewSize().height; int picw = camera.getParameters().getPreviewSize().width; int[] pix = new int[picw * pich]; bitmap.getPixels(pix, 0, picw, 0, 0, picw, pich); // int R, G, B, Y; for (int y = 0; y < pich; y++) { for (int x = 0; x < picw; x++) { int index = y * picw + x; int R = (pix[index] >> 16) & 0xff; int G = (pix[index] >> 8) & 0xff; int B = pix[index] & 0xff; pix[index] = 0xff000000 | (R << 16) | (G << 8) | B; } } 

En segundo lugar he intentado muchas soluciones para convertir decodificar NV21 primero un código de renderscript

  public Bitmap convertYUV420_NV21toRGB8888_RenderScript(byte [] data,int W, int H, Fragment fragment) { // http://stackoverflow.com/questions/20358803/how-to-use-scriptintrinsicyuvtorgb-converting-byte-yuv-to-byte-rgba RenderScript rs; ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic; rs = RenderScript.create(fragment.getActivity()); yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); //Create an intrinsic for converting YUV to RGB. Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length); Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); //an Allocation will be populated with empty data when it is first created Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H); Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); //an Allocation will be populated with empty data when it is first created in.copyFrom(data);//Populate Allocations with data. yuvToRgbIntrinsic.setInput(in); //Set the input yuv allocation, must be U8(RenderScript). yuvToRgbIntrinsic.forEach(out); //Launch the appropriate kernels,Convert the image to RGB. Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888); out.copyTo(bmpout); //Copy data out of Allocation objects. return bmpout; } 

Y también este código

  void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) { final int frameSize = width * height; for (int j = 0, yp = 0; j < height; j++) { int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; for (int i = 0; i < width; i++, yp++) { int y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } int y1192 = 1192 * y; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); if (r < 0) r = 0; else if (r > 262143) r = 262143; if (g < 0) g = 0; else if (g > 262143) g = 262143; if (b < 0) b = 0; else if (b > 262143) b = 262143; rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); } } } 

Y finalmente intenté guardar la imagen en la tarjeta SD y luego volver a abrirla, pero también falla

 File pictureFile = new File(filename); int pich = camera.getParameters().getPreviewSize().height; int picw = camera.getParameters().getPreviewSize().width; Rect rect = new Rect(0, 0,picw, pich); YuvImage img = new YuvImage(data, ImageFormat.NV21, picw, picw, null); try { FileOutputStream fos = new FileOutputStream(pictureFile); img.compressToJpeg(rect, 100, fos); fos.write(data); fos.close(); 

Y este es el resultado con el último enfoque 3 que tenía seguir Introduzca aquí la descripción de la imagen

Hay algunas maneras de guardar un marco NV21 que viene de la cámara, la manera más fácil de convertirlo a un YuvImage a continuación, guardarlo en un archivo Jpeg:

 FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/imagename.jpg"); YuvImage yuvImage = new YuvImage(nv21bytearray, ImageFormat.NV21, width, height, null); yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, fos); fos.close(); 

Alternativamente, también puede convertirlo en un objeto Bitmap de Android y guardarlo como un formato PNG u otro formato:

 YuvImage yuvImage = new YuvImage(nv21bytearray, ImageFormat.NV21, width, height, null); ByteArrayOutputStream os = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, os); byte[] jpegByteArray = os.toByteArray(); Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length); FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/imagename.png"); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.close(); 

Tenga en cuenta que la última opción hace un NV21 -> JPEG -> Bitmap Object -> PNG file proceso de NV21 -> JPEG -> Bitmap Object -> PNG file así que tenga en cuenta que esta no es una manera muy eficiente para guardar las imágenes de vista previa de la cámara si necesita alto rendimiento.

ACTUALIZACIÓN: Me cansé de cuánto tiempo toma para que esta conversión trabaje así que escribí una biblioteca ( easyRS ) alrededor de RenderScript para hacer esto fácilmente en una línea de código:

 Bitmap outputBitmap = Nv21Image.nv21ToBitmap(rs, nv21ByteArray, width, height); 

Es alrededor de cinco veces más rápido que el proceso JPEG en una imagen de 2000×2000 en un Moto G 2do.

Su segundo intento (con ScriptIntrinsicYuvToRGB) parece prometedor. Con JellyBean 4.3 (API18) o superior, haga lo siguiente (el formato de previsualización de la cámara debe ser NV21):

En primer lugar, no cree los rs, yuvToRgbIntrinsic y las asignaciones en un método o en un bucle en el que se ejecutará el script. Esto ralentizará su aplicación extremadamente y puede causar errores de falta de memoria. Poner estos en el método onCreate () ..:

 rs = RenderScript.create(this); // create rs object only once and use it as long as possible yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); // ditto. 

Con Api18 + las asignaciones se crean mucho más fácil (no necesita los objetos de Type.Builder!). Con su cámaraPreviewWidth y cameraPreviewHeight crear asignación aIn:

 int yuvDatalength = cameraPreviewWidth*cameraPreviewHeight*3/2; // this is 12 bit per pixel aIn = Allocation.createSized(rs, Element.U8(rs), yuvDatalength); 

Necesita un mapa de bits para la salida:

 bmpout = Bitmap.createBitmap(cameraPreviewWidth, cameraPreviewHeight, Bitmap.Config.ARGB_8888); 

Y simplemente crear la asignación aOut de este Bitmap:

 aOut = Allocation.createFromBitmap(rs, bmpout); 

Establezca la asignación de la secuencia de comandos (sólo una vez, fuera del bucle):

 yuvToRgbIntrinsic.setInput(aIn); //Set the input yuv allocation, must be U8(RenderScript). 

En el "bucle de cámara" hacer con datos de byte []:

 aIn.copyFrom(data); // or aIn.copyFromUnchecked(data); // which is faster and safe with camera data yuvToRgbIntrinsic.forEach(aOut); //Launch the appropriate kernels,Convert the image to RGB. aOut.copyTo(bmpout); // copy data from Allocation aOut to Bitmap bmpout 

Por ejemplo, en Nexus 7 (2013, JellyBean 4.3), una conversión de vista previa de cámara Full HD (1920×1080 píxeles) dura unos 7 ms.

  • ¿Por qué el decodificador de MediaCodec no emite un formato YUV unificado (como YUV420P)?
  • OnPreviewFrame data image to imageView
  • YUV_420_888 interpretación en Samsung Galaxy S7 (Camera2)
  • Convertir de YUV a RGB en c + + (android-ndk)
  • Convertir matriz de mapa de bits a YUV (YCbCr NV21)
  • Convertir android.media.Image (YUV_420_888) en mapa de bits
  • La manera más rápida de dibujar un marco de vídeo decodificado con MediaCodec a la pantalla?
  • Camera2 api convertir yuv420 a rgb verde hacia fuera
  • Rotar una matriz de bytes YUV en Android
  • Cómo mostrar la imagen de YUV en Android
  • Problemas al escalar una imagen YUV utilizando la biblioteca libyuv
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.