Convert from yuv 420 to image

后端 未结 4 1975
我在风中等你
我在风中等你 2021-01-03 03:33

I have byte array with yuv420 data.

byte[] yuv420;//yuv data

How can I convert this to an Image?

I fo

4条回答
  •  情书的邮戳
    2021-01-03 03:40

    You are in luck because i solved exactly this issue before. There are some links in the code for more info.

    In general always try to use pointers when doing image processing and avoid calling functions in nested loops. In my code the size comparison is by far the slowest part but unfortunately it is needed (try switching it off using the pre-processor switch).

    I have to say though that in the end i never used this function because it was just too slow, i opted to implement it in c++ and call it from c# using p invoke.

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

    and incase you decide to implement this in 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;
            }
        }
    }
    

提交回复
热议问题