假设一个分辨率为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
#include "stdafx.h"
#include
#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++;
}
}
}
}
}