2015-08-28 11 views
9

Hey Ich erstelle kleine Kamera-App Ich habe alle Dinge implementiert, aber ich habe ein Problem, NV21 Byte-Array in JPEG-Format konvertiert
Ich habe viele, aber alle von ihnen sogar gefunden nicht funktioniert oder
zunächst auf einigen Geräten arbeiten ich diese Schnipsel versucht und es auf Xperia z2 5.2 aber 4.4.4Konvertieren NV21 Byte-Array in Bitmap-lesbaren Format

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

auch diese Art und Weise arbeitet auf demselben Gerät und nicht auf die anderen

s4 auf Galaxie arbeiten
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; 
         } 
            } 

zweitens ich viele Lösungen ausprobiert dekodieren NV21 ersten renderscript Code

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; 

} 

und auch dieser Code

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); 
     } 

    } 
} 

und schließlich zu konvertieren Ich habe versucht, das Bild auf SD-Karte zu speichern und dann wieder öffnen aber es scheitert auch

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(); 

und das ist das Ergebnis mit dem letzten 3 Ansatz, den ich enter image description here

+0

Wenn Sie Jpeg erhalten möchten, benennen Sie bitte Ihre Frage, es sieht so aus, als ob Sie NV21 in RGB konvertieren möchten, was eine ganz andere Aufgabe ist. –

+0

Wie haben Sie das Bild angezeigt? Laden Sie die JPEG-Datei in ein ImageView? –

Antwort

13

Es gibt ein paar Möglichkeiten, um einen NV21 Rahmen aus der Kamera zu speichern, ist die einfachste Art und Weise folgen musste es eine YuvImage seiner Umwandlung dann zu einer Einsparung jPEG-Datei:

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(); 

Alternativ können Sie auch wandeln es in Android Bitmap-Objekt und als PNG oder einem anderen Format speichern:

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(); 

Hinweis t Hat die letzte Option einen NV21 -> JPEG -> Bitmap Object -> PNG file Prozess, so bedenken Sie, dass dies keine sehr effiziente Möglichkeit ist, Vorschaubilder von der Kamera zu speichern, wenn Sie eine hohe Leistung benötigen.

UPDATE: Ich habe müde davon, wie lange es dauert, diese Umwandlung zu arbeiten, so schrieb ich eine Bibliothek (easyRS) um render auf einfache Weise diese von Code in einer Zeile zu tun:

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

Es ist etwa fünf Mal schneller als der JPEG-Prozess in einem 2000x2000 Bild auf einem Moto G 2nd.

2

Ihr zweiter Versuch (mit ScriptIntrinsicYuvToRGB) sieht vielversprechend aus. Mit JellyBean 4.3 (API18) oder höher gehen Sie wie folgt (Kameravorschau Format NV21 sein muss):

Zuerst dont die rs schaffen, die yuvToRgbIntrinsic und die Zuweisungen in einem Verfahren oder in einer Schleife, wo die Skript wird ausgeführt. Dies verlangsamt Ihre App extrem und kann zu Fehlern im Arbeitsspeicher führen. Setzen Sie diese in der onCreate() .. Methode:

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. 

Mit Api18 + die Zuordnungen werden erstellt, viel einfacher (Sie brauchen nicht Type.Builder Objekte!).Mit Ihrer cameraPreviewWidth und cameraPreviewHeight Zuordnung aIn erstellen:

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

Sie benötigen ein Bitmap für die Ausgabe:

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

und einfach die août Zuordnung dieser Bitmap erstellen:

aOut = Allocation.createFromBitmap(rs, bmpout); 

das Skripts Set In-allocation (nur einmal, außerhalb der Schleife):

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

In dem "Kamera-Loop" tut mit byte [] Daten:

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 

Zum Beispiel auf Nexus 7 (2013, JellyBean 4.3) einen Full-HD (1920x1080 Pixel) Kamera Vorschau Umwandlung dauert etwa 7 Frau.

Verwandte Themen