2015-05-28 25 views
9

Sto scrivendo un'app che prende il feed della telecamera, lo converte in rgb, per fare qualche elaborazione.Converti Android camera2 api YUV_420_888 in RGB

Funziona perfettamente con la vecchia implementazione della videocamera che utilizza il formato NV21 Yuv. Il problema che sto avendo è con il nuovo formato Yuv, YUV_420_888. L'immagine non viene più convertita correttamente in RGB nel nuovo Camera2 Api che invia il formato YUV_420_888 yuv invece del formato NV21 (YUV_420_SP).

Qualcuno può dirmi come devo convertire YUV_420_888 in RGB?

Grazie

+0

possibile duplicato del [Conversione YUV-> RGB (elaborazione di immagini) -> YUV durante onPreviewFrame in Android ?] (http://stackoverflow.com/questions/9325861/converting-yuv-rgbimage-processing-yuv-during-onpreviewframe-in-android) – JAL

+0

Questo vale per l'implementazione della fotocamera precedente, che non mi aiuta. Grazie comunque. –

+0

Qualcuno ha convertito YUV_420_888 in NV21 (YUV_420_SP)? –

risposta

5

Nel mio approccio che uso OpenCV Mat e script da https://gist.github.com/camdenfullmer/dfd83dfb0973663a7974

Prima di tutto si converte il YUV_420_888 Immagine a Mat con il codice nel link sopra.

* mImage è mio oggetto Immagine che ottengo in ImageReader.OnImageAvailableListener

Mat mYuvMat = imageToMat(mImage); 

public static Mat imageToMat(Image image) { 
    ByteBuffer buffer; 
    int rowStride; 
    int pixelStride; 
    int width = image.getWidth(); 
    int height = image.getHeight(); 
    int offset = 0; 

    Image.Plane[] planes = image.getPlanes(); 
    byte[] data = new byte[image.getWidth() * image.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888)/8]; 
    byte[] rowData = new byte[planes[0].getRowStride()]; 

    for (int i = 0; i < planes.length; i++) { 
     buffer = planes[i].getBuffer(); 
     rowStride = planes[i].getRowStride(); 
     pixelStride = planes[i].getPixelStride(); 
     int w = (i == 0) ? width : width/2; 
     int h = (i == 0) ? height : height/2; 
     for (int row = 0; row < h; row++) { 
      int bytesPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888)/8; 
      if (pixelStride == bytesPerPixel) { 
       int length = w * bytesPerPixel; 
       buffer.get(data, offset, length); 

       if (h - row != 1) { 
        buffer.position(buffer.position() + rowStride - length); 
       } 
       offset += length; 
      } else { 


       if (h - row == 1) { 
        buffer.get(rowData, 0, width - pixelStride + 1); 
       } else { 
        buffer.get(rowData, 0, rowStride); 
       } 

       for (int col = 0; col < w; col++) { 
        data[offset++] = rowData[col * pixelStride]; 
       } 
      } 
     } 
    } 

    Mat mat = new Mat(height + height/2, width, CvType.CV_8UC1); 
    mat.put(0, 0, data); 

    return mat; 
} 

Abbiamo 1 canale YUV Mat. Definire nuova Mat per BGR (non RGB ancora) immagine:

Mat bgrMat = new Mat(mImage.getHeight(), mImage.getWidth(),CvType.CV_8UC4); 

Ho appena iniziato a studiare in modo OpenCV propably questo non deve essere Mat 4 canali e invece potrebbe essere a 3 canali, ma funziona per me. Ora uso il metodo convert color per cambiare il mio yuv Mat in bgr Mat.

Imgproc.cvtColor(mYuvMat, bgrMat, Imgproc.COLOR_YUV2BGR_I420); 

Ora possiamo fare tutto il trattamento delle immagini come trovare contorni, dei colori, cerchi, ecc Per stampare un'immagine di nuovo sullo schermo abbiamo bisogno di convertirlo in bitmap:

Mat rgbaMatOut = new Mat(); 
Imgproc.cvtColor(bgrMat, rgbaMatOut, Imgproc.COLOR_BGR2RGBA, 0); 
final Bitmap bitmap = Bitmap.createBitmap(bgrMat.cols(), bgrMat.rows(), Bitmap.Config.ARGB_8888); 
Utils.matToBitmap(rgbaMatOut, bitmap); 

ho tutti i miei l'elaborazione delle immagini in thread separati in modo tale da impostare il mio ImageView, ho bisogno di farlo sul thread dell'interfaccia utente.

runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         if(bitmap != null) { 
          mImageView.setImageBitmap(bitmap); 
         } 
        } 
       }); 
+0

Grazie per il codice. Questo ha funzionato per me. – Brian

0

circa 10 volte più veloce rispetto alla -Function citato "imageToMat" di cui sopra è di questo codice:

Image image = reader.acquireLatestImage(); 
... 
Mat yuv = new Mat(image.getHeight() + image.getHeight()/2, image.getWidth(), CvType.CV_8UC1); 
ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 
final byte[] data = new byte[buffer.limit()]; 
buffer.get(data); 
yuv.put(0, 0, data); 
... 
image.close(); 
+0

Non vedo come la tua risposta possa essere corretta ... imageToMat e la tua funzione semplificata che ho testato producono due diversi array di byte. Sarebbe bello se OpenCV fosse in grado di gestire questo nuovo formato YUV da Camera2 api.Ma la prossima conversione: Imgproc.cvtColor (mYuvMat, bgrMat, mgproc.COLOR_YUV2BGR_I420); è fondamentale e per tutti i miei test solo imageToMat produce buoni risultati. Se ci fosse YUV2BGR_CAMERA2_API la tua risposta sarebbe migliore. E forse ora lo è. Sono passati due mesi ora;) –

Problemi correlati