假设一个分辨率为8X4的YUV图像,它们的格式如下图:
YUV420sp格式如下图 YUV420p数据格式如下图
(1)cvSetData()
函数原型:CVAPI(void) cvSetData( CvArr* arr, void* data, int step );
arr 数组头
data 用户数据data
step 一行所占的字节数
该函数将用户数据data指派给数组头arr,step为一行所占的字节数。
(2)cvResize()
函数原型:CVAPI(void) cvResize( const CvArr* src, CvArr* dst,int interpolation CV_DEFAULT( CV_INTER_LINEAR ));
src 源图像
dst 目标图像
interpolation 修改、插补的方法,取值如下:
·CV_INTER_NN - 最近-邻居插补
·CV_INTER_LINEAR - 双线性插值(默认方法)
·CV_INTER_AREA - 像素面积相关重采样。当缩小图像时,该方法可以避免波纹的出现。当放大图像时,类似于方法CV_INTER_NN。
·CV_INTER_CUBIC - 双三次插值。
函数cvResize 重新调整图像src(或它的ROI),使它精确匹配目标dst(或其ROI)。这里需要说明的是,cvResize可以用来调整3通道图像(如RGB图像)和单通道图像的大小。
(3)cvMerge()
函数原型:CVAPI(void) cvMerge( const CvArr* src0, const CvArr* src1,const CvArr* src2, const CvArr* src3,CvArr* dst );
cvMerge()是cvSplit()的逆运算。数组src0,src1,src2和src3将被合并到数组dst中。当然,dst应该与源数组具有相同的数据类型和尺寸,但它可以有
两个,三个,四个通道,未使用的源图像参数可设置为NULL。
(4)cvCvtColor()
CVAPI(void) cvCvtColor( const CvArr* src, CvArr* dst, int code );
src 原始图像
dst 目标图像
code 色彩空间转换的模式
当数据类型一致时,它将图像从一个颜色空间(通道的数值)转换到另一个[Wharton71].具体转换类型由参数code来指定。
(1)
// YUV420数据转为IplImage格式.cpp : 定义控制台应用程序的入口点。 // #define CRT_SECURE_NO_WARNINGS #include <windows.h> #include "stdafx.h" #include <iostream> #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/imgproc/types_c.h" #include "CvvImage.h" using namespace std; using namespace cv; IplImage* YUV420_To_IplImage_Opencv(unsigned char* pYUV420, int width, int height){ if (!pYUV420) { return NULL; } IplImage *yuvImg, *rgbImg, *yImg, *uImg, *vImg, *uuImg, *vvImg; int nWidth = width; int nHeight = height; rgbImg = cvCreateImage(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 3); yuvImg = cvCreateImage(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 3); //只有Y的图像就是灰度图像 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, yuvImg); cvCvtColor(yuvImg, rgbImg, CV_YCrCb2RGB); cvReleaseImage(&uuImg); cvReleaseImage(&vvImg); cvReleaseImageHeader(&yImg); cvReleaseImageHeader(&uImg); cvReleaseImageHeader(&vImg); cvReleaseImage(&yuvImg); if (!rgbImg) { return NULL; } return rgbImg; } int _tmain(int argc, _TCHAR* argv[]) { BYTE * yuvBuf = new BYTE[(640 * 360 * 3) / 2]; FILE* f = fopen("sintel_640_360.yuv", "r+b"); if (!f) { return -1; } fread(yuvBuf, 1, (640 * 360 * 3) / 2, f); fclose(f); IplImage* pImg = YUV420_To_IplImage_Opencv(yuvBuf, 640, 360); cvNamedWindow("test"); cvShowImage("test", pImg); printf("hello...\n"); system("pause"); return 0; }
(2)采用数学转换的方式,代码如下:
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 yIndex = 0, uvIndex = 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; } //yuv转rgb的函数 void YUV420_To_RGB(char* pYUV, unsigned char* pRGB, int width, int height) { char* pY = pYUV; char* pU = pYUV + height*width; char* pV = pU + (height*width / 4); unsigned char* pBGR = NULL; unsigned char R = 0; unsigned char G = 0; unsigned char B = 0; char Y = 0; char U = 0; char V = 0; double tmp = 0; for (int i = 0; i < height; ++i) { for (int j = 0; j < width; ++j) { pBGR = pRGB + i*width * 3 + j * 3; Y = *(pY + i*width + j); U = *pU; V = *pV; //B tmp = MB(Y, U, V); //B = (tmp > 255) ? 255 : (char)tmp; //B = (B<0) ? 0 : B; B = (unsigned char)tmp; //G tmp = MG(Y, U, V); //G = (tmp > 255) ? 255 : (char)tmp; // G = (G<0) ? 0 : G; G = (unsigned char)tmp; //R tmp = MR(Y, U, V); //R = (tmp > 255) ? 255 : (char)tmp; //R = (R<0) ? 0 : R; R = (unsigned char)tmp; *pBGR = R; *(pBGR + 1) = G; *(pBGR + 2) = B; if (i % 2 == 0 && j % 2 == 0) { *pU++; //*pV++; } else { if (j % 2 == 0) { *pV++; } } } } }