一、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 = 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
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 }
时间: 2024-10-09 22:34:34