YUV420数据转为IplImage格式

来源:互联网 发布:老僧扫矿软件 病毒 编辑:程序博客网 时间:2024/06/01 19:55

1 YUV420理解

    首先我们需要对YUV420的数据有一个了解,很多人对YUV数据格式不清楚,以至于在做视频的时候出现了一些不可预知的错误(比如说图像带有点、颜色不对等)。图文讲解,
在YUV420中,一个像素点对应一个Y,一个2X2的小方块对应一个U和V。对于所有YUV420图像,它们的Y值排列是完全相同的,因为只有Y的图像就是灰度图像。YUV420sp与YUV420p的数据格式它们的UV排列在原理上是完全不同的。
420p它是先把U存放完后,再存放V,也就是说UV它们分别是连续的。而420sp它是UV、UV这样交替存放的。(见下图)
有了上面的理论,我就可以准确的计算出一个YUV420在内存中存放的大小。
width * hight =Y(总和)
U = Y / 4
V = Y / 4
所以YUV420 数据在内存中的长度是 width * hight * 3 / 2,

假设一个分辨率为8X4的YUV图像,它们的格式如下图:

                                  YUV420sp格式如下图                                                                             YUV420p数据格式如下图

                                    
                                       

2 函数使用

(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来指定。

3 源代码

(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_dataint 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];   //Rpuc_rgb[y * widthStep + x * 3 + 1] = gData[y * width_y + x];   //Gpuc_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++;}}}}}



0 0
原创粉丝点击