2015-11-05 12 views
8

ich versuche, Bild von YUV_420_888 zu rgb zu konvertieren, und ich habe einige Probleme mit dem Ausgabebild. In ImageReader erhalte ich ein Bild im Format YUV_420_888 (mit Kamera 2 api für diese Bildvorschau).camera2 api konvertieren yuv420 zu rgb grün

imageReader = ImageReader.newInstance(1920,1080,ImageFormat.YUV_420_888,10); 

In android sdk für YuvImage Klasse schriftlich, dass YuvImage nur NV21, YUY2 verwenden.

wie wir Differenz zwischen N21 und YUV420 nicht groß sehen, und ich versuchen, Daten zu N21 konvertieren

YUV420: enter image description here

und N21: enter image description here

in onImageAvailable ich bekomme separat alle Planes und lege sie an die richtige Stelle (wie auf dem Bild)

ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 

ByteBuffer bufferY = image.getPlanes()[0].getBuffer(); 
byte[] data0 = new byte[bufferY.remaining()]; 
bufferY.get(data0); 

ByteBuffer bufferU = image.getPlanes()[1].getBuffer(); 
byte[] data1 = new byte[bufferU.remaining()]; 
bufferU.get(data1); 

ByteBuffer bufferV = image.getPlanes()[2].getBuffer(); 
byte[] data2 = new byte[bufferV.remaining()]; 
bufferV.get(data2); 
... 
outputStream.write(data0); 
for (int i=0;i<bufferV.remaining();i++) { 
    outputStream.write(data1[i]); 
    outputStream.write(data2[i]); 
} 

nach YuvImage Erstellen, Konvertieren zu Bitmap, anzeigen und speichern

final YuvImage yuvImage = new YuvImage(outputStream.toByteArray(), ImageFormat.NV21, 1920,1080, null); 
ByteArrayOutputStream outBitmap = new ByteArrayOutputStream(); 

yuvImage.compressToJpeg(new Rect(0, 0,1920, 1080), 95, outBitmap); 

byte[] imageBytes = outBitmap.toByteArray(); 

final Bitmap imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); 
mImageView.setImageBitmap(imageBitmap); 
... 
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 95, out); 

aber mein gespeicherte Bild ist grün und rosa: capture image capture image

was habe ich verpasst ??

+2

Minor Punkt: das Diagramm für NV21 tatsächlich falsch ist, und zeigt NV12-Codierung. NV21 ist dasselbe, außer dass U und V vertauscht sind, d. H. VUVUVUVUV anstelle von UVUVUVUVUV. – samgak

Antwort

2

bufferV.get(data2) erhöht die Position des ByteBuffers. Deshalb erzeugt die Schleife for (int i=0;i<bufferV.remaining();i++) 0 Iterationen. Sie können es leicht umschreiben als

for (int i=0; i<data1.length; i++) { 
    outputStream.write(data1[i]); 
    outputStream.write(data2[i]); 
} 
+0

ich ändere das ... aber das selbe. ich überprüft, was innerhalb Array ** data1 **, ** data2 ** und sie fast 0. Array-Länge 518400 und von dieser Länge 517440 ist 0-Wert. kann nur erste 960 verwenden? –

+0

Dies könnte eine fehlerhafte Implementierung von camera2 API auf Ihrem Gerät sein. –

3

Es gibt zwei Hauptprobleme auf der Conversion-Versuch:

  1. Wir können nicht davon ausgehen, dass die U und V-Ebenen getrennt sind, könnten sie verschachtelten Daten enthalten (zB U-PLANE = {U1, V1, U2, V2, ...}). Tatsächlich könnte es sogar ein NV21-Interleaving sein. Der Schlüssel hier ist, die row stride und pixel stride des Flugzeuges zu betrachten und auch zu überprüfen, was wir über die YUV_420_888 format annehmen können.
  2. Die Tatsache, dass Sie kommentiert haben, dass die meisten Daten der U an V-Ebene Nullen sind, zeigt an, dass Sie eine Android bug on the generation of images in YUV_420_888 haben. Dies bedeutet, dass selbst wenn Sie das Umwandlungsrecht erhalten, das Bild immer noch grün aussieht, wenn Sie von dem Fehler betroffen sind, der nur bei Android 5.1.1 und höher behoben wurde. Es lohnt sich also zu prüfen, welche Version Sie verwenden den Code reparieren.
+0

danke für den link mit android fehler, ich überprüfe meine version und ich habe auch 5.0.1. also werde ich versuchen, mein Android zu aktualisieren und sehen, was sich ändert –

3

Ich habe die YUV_420 Logik implementiert in render (genau wie im obigen Diagramm dargestellt), hier vollständigen Code sehen:

Conversion YUV_420 _888 to Bitmap, complete code

Es produziert perfekte bimaps für API 22, aber für API 21 es zeigt die "grüne Idylle". Von diesem kann ich bestätigen, die Ergebnisse, die Sie gefunden haben. Wie bereits oben von Silvaren erwähnt, scheint der Grund ein Android-Fehler in API 21 zu sein. Wenn ich meinen RS-Code betrachte, ist klar, dass wenn die U- und V-Information fehlt (dh Null), die G (reen) ARGB-Komponente sehr groß wird die Umwandlung.

Ich sehe ähnliche grüne Bilder auf meinem Galaxy S5 (immer noch API 21) - hier sogar kopfüber ;-). Ich vermute, dass die meisten Geräte auf API 21 derzeit Camera2 noch nicht für ihre Gerätekamera-Apps verwenden. Es gibt eine kostenlose App namens "Manual Camera Compatibility", die es erlaubt, dies zu testen. Von diesem sehe ich, dass in der Tat die S5/API21 immer noch nicht Camera2 verwendet ... zum Glück nicht ...

2

Ich habe ein Bild von ImageFormat.YUV_420_888 und war erfolgreich in JPEG-Datei speichern, und konnte es richtig auf Windows anzeigen .
Ich teile hier:

private final Image mImage; 
private final File mFile; 
private final int mImageFormat; 


ByteArrayOutputStream outputbytes = new ByteArrayOutputStream(); 

ByteBuffer bufferY = mImage.getPlanes()[0].getBuffer(); 
byte[] data0 = new byte[bufferY.remaining()]; 
bufferY.get(data0); 

ByteBuffer bufferU = mImage.getPlanes()[1].getBuffer(); 
byte[] data1 = new byte[bufferU.remaining()]; 
bufferU.get(data1); 

ByteBuffer bufferV = mImage.getPlanes()[2].getBuffer(); 
byte[] data2 = new byte[bufferV.remaining()]; 
bufferV.get(data2); 

try 
{ 
    outputbytes.write(data0); 
    outputbytes.write(data2); 
    outputbytes.write(data1); 


    final YuvImage yuvImage = new YuvImage(outputbytes.toByteArray(), ImageFormat.NV21, mImage.getWidth(),mImage.getHeight(), null); 
    ByteArrayOutputStream outBitmap = new ByteArrayOutputStream(); 

    yuvImage.compressToJpeg(new Rect(0, 0,mImage.getWidth(), mImage.getHeight()), 95, outBitmap); 


    FileOutputStream outputfile = null; 
    outputfile = new FileOutputStream(mFile); 
    outputfile.write(outBitmap.toByteArray()); 
} 
catch (IOException e) 
{ 
    e.printStackTrace(); 
} 
finally 
{ 
    mImage.close(); 
}