一、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
- IplImage* YUV420_To_IplImage_Opencv(unsigned char* pYUV420, int width, int height)
- {
- if (!pYUV420)
- {
- return NULL;
- }
- IplImage *yuvimage,*rgbimg,*yimg,*uimg,*vimg,*uuimg,*vvimg;
- int nWidth = width;
- int nHeight = height;
- rgbimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,3);
- yuvimage = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,3);
- yimg = cvCreateImageHeader(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1);
- uimg = cvCreateImageHeader(cvSize(nWidth/2, nHeight/2),IPL_DEPTH_8U,1);
- vimg = cvCreateImageHeader(cvSize(nWidth/2, nHeight/2),IPL_DEPTH_8U,1);
- uuimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1);
- vvimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1);
- cvSetData(yimg,pYUV420, nWidth);
- cvSetData(uimg,pYUV420+nWidth*nHeight, nWidth/2);
- cvSetData(vimg,pYUV420+long(nWidth*nHeight*1.25), nWidth/2);
- cvResize(uimg,uuimg,CV_INTER_LINEAR);
- cvResize(vimg,vvimg,CV_INTER_LINEAR);
- cvMerge(yimg,uuimg,vvimg,NULL,yuvimage);
- cvCvtColor(yuvimage,rgbimg,CV_YCrCb2RGB);
- cvReleaseImage(&uuimg);
- cvReleaseImage(&vvimg);
- cvReleaseImageHeader(&yimg);
- cvReleaseImageHeader(&uimg);
- cvReleaseImageHeader(&vimg);
- cvReleaseImage(&yuvimage);
- if (!rgbimg)
- {
- return NULL;
- }
- return rgbimg;
- }
采用数学转换的方式,代码如下:
- 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)
- {
- if (!puc_y || !puc_u || !puc_v || !puc_rgb)
- {
- return false;
- }
- //初始化变量
- int baseSize = width_y * height_y;
- int rgbSize = baseSize * 3;
- BYTE* rgbData = new BYTE[rgbSize];
- memset(rgbData, 0, rgbSize);
- /* 变量声明 */
- int temp = 0;
- BYTE* rData = rgbData; //r分量地址
- BYTE* gData = rgbData + baseSize; //g分量地址
- BYTE* bData = gData + baseSize; //b分量地址
- int uvIndex =0, yIndex =0;
- //YUV->RGB 的转换矩阵
- //double Yuv2Rgb[3][3] = {1, 0, 1.4022,
- // 1, -0.3456, -0.7145,
- // 1, 1.771, 0};
- for(int y=0; y < height_y; y++)
- {
- for(int x=0; x < width_y; x++)
- {
- uvIndex = (y>>1) * (width_y>>1) + (x>>1);
- yIndex = y * width_y + x;
- /* r分量 */
- temp = (int)(puc_y[yIndex] + (puc_v[uvIndex] - 128) * 1.4022);
- rData[yIndex] = temp<0 ? 0 : (temp > 255 ? 255 : temp);
- /* g分量 */
- temp = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * (-0.3456) +
- (puc_v[uvIndex] - 128) * (-0.7145));
- gData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp);
- /* b分量 */
- temp = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * 1.771);
- bData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp);
- }
- }
- //将R,G,B三个分量赋给img_data
- int widthStep = width_y*3;
- for (int y = 0; y < height_y; y++)
- {
- for (int x = 0; x < width_y; x++)
- {
- puc_rgb[y * widthStep + x * 3 + 2] = rData[y * width_y + x]; //R
- puc_rgb[y * widthStep + x * 3 + 1] = gData[y * width_y + x]; //G
- puc_rgb[y * widthStep + x * 3 + 0] = bData[y * width_y + x]; //B
- }
- }
- if (!puc_rgb)
- {
- return false;
- }
- delete [] rgbData;
- return true;
- }
- IplImage* YUV420_To_IplImage(unsigned char* pYUV420, int width, int height)
- {
- if (!pYUV420)
- {
- return NULL;
- }
- //初始化变量
- int baseSize = width*height;
- int imgSize = baseSize*3;
- BYTE* pRGB24 = new BYTE[imgSize];
- memset(pRGB24, 0, imgSize);
- /* 变量声明 */
- int temp = 0;
- BYTE* yData = pYUV420; //y分量地址
- BYTE* uData = pYUV420 + baseSize; //u分量地址
- BYTE* vData = uData + (baseSize>>2); //v分量地址
- if(YUV420_To_BGR24(yData, uData, vData, pRGB24, width, height) == false || !pRGB24)
- {
- return NULL;
- }
- IplImage *image = cvCreateImage(cvSize(width, height), 8,3);
- memcpy(image->imageData, pRGB24, imgSize);
- if (!image)
- {
- return NULL;
- }
- delete [] pRGB24;
- return image;
- }
三、YV12转IplImage
- //YV12转为BGR24数据
- bool YV12_To_BGR24(unsigned char* pYV12, unsigned char* pRGB24,int width, int height)
- {
- if(!pYV12 || !pRGB24)
- {
- return false;
- }
- const long nYLen = long(height * width);
- const int halfWidth = (width>>1);
- if(nYLen<1 || halfWidth<1)
- {
- return false;
- }
- // yv12's data structure
- // |WIDTH |
- // y......y--------
- // y......y HEIGHT
- // y......y
- // y......y--------
- // v..v
- // v..v
- // u..u
- // u..u
- unsigned char* yData = pYV12;
- unsigned char* vData = &yData[nYLen];
- unsigned char* uData = &vData[nYLen>>2];
- if(!uData || !vData)
- {
- return false;
- }
- // Convert YV12 to RGB24
- int rgb[3];
- int i, j, m, n, x, y;
- m = -width;
- n = -halfWidth;
- for(y=0; y<height;y++)
- {
- m += width;
- if(!(y % 2))
- n += halfWidth;
- for(x=0; x<width;x++)
- {
- i = m + x;
- j = n + (x>>1);
- rgb[2] = int(yData[i] + 1.370705 * (vData[j] - 128)); // r
- rgb[1] = int(yData[i] - 0.698001 * (uData[j] - 128) - 0.703125 * (vData[j] - 128)); // g
- rgb[0] = int(yData[i] + 1.732446 * (uData[j] - 128)); // b
- //j = nYLen - iWidth - m + x;
- //i = (j<<1) + j; //图像是上下颠倒的
- j = m + x;
- i = (j<<1) + j;
- for(j=0; j<3; j++)
- {
- if(rgb[j]>=0 && rgb[j]<=255)
- pRGB24[i + j] = rgb[j];
- else
- pRGB24[i + j] = (rgb[j] < 0)? 0 : 255;
- }
- }
- }
- if (pRGB24 == NULL)
- {
- return false;
- }
- return true;
- }
- IplImage* YV12_To_IplImage(unsigned char* pYV12, int width, int height)
- {
- if (!pYV12)
- {
- return NULL;
- }
- int sizeRGB = width* height *3;
- unsigned char* pRGB24 = new unsigned char[sizeRGB];
- memset(pRGB24, 0, sizeRGB);
- if(YV12_To_BGR24(pYV12, pRGB24 ,width, height) == false || (!pRGB24))
- {
- return NULL;
- }
- IplImage* pImage = cvCreateImage(cvSize(width, height), 8, 3);
- if(!pImage)
- {
- return NULL;
- }
- memcpy(pImage->imageData, pRGB24, sizeRGB);
- if (!(pImage->imageData))
- {
- return NULL;
- }
- delete [] pRGB24;
- return pImage;
- }