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

    另外,需要注意的是海康设备回调数据类型为YV12格式;而大华设备回调数据类型为YUV420格式。

二、YUV420转IplImage

采用OpenCV转换的方式,代码如下:
[cpp]   view plain copy 在CODE上查看代码片 派生到我的代码片
  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. }  

采用数学转换的方式,代码如下:
[cpp]   view plain copy 在CODE上查看代码片 派生到我的代码片
  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  = new BYTE[rgbSize];  
  13.     memset(rgbData, 0, rgbSize);  
  14.   
  15.     /* 变量声明 */  
  16.     int temp = 0;  
  17.   
  18.     BYTE* rData = rgbData;                  //r分量地址  
  19.     BYTE* gData = rgbData + baseSize;       //g分量地址  
  20.     BYTE* bData = 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 = pYUV420;                  //y分量地址  
  90.     BYTE* uData = pYUV420 + baseSize;       //u分量地址  
  91.     BYTE* vData = 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

[cpp]   view plain copy 在CODE上查看代码片 派生到我的代码片
  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 = pYV12;  
  28.     unsigned char* vData = &yData[nYLen];  
  29.     unsigned char* uData = &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. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值