首页 > 代码库 > YUV转为IplImage格式(I420和YV12)(转)

YUV转为IplImage格式(I420和YV12)(转)

一、YUV简介
    一般来说,直接采集到的视频数据是RGB24的格式,RGB24一帧的大小size=width×heigth×3 Byte,RGB32的size=width×heigth×4 Byte,如果是I420(即YUV标准格式4:2:0)的数据量是 size=width×heigth×1.5 Byte。 在采集到RGB24数据后,需要对这个格式的数据进行第一次压缩。即将图像的颜色空间由RGB24转化为IYUV。因为,X264在进行编码的时候需要标准的YUV(4:2:0)。但是这里需要注意的是,虽然YV12也是(4:2:0),但是YV12和I420的却是不同的,在存储空间上面有些区别。如下:
    YV12 : 亮度(行×列) + V(行×列/4) + U(行×列/4)
    I420 : 亮度(行×列) + U(行×列/4) + V(行×列/4)

可以看出,YV12和I420基本上是一样的,就是UV的顺序不同。
    YUV420p 和 YUV420的区别在于存储格式上有区别:
    YUV420p:yyyyyyyy uuuu vvvvv
    YUV420: yuv yuv yuv

     关于YUV 更详细资料可参考:http://zh.wikipedia.org/wiki/YUV。
    另外,需要注意的是海康设备回调数据类型为YV12格式;而大华设备回调数据类型为YUV420格式。

二、YUV420转IplImage

采用OpenCV转换的方式,代码如下:

 1 IplImage* YUV420_To_IplImage_Opencv(unsigned char* pYUV420, int width, int height) 2 { 3     if (!pYUV420) 4     { 5         return NULL; 6     } 7  8     IplImage *yuvimage,*rgbimg,*yimg,*uimg,*vimg,*uuimg,*vvimg; 9 10     int nWidth = width;11     int nHeight = height;12     rgbimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,3);13     yuvimage = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,3);14 15     yimg = cvCreateImageHeader(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1);16     uimg = cvCreateImageHeader(cvSize(nWidth/2, nHeight/2),IPL_DEPTH_8U,1);17     vimg = cvCreateImageHeader(cvSize(nWidth/2, nHeight/2),IPL_DEPTH_8U,1);18 19     uuimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1);20     vvimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1);21 22     cvSetData(yimg,pYUV420, nWidth);23     cvSetData(uimg,pYUV420+nWidth*nHeight, nWidth/2);24     cvSetData(vimg,pYUV420+long(nWidth*nHeight*1.25), nWidth/2);25     cvResize(uimg,uuimg,CV_INTER_LINEAR);26     cvResize(vimg,vvimg,CV_INTER_LINEAR);27 28     cvMerge(yimg,uuimg,vvimg,NULL,yuvimage);29     cvCvtColor(yuvimage,rgbimg,CV_YCrCb2RGB);30 31     cvReleaseImage(&uuimg);32     cvReleaseImage(&vvimg);33     cvReleaseImageHeader(&yimg);34     cvReleaseImageHeader(&uimg);35     cvReleaseImageHeader(&vimg);36 37     cvReleaseImage(&yuvimage);38 39     if (!rgbimg)40     {41         return NULL;42     }43 44     return rgbimg;45 }

采用数学转换的方式,代码如下:

  1 bool YUV420_To_BGR24(unsigned char *puc_y, unsigned char *puc_u, unsigned char *puc_v, unsigned char *puc_rgb, int width_y, int height_y)  2 {  3     if (!puc_y || !puc_u || !puc_v || !puc_rgb)  4     {  5         return false;  6     }  7       8     //初始化变量  9     int baseSize = width_y * height_y; 10     int rgbSize = baseSize * 3; 11  12     BYTE* rgbData  = http://www.mamicode.com/new BYTE[rgbSize]; 13     memset(rgbData, 0, rgbSize); 14  15     /* 变量声明 */ 16     int temp = 0; 17  18     BYTE* rData = http://www.mamicode.com/rgbData;                  //r分量地址 19     BYTE* gData = http://www.mamicode.com/rgbData + baseSize;       //g分量地址 20     BYTE* bData = http://www.mamicode.com/gData   + baseSize;       //b分量地址 21  22     int uvIndex =0, yIndex =0; 23  24     //YUV->RGB 的转换矩阵 25     //double  Yuv2Rgb[3][3] = {1, 0, 1.4022, 26     //    1, -0.3456, -0.7145, 27     //    1, 1.771,   0}; 28  29     for(int y=0; y < height_y; y++) 30     { 31         for(int x=0; x < width_y; x++) 32         { 33             uvIndex        = (y>>1) * (width_y>>1) + (x>>1); 34             yIndex         = y * width_y + x; 35  36             /* r分量 */ 37             temp          = (int)(puc_y[yIndex] + (puc_v[uvIndex] - 128) * 1.4022); 38             rData[yIndex] = temp<0 ? 0 : (temp > 255 ? 255 : temp); 39  40             /* g分量 */ 41             temp          = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * (-0.3456) + 42                 (puc_v[uvIndex] - 128) * (-0.7145)); 43             gData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp); 44  45             /* b分量 */ 46             temp          = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * 1.771); 47             bData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp); 48         } 49     } 50  51     //将R,G,B三个分量赋给img_data 52     int widthStep = width_y*3; 53     for (int y = 0; y < height_y; y++) 54     { 55         for (int x = 0; x < width_y; x++) 56         { 57             puc_rgb[y * widthStep + x * 3 + 2] = rData[y * width_y + x];   //R 58             puc_rgb[y * widthStep + x * 3 + 1] = gData[y * width_y + x];   //G 59             puc_rgb[y * widthStep + x * 3 + 0] = bData[y * width_y + x];   //B 60         } 61     } 62  63     if (!puc_rgb) 64     { 65         return false; 66     } 67  68     delete [] rgbData; 69     return true; 70 } 71  72 IplImage* YUV420_To_IplImage(unsigned char* pYUV420, int width, int height) 73 { 74     if (!pYUV420) 75     { 76         return NULL; 77     } 78  79     //初始化变量 80     int baseSize = width*height; 81     int imgSize = baseSize*3; 82  83 BYTE* pRGB24  = new BYTE[imgSize]; 84 memset(pRGB24,  0, imgSize); 85  86     /* 变量声明 */ 87     int temp = 0; 88  89     BYTE* yData = http://www.mamicode.com/pYUV420;                  //y分量地址 90     BYTE* uData = http://www.mamicode.com/pYUV420 + baseSize;       //u分量地址 91     BYTE* vData = http://www.mamicode.com/uData  + (baseSize>>2);   //v分量地址 92  93     if(YUV420_To_BGR24(yData, uData, vData, pRGB24, width, height) == false || !pRGB24) 94     { 95         return NULL; 96     } 97  98     IplImage *image = cvCreateImage(cvSize(width, height), 8,3); 99     memcpy(image->imageData, pRGB24, imgSize);100 101     if (!image)102     {103         return NULL;104     }105 106     delete [] pRGB24;107     return image;108 }

三、YV12转IplImage

  1 //YV12转为BGR24数据  2 bool YV12_To_BGR24(unsigned char* pYV12, unsigned char* pRGB24,int width, int height)  3 {  4     if(!pYV12 || !pRGB24)  5     {  6         return false;  7     }  8   9     const long nYLen = long(height * width); 10     const int halfWidth = (width>>1); 11  12     if(nYLen<1 || halfWidth<1) 13     { 14         return false; 15     } 16  17     // yv12‘s data structure 18     // |WIDTH | 19     // y......y-------- 20     // y......y   HEIGHT 21     // y......y 22     // y......y-------- 23     // v..v 24     // v..v 25     // u..u 26     // u..u 27     unsigned char* yData =http://www.mamicode.com/ pYV12; 28     unsigned char* vData = http://www.mamicode.com/&yData[nYLen]; 29     unsigned char* uData = http://www.mamicode.com/&vData[nYLen>>2]; 30  31     if(!uData || !vData) 32     { 33         return false; 34     } 35  36     // Convert YV12 to RGB24 37     int rgb[3]; 38     int i, j, m, n, x, y; 39     m = -width; 40     n = -halfWidth; 41     for(y=0; y<height;y++) 42     { 43         m += width; 44             if(!(y % 2)) 45                 n += halfWidth; 46         for(x=0; x<width;x++)    47         { 48             i = m + x; 49                 j = n + (x>>1); 50             rgb[2] = int(yData[i] + 1.370705 * (vData[j] - 128)); // r 51             rgb[1] = int(yData[i] - 0.698001 * (uData[j] - 128)  - 0.703125 * (vData[j] - 128));   // g 52             rgb[0] = int(yData[i] + 1.732446 * (uData[j] - 128)); // b 53  54             //j = nYLen - iWidth - m + x; 55             //i = (j<<1) + j;    //图像是上下颠倒的 56  57             j = m + x; 58             i = (j<<1) + j; 59  60             for(j=0; j<3; j++) 61             { 62                 if(rgb[j]>=0 && rgb[j]<=255) 63                     pRGB24[i + j] = rgb[j]; 64                 else 65                     pRGB24[i + j] = (rgb[j] < 0)? 0 : 255; 66             } 67         } 68     } 69  70     if (pRGB24 == NULL) 71     { 72         return false; 73     } 74  75     return true; 76 } 77  78  79 IplImage* YV12_To_IplImage(unsigned char* pYV12, int width, int height) 80 { 81     if (!pYV12) 82     { 83         return NULL; 84     } 85  86     int sizeRGB = width* height *3; 87     unsigned char* pRGB24 = new unsigned char[sizeRGB]; 88     memset(pRGB24, 0, sizeRGB); 89  90     if(YV12_To_BGR24(pYV12, pRGB24 ,width, height) == false || (!pRGB24)) 91     { 92         return NULL; 93     } 94  95     IplImage* pImage = cvCreateImage(cvSize(width, height), 8, 3); 96     if(!pImage) 97     { 98         return NULL; 99     }100 101     memcpy(pImage->imageData, pRGB24, sizeRGB);102     if (!(pImage->imageData))103     {104         return NULL;105     }106 107     delete [] pRGB24;108     return pImage;109 }

 

YUV转为IplImage格式(I420和YV12)(转)