2013-04-19 11 views
5

Ich habe Byte-Array mit yuv420 Daten.Konvertieren von Yuv 420 zu Bild <Bgr,byte>

byte[] yuv420;//yuv data 

Wie kann ich konvertiere dies ein Image<Bgr, byte>?

Ich fand eine mathematische Formel zu RGB und dann zu Image<Bgr, byte> konvertieren, aber es ist sehr langsam. Gibt es eine Möglichkeit, es schneller zu konvertieren?

Es gibt eine Klasse in Emgu für

Umwandlung
COLOR_CONVERSION(enum CV_YUV2RGB Convert YUV color to RGB) 

aber ich kann nicht verstehen, wie diese Klasse verwenden. Kann jemand helfen?

static Bitmap ConvertYUV2RGB(byte[] yuvFrame, byte[] rgbFrame, int width, int height) 
{ 
    int uIndex = width * height; 
    int vIndex = uIndex + ((width * height) >> 2); 
    int gIndex = width * height; 
    int bIndex = gIndex * 2; 

    int temp = 0; 


    //图片为pic1,RGB颜色的二进制数据转换得的int r,g,b; 
    Bitmap bm = new Bitmap(width, height); 

    int r = 0; 
    int g = 0; 
    int b = 0; 


    for (int y = 0; y < height; y++) 
    { 
     for (int x = 0; x < width; x++) 
     { 
      // R分量 
      temp = (int)(yuvFrame[y * width + x] + (yuvFrame[vIndex + (y/2) * (width/2) + x/2] - 128) * YUV2RGB_CONVERT_MATRIX[0, 2]); 
      rgbFrame[y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp)); 
      // G分量 
      temp = (int)(yuvFrame[y * width + x] + (yuvFrame[uIndex + (y/2) * (width/2) + x/2] - 128) * YUV2RGB_CONVERT_MATRIX[1, 1] + (yuvFrame[vIndex + (y/2) * (width/2) + x/2] - 128) * YUV2RGB_CONVERT_MATRIX[1, 2]); 
      rgbFrame[gIndex + y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp)); 
      // B分量 
      temp = (int)(yuvFrame[y * width + x] + (yuvFrame[uIndex + (y/2) * (width/2) + x/2] - 128) * YUV2RGB_CONVERT_MATRIX[2, 1]); 
      rgbFrame[bIndex + y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp)); 
      Color c = Color.FromArgb(rgbFrame[y * width + x], rgbFrame[gIndex + y * width + x], rgbFrame[bIndex + y * width + x]); 
      bm.SetPixel(x, y, c); 
     } 
    } 
    return bm; 

} 

static double[,] YUV2RGB_CONVERT_MATRIX = new double[3, 3] { { 1, 0, 1.4022 }, { 1, -0.3456, -0.7145 }, { 1, 1.771, 0 } }; 
static byte clamp(float input) 
{ 
    if (input < 0) input = 0; 
    if (input > 255) input = 255; 
    return (byte)Math.Abs(input); 
} 

Antwort

7

Sie haben Glück, weil ich genau dieses Problem vorher gelöst habe. Es gibt einige Links im Code für weitere Informationen.

Im Allgemeinen versuchen Sie immer, Zeiger bei der Bildverarbeitung zu verwenden und vermeiden Sie den Aufruf von Funktionen in verschachtelten Schleifen. In meinem Code ist der Größenvergleich bei weitem der langsamste Teil, aber leider wird es benötigt (versuche es mit dem Pre-Prozessor-Schalter abzuschalten).

Ich muss jedoch sagen, dass ich am Ende nie diese Funktion verwendet, weil es einfach zu langsam war, entschied ich mich, es in C++ zu implementieren und es von C# mit p invoke aufrufen.

private static unsafe void YUV2RGBManaged(byte[] YUVData, byte[] RGBData, int width, int height) 
    { 

     //returned pixel format is 2yuv - i.e. luminance, y, is represented for every pixel and the u and v are alternated 
     //like this (where Cb = u , Cr = y) 
     //Y0 Cb Y1 Cr Y2 Cb Y3 

     /*http://msdn.microsoft.com/en-us/library/ms893078.aspx 
     * 
     * C = Y - 16 
     D = U - 128 
     E = V - 128 
     R = clip((298 * C   + 409 * E + 128) >> 8) 
     G = clip((298 * C - 100 * D - 208 * E + 128) >> 8) 
     B = clip((298 * C + 516 * D   + 128) >> 8) 

     * here are a whole bunch more formats for doing this... 
     * http://stackoverflow.com/questions/3943779/converting-to-yuv-ycbcr-colour-space-many-versions 
     */ 


     fixed(byte* pRGBs = RGBData, pYUVs = YUVData) 
     { 
      for (int r = 0; r < height; r++) 
      { 
       byte* pRGB = pRGBs + r * width * 3; 
       byte* pYUV = pYUVs + r * width * 2; 

       //process two pixels at a time 
       for (int c = 0; c < width; c += 2) 
       { 
        int C1 = pYUV[1] - 16; 
        int C2 = pYUV[3] - 16; 
        int D = pYUV[2] - 128; 
        int E = pYUV[0] - 128; 

        int R1 = (298 * C1 + 409 * E + 128) >> 8; 
        int G1 = (298 * C1 - 100 * D - 208 * E + 128) >> 8; 
        int B1 = (298 * C1 + 516 * D + 128) >> 8; 

        int R2 = (298 * C2 + 409 * E + 128) >> 8; 
        int G2 = (298 * C2 - 100 * D - 208 * E + 128) >> 8; 
        int B2 = (298 * C2 + 516 * D + 128) >> 8; 
#if true 
        //check for overflow 
        //unsurprisingly this takes the bulk of the time. 
        pRGB[0] = (byte)(R1 < 0 ? 0 : R1 > 255 ? 255 : R1); 
        pRGB[1] = (byte)(G1 < 0 ? 0 : G1 > 255 ? 255 : G1); 
        pRGB[2] = (byte)(B1 < 0 ? 0 : B1 > 255 ? 255 : B1); 

        pRGB[3] = (byte)(R2 < 0 ? 0 : R2 > 255 ? 255 : R2); 
        pRGB[4] = (byte)(G2 < 0 ? 0 : G2 > 255 ? 255 : G2); 
        pRGB[5] = (byte)(B2 < 0 ? 0 : B2 > 255 ? 255 : B2); 
#else 
        pRGB[0] = (byte)(R1); 
        pRGB[1] = (byte)(G1); 
        pRGB[2] = (byte)(B1); 

        pRGB[3] = (byte)(R2); 
        pRGB[4] = (byte)(G2); 
        pRGB[5] = (byte)(B2); 
#endif 

        pRGB += 6; 
        pYUV += 4; 
       } 
      } 
     } 
    } 

und einhüllen entscheiden Sie, dies in C++ zu implementieren

void YUV2RGB(void *yuvDataIn,void *rgbDataOut, int w, int h, int outNCh) 
{ 

    const int ch2 = 2 * outNCh; 

    unsigned char* pRGBs = (unsigned char*)rgbDataOut; 
    unsigned char* pYUVs = (unsigned char*)yuvDataIn; 

    for (int r = 0; r < h; r++) 
    { 
     unsigned char* pRGB = pRGBs + r * w * outNCh; 
     unsigned char* pYUV = pYUVs + r * w * 2; 

     //process two pixels at a time 
     for (int c = 0; c < w; c += 2) 
     { 
      int C1 = pYUV[1] - 16; 
      int C2 = pYUV[3] - 16; 
      int D = pYUV[2] - 128; 
      int E = pYUV[0] - 128; 

      int R1 = (298 * C1 + 409 * E + 128) >> 8; 
      int G1 = (298 * C1 - 100 * D - 208 * E + 128) >> 8; 
      int B1 = (298 * C1 + 516 * D + 128) >> 8; 

      int R2 = (298 * C2 + 409 * E + 128) >> 8; 
      int G2 = (298 * C2 - 100 * D - 208 * E + 128) >> 8; 
      int B2 = (298 * C2 + 516 * D + 128) >> 8; 

      //unsurprisingly this takes the bulk of the time. 
      pRGB[0] = (unsigned char)(R1 < 0 ? 0 : R1 > 255 ? 255 : R1); 
      pRGB[1] = (unsigned char)(G1 < 0 ? 0 : G1 > 255 ? 255 : G1); 
      pRGB[2] = (unsigned char)(B1 < 0 ? 0 : B1 > 255 ? 255 : B1); 

      pRGB[3] = (unsigned char)(R2 < 0 ? 0 : R2 > 255 ? 255 : R2); 
      pRGB[4] = (unsigned char)(G2 < 0 ? 0 : G2 > 255 ? 255 : G2); 
      pRGB[5] = (unsigned char)(B2 < 0 ? 0 : B2 > 255 ? 255 : B2); 

      pRGB += ch2; 
      pYUV += 4; 
     } 
    } 
} 
+0

Vielen Dank, viele andere Ideen, denn diese Funktion ist nicht schnell. – user1541069

+0

Welche Version hast du versucht? Die C++ Version ist ungefähr dreimal schneller, also benutze das. Wenn Sie so schnell wie möglich brauchen, wird C# nicht für Sie arbeiten. –

+0

Wie konvertiert man byte [] RGBData in Bitmap? – user1541069

0

Der größte Täter in diesem Code ist die Verwendung von Bitmap.SetPixel; es ist sehr langsam, dies bei jeder inneren Schleifeniteration zu tun. Verwenden Sie stattdessen ein Byte-Array, um Ihre RGB-Werte zu speichern, und kopieren Sie es nach dem Füllen in eine Bitmap as a single step.

Zweitens verstehen, dass y, u und v Bytes sind, und so nur 256 mögliche Werte haben können. Es ist daher durchaus möglich, Nachschlagetabellen für r, g und b zu erstellen, sodass Sie keine Berechnungen in Ihrer inneren Schleife durchführen müssen.

Schließlich, wenn Sie wirklich Leistung wollen, müssen Sie dies in C++ schreiben mit Zeigerarithmetik und kompilieren Sie mit allen Optimierungen auf. Diese Schleife ist auch ein sehr guter Kandidat für eine parallel for, da jede Iteration mit unabhängigen Daten arbeitet. Es ist auch möglich, dies weiter zu optimieren mit SSE intrinsics, wobei mehrere Pixel pro Befehl konvertiert werden.

Hoffentlich sollte dies Ihnen den Anfang machen.

+0

Dank, aber ich kann nicht glauben, dass es keine DLL ist YUV420 zu konvertieren mit dll rgb Und was konvertiert mit emgu Klasse COLOR_CONVERSION ??? – user1541069

+0

gibt es wahrscheinlich DLLs, was das tun. Es ist ein häufiges Problem. Ich kann mich jetzt nicht erinnern, warum ich meine eigene geschrieben habe, aber vermutlich, weil ich entweder keine Implementierung finden konnte oder weil ich nicht die Komplikation der Verknüpfung in opencv nur für eine Funktion wollte. –

+0

Ich benutze Emgu in meinem Projekt.Und das Beste von allem ist, um Bild formatieren.Ich habe 16 Kameras mit 25 fps (704x576) Callback-Funktion Rückkehr yuv420 Rahmen, Umwandlung in rgb muss so schnell wie möglich sein. – user1541069

0

Ich habe gerade ein altes Stück Code, der Ihnen helfen könnte. YUV-Konvertierung mit OpenCVSharp (Disclaimer: Ich habe einige unnötige Code entfernt und dies nicht getestet!)

IplImage yuvImage = new IplImage(w, h, BitDepth.U8, 3); 
IplImage rgbImage = new IplImage(w, h, BitDepth.U8, 3); 

Cv.CvtColor(yuvImage, rgbImage, ColorConversion.CrCbToBgr); 

Ihre andere Frage zu beantworten - zu konvertieren byte [] in eine Bitmap verwenden diese

int w= 100; 
int h = 200; 
int ch = 3; 

byte[] imageData = new byte[w*h*ch]; //you image data here 
Bitmap bitmap  = new Bitmap(w,h,PixelFormat.Format24bppRgb); 
BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); 
IntPtr pNative  = bmData.Scan0; 
Marshal.Copy(imageData,0,pNative,w*h*ch); 
bitmap.UnlockBits(bmData); 
+0

Thnks, für Ihre Antworten) – user1541069

+0

Wenn ich meine alte Methode ConvertYUV2RGB Konvertierung ist gut durch sehr langsam !!! ! Und wenn ich die Methode YUV2RGBVerwaltet benutze und zu bmp wie in deiner post-bmp-Datei verdeckt bin, ist das grün !!! – user1541069

+0

Ich kann mit GCHandle Handle konvertieren = GCHandle.Alloc (fmain.ALLImage [Kanalnummer], GCHandleType.Pinned); Verwendung (Foto yuv420sp = new Bild (704, (576 >> 1) * 3, 704, handle.AddrOfPinnedObject())) { Bild image = Bild neues (704.576); CvInvoke.cvCvtColor (yuv420sp, Bild, Emgu.CV.CvEnum.COLOR_CONVERSION.CV_YUV420sp2BGR); // Bild enthält jetzt das gleiche yuv-Bild im bgr-Farbraum } handle.Free(); Aber bmpfile ist schwarz und während, nicht in Farbe. Wie zu lösen – user1541069

0

Ein schneller Modus.Zwei mutiplication und zwei addieren weniger pro Pixel:

private static unsafe void YUV2RGBManaged(byte[] YUVData, byte[] RGBData, int width, int height) 
{ 
    //returned pixel format is 2yuv - i.e. luminance, y, is represented for every pixel and the u and v are alternated 
    //like this (where Cb = u , Cr = y) 
    //Y0 Cb Y1 Cr Y2 Cb Y3 

    /*http://msdn.microsoft.com/en-us/library/ms893078.aspx 
    * 
    C = 298 * (Y - 16) + 128 
    D = U - 128 
    E = V - 128 
    R = clip((C   + 409 * E) >> 8) 
    G = clip((C - 100 * D - 208 * E) >> 8) 
    B = clip((C + 516 * D   ) >> 8) 

    * here are a whole bunch more formats for doing this... 
    * http://stackoverflow.com/questions/3943779/converting-to-yuv-ycbcr-colour-space-many-versions 
    */ 


    fixed(byte* pRGBs = RGBData, pYUVs = YUVData) 
    { 
     for (int r = 0; r < height; r++) 
     { 
      byte* pRGB = pRGBs + r * width * 3; 
      byte* pYUV = pYUVs + r * width * 2; 

      //process two pixels at a time 
      for (int c = 0; c < width; c += 2) 
      { 
       int C1 = 298 * (pYUV[1] - 16) + 128; 
       int C2 = 298 * (pYUV[3] - 16) + 128; 
       int D = pYUV[2] - 128; 
       int E = pYUV[0] - 128; 

       int R1 = (C1 + 409 * E) >> 8; 
       int G1 = (C1 - 100 * D - 208 * E) >> 8; 
       int B1 = (C1 + 516 * D) >> 8; 

       int R2 = (C2 + 409 * E) >> 8; 
       int G2 = (C2 - 100 * D - 208 * E) >> 8; 
       int B2 = (298 * C2 + 516 * D) >> 8; 

       //check for overflow 
       //unsurprisingly this takes the bulk of the time. 
       pRGB[0] = (byte)(R1 < 0 ? 0 : R1 > 255 ? 255 : R1); 
       pRGB[1] = (byte)(G1 < 0 ? 0 : G1 > 255 ? 255 : G1); 
       pRGB[2] = (byte)(B1 < 0 ? 0 : B1 > 255 ? 255 : B1); 

       pRGB[3] = (byte)(R2 < 0 ? 0 : R2 > 255 ? 255 : R2); 
       pRGB[4] = (byte)(G2 < 0 ? 0 : G2 > 255 ? 255 : G2); 
       pRGB[5] = (byte)(B2 < 0 ? 0 : B2 > 255 ? 255 : B2); 

       pRGB += 6; 
       pYUV += 4; 
      } 
     } 
    } 
} 
Verwandte Themen