Convertir à partir de yuv 420 à image

J’ai tableau d’octets avec les données yuv420.

byte[] yuv420;//yuv data 

Comment puis-je convertir ceci en une Image ?

J’ai trouvé une formule mathématique pour convertir en RVB puis en Image mais c’est très lent. Y a-t-il un moyen de le convertir plus rapidement?

Il y a une classe dans Emgu pour la conversion

 COLOR_CONVERSION(enum CV_YUV2RGB Convert YUV color to RGB) 

mais je ne peux pas comprendre comment utiliser cette classe. Quelqu’un peut-il aider?

 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  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  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  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  255) input = 255; return (byte)Math.Abs(input); } 

Vous avez de la chance car j’ai résolu exactement ce problème auparavant. Il y a quelques liens dans le code pour plus d’informations.

En général, essayez toujours d’utiliser des pointeurs lors du traitement de l’image et évitez d’appeler des fonctions dans des boucles nestedes. Dans mon code, la comparaison de taille est de loin la partie la plus lente, mais malheureusement, elle est nécessaire (essayez de l’éteindre à l’aide du commutateur de pré-processeur).

Je dois dire cependant qu’à la fin je n’ai jamais utilisé cette fonction parce qu’elle était trop lente, j’ai choisi de l’implémenter en c ++ et de l’appeler depuis c # en utilisant p invoke.

 private static unsafe void YUV2RGBManaged(byte[] YUVData, byte[] RGBData, int width, int height) { //returned pixel format is 2yuv - ie 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; } } } } 

et si vous décidez de l’implémenter en c ++

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

Le plus grand contrevenant dans ce code est l’utilisation de Bitmap.SetPixel ; cela est très lent pour chaque itération de boucle interne. Utilisez plutôt un tableau d’octets pour stocker vos valeurs RVB et, une fois rempli, copiez-le dans une image bitmap en une seule étape .

Deuxièmement, comprenez que y, u et v sont des octets et ne peuvent donc avoir que 256 valeurs possibles. Il est donc parfaitement possible de construire des tables de recherche pour r, g et b, de sorte que vous n’aurez à effectuer aucun calcul dans votre boucle interne.

Enfin, si vous voulez vraiment de la performance, vous devrez écrire cela en C ++ en utilisant l’arithmétique de pointeur et la comstackr avec toutes les optimisations en cours. Cette boucle est également un très bon candidat pour un parallèle car chaque itération opère sur des données indépendantes. Il est également possible d’optimiser cela davantage avec les composants insortingnsèques SSE , en convertissant plusieurs pixels par instruction.

Espérons que cela devrait vous aider à démarrer.

Je viens de trouver un vieux code qui pourrait vous aider. Conversion YUV avec OpenCVSharp (disclaimer: j’ai supprimé du code inutile et je ne l’ai pas testé!)

 IplImage yuvImage = new IplImage(w, h, BitDepth.U8, 3); IplImage rgbImage = new IplImage(w, h, BitDepth.U8, 3); Cv.CvtColor(yuvImage, rgbImage, ColorConversion.CrCbToBgr); 

pour répondre à votre autre question – pour convertir byte [] en Bitmap, utilisez cette

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

Un mode plus rapide. Deux multiplications et deux ajoutent moins par pixel:

 private static unsafe void YUV2RGBManaged(byte[] YUVData, byte[] RGBData, int width, int height) { //returned pixel format is 2yuv - ie 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; } } } }