您的位置:首页 > 其它

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

2014-09-22 17:09 537 查看
一、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转换的方式,代码如下:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: