2015-11-05 11 views
8

provo a convertire l'immagine da YUV_420_888 a rgb e ho qualche problema con l'immagine di output. In ImageReader ottengo l'immagine nel formato YUV_420_888 (utilizzando la fotocamera 2 api per ottenere questa anteprima dell'immagine).camera2 api converti yuv420 in rgb green out

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

In Android SDK per la scrittura di classe YuvImage, che YuvImage utilizzando solo NV21, YUY2.

come possiamo vedere differenza tra N21 e YUV420 non è grande e cerco convertire i dati in N21

YUV420: enter image description here

e N21: enter image description here

in onImageAvailable prendo separatamente ciascun Piano e li metto nella posizione corretta (come nell'immagine)

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

dopo creare YuvImage, convertire in bitmap, visualizzare e salvare

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

ma la mia immagine salvata è verde e rosa: capture image capture image

Cosa mi sono perso ??

+2

Punto minore: lo schema per la NV21 è in realtà sbagliata e raffigura la codifica NV12. NV21 è lo stesso, tranne che U e V sono scambiati, cioè VUVUVUVUV invece di UVUVUVUVUV. – samgak

risposta

2

bufferV.get(data2) aumenta la posizione di ByteBuffer. Ecco perché il ciclo for (int i=0;i<bufferV.remaining();i++) produce 0 iterazioni. Si può facilmente riscrivere come

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

lo cambio ... ma lo stesso. ho controllato, quale array interno ** data1 **, ** data2 ** e quasi 0. Lunghezza della matrice 518400 e da questa lunghezza 517440 è il valore 0. può essere possibile utilizzare solo il primo 960? –

+0

Questa potrebbe essere un'implementazione difettosa dell'API camera2 sul tuo dispositivo. –

3

Ci sono due problemi principali sul tentativo di conversione:

  1. Non possiamo assumere che i piani U e V sono isolati, potrebbero contenere dati interlacciati (ad es U-PLANE = {U1, V1, U2, V2, ...}). In effetti, potrebbe già essere un interleaving in stile NV21. La chiave qui sta esaminando il piano di row stride e pixel stride e anche controllare quello che possiamo assumere la YUV_420_888 format.
  2. Il fatto che tu abbia commentato che la maggior parte dei dati sugli aerei U e V sono zeri indica che stai vivendo un Android bug on the generation of images in YUV_420_888. Ciò significa che anche se ottieni la conversione corretta, l'immagine risulterebbe ancora verde se sei affetto dal bug, che è stato corretto solo su Android 5.1.1 e versioni successive, quindi vale la pena controllare quale versione stai utilizzando fissando il codice.
+0

grazie per il collegamento con bug android, controllo la mia versione e anch'io ho 5.0.1. quindi cercherò di aggiornare il mio androide e vedrò cosa cambierà –

3

Ho implementato la logica YUV_420 (esattamente come mostrato nella figura precedente) in RenderScript, vedi piena codice qui:

Conversion YUV_420 _888 to Bitmap, complete code

Produce bimaps ideale per API 22, ma per API 21 mostra "l'idillio verde". Da questo posso confermare, i risultati che hai trovato. Come già accennato da Silvaren sopra, il motivo sembra essere un bug di Android nell'API 21. Guardando il mio codice rs è chiaro, che se mancano informazioni U e V (cioè zero) la componente G (reen) ARGB diventa enorme durante la conversione.

Vedo immagini verdi simili sul mio Galaxy S5 (ancora API 21) - anche qui capovolto ;-). Ho il sospetto che la maggior parte dei dispositivi dell'API 21 attualmente non utilizzi ancora Camera2 per le proprie app con fotocamera per dispositivo. C'è una app gratuita chiamata "Manual Camera Compatibility" che permette di testare questo. Da questo vedo che in effetti S5/API21 non usa ancora Camera2 ... fortunatamente no ...

2

Ho ottenuto un'immagine di ImageFormat.YUV_420_888 e sono riuscito a salvare in file jpeg, e ho potuto visualizzarlo correttamente su Windows .
sto condividendo qui:

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(); 
} 
Problemi correlati