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++;}}}}}
- YUV420数据转为IplImage格式
- YUV420数据转为IplImage格式
- 通用图像转为IplImage格式
- 通用图像转为IplImage格式
- YUV转为IplImage格式(I420和YV12)
- YUV转为IplImage格式(I420和YV12)
- 将yuyv格式图像转为IplImage(彩色)
- YUV420格式
- YUV420格式
- yuv420格式
- yuv420转为cv::Mat
- Mat 转为 IplImage
- IplImage转为BufferedImage
- YUV420格式解析(转载)
- YUV420格式解析
- YUV420格式解析
- YUV420 存储格式
- YUV420格式解析
- python中的list、dict、string基本操作
- java中四种引用类型
- 错误处理error C4996: 'fopen': This function or variable may be unsafe
- Spring分布式事务实现
- 国际化—— i18n:internationalization
- YUV420数据转为IplImage格式
- Java多线程编程(一)
- BZOJ2705: [SDOI2012]Longge的问题
- Hashmap实现原理
- 接口和抽象类
- 面向对象编程的关键点(用php实现面向对象的、变化跟不变化进行伪代码逻辑进阶编程)
- iOS 一些关键描述字
- c++快速简易入门教程_007虚函数与多态性、纯虚函数
- 注册表操作(VC_Win32)