2015-05-28 19 views
9

Ich schreibe eine App, die die Kamera zieht, wandelt es in rgb, um einige Verarbeitung zu tun.Konvertieren Android camera2 api YUV_420_888 zu RGB

Es funktioniert gut auf der alten Kamera-Implementierung, die NVuv Yuv-Format verwendet. Das Problem, das ich habe, ist mit dem neuen Yuv-Format, YUV_420_888. Das Bild wird in der neuen Camera2 Api nicht mehr korrekt in RGB konvertiert. Statt des NV21 (YUV_420_SP) -Formats wird YUV_420_888 Yuv-Format gesendet.

Kann mir bitte jemand sagen, wie ich YUV_420_888 in RGB konvertieren soll?

Danke

+0

möglich Duplikat [Converting YUV-> RGB (Bildverarbeitung) -> YUV während onPreviewFrame in Android ?] (http://stackoverflow.com/questions/9325861/converting-yuv-rgbimage-processing-yuv-during-onpreviewframe-in-android) – JAL

+0

Das ist für die ältere Kamera-Implementierung, das hilft mir nicht. Trotzdem danke. –

+0

Hat jemand YUV_420_888 zu NV21 konvertiert (YUV_420_SP)? –

Antwort

5

In meinem Ansatz, den ich OpenCV Mat verwenden und Skript von https://gist.github.com/camdenfullmer/dfd83dfb0973663a7974

Zu allererst Sie Ihre YUV_420_888 Bild konvertieren mit dem Code in dem Link Mat über.

* mImage ist mein Image-Objekt, das ich in ImageReader.OnImageAvailableListener bekommen

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

Wir haben 1 Kanal YUV Mat. Definieren Sie neue Matte für BGR (noch nicht RGB) Bild:

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

Ich habe gerade angefangen OpenCV Lernen so propably dies nicht über 4-Kanal-Mat sein und stattdessen könnte sein, 3-Kanal, aber es funktioniert für mich. Jetzt verwende ich konvertieren Farbe Methode, um meine Yuv Mat in bgr Mat.

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

Jetzt können wir wie der Suche nach Konturen, Farben, Kreise etc. alle Bildverarbeitung tun Bild auf dem Bildschirm drucken zurück wir es Bitmap konvertieren müssen:

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

Ich habe alle meine Bildverarbeitung in einem separaten Thread, um meine ImageView zu setzen, muss ich dies im UI-Thread tun.

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

Danke für den Code. Das hat für mich funktioniert. – Brian

0

Etwa 10 mal schneller als die erwähnten "imageToMat" -Funktion oben ist dieser Code:

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

Ich sehe nicht, wie Ihre Antwort richtig sein kann ... imageToMat und Ihre einfachere Funktion, die ich getestet habe, erzeugen zwei verschiedene Byte-Arrays. Es wäre gut, wenn OpenCV dieses neue YUV-Format von Camera2 API verarbeiten könnte.Aber die nächste Umwandlung: Imgproc.cvtColor (mYuvMat, bgrMat, mgproc.COLOR_YUV2BGR_I420); ist entscheidend und für alle meine Tests produziert nur ImageToMat gute Ergebnisse. Wenn YUV2BGR_CAMERA2_API vorhanden wäre, wäre Ihre Antwort besser. Und vielleicht ist es jetzt. Es ist jetzt zwei Monate später;) –