yuv444 yuv420_硬盘转速和缓存哪个重要

yuv444 yuv420_硬盘转速和缓存哪个重要YUV420与YUV444互转,YUV420与YUV444读取和保存,YUV的显示和播放功能【尊重原创,转载请注明出处】:https://blog.csdn.net/guyuealian/article/details/82454945  OpenCV提供了RGB与YUV420/YUV444互转的接口:cvtColor(),但根尴尬OpenCV就是没有提供YUV444与YUV420互转…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

YUV420与YUV444互转,YUV420与YUV444读取和保存,YUV的显示和播放功能


尊重原创,转载请注明出处】:https://blog.csdn.net/guyuealian/article/details/82454945

    OpenCV提供了RGB与YUV420/YUV444互转的接口:cvtColor(),但根尴尬OpenCV就是没有提供YUV444与YUV420互转的接口,如果你想用OpenCV转换,那就只能使用间接的方法了,将YUV420转为BGR(CV_YUV2BGR_I420),然后再将BGR转为YUV444(CV_BGR2YUV),这很蛋疼!效率太低了。

    实质上,只要我们理解了YUV420与YUV444的数据格式,完全可以自己转换的,下面使用C++实现YUV420与YUV444读取和保存,以及UV420与YUV444互转,并实现YUV的显示和播放功能。

    YUV444和YUV420的测试文件,可以这里下载https://download.csdn.net/download/guyuealian/10697442


目录

C++读写YUV444和YUV420,现实YUV444与YUV420互转,支持OpenCV显示

一、YUV数据格式

1、YUV分三种采样方式:

2、YUV的存储格式:

二、YUV文件的读取和保存

1、读取YUV文件

2、保存YUV文件

三、C++实现YUV420与YUV444互转

1、YUV420转YUV444

2、YUV444转YUV420

四、显示和播放YUV文件

1、显示YUV图像

2、播放YUV数据 

五、完整的代码

参考资料:


一、YUV数据格式

     YUV有三个分量:Y(Luminance/Luma:亮度)、U和V表示色差,体现的是图片的色彩信息。相对于RGB彩色空间,将亮度信息和色彩信息分离。这种编码模式也更加适应于人眼,据研究表明,人眼对亮度信息比色彩信息更加敏感。而YUV下采样就是根据人眼的特点,将人眼相对不敏感的色彩信息进行压缩采样,得到相对小的文件进行播放和传输。与YUV相像YCbCr其实与其有少许不同,体现在参数的大小上,本质上都是将亮度信息与色彩信息相分开。


1、YUV分三种采样方式:

yuv444 yuv420_硬盘转速和缓存哪个重要

    YUV444:对于每一个像素都对应一个Y分量、一个U分量、一个V分量。

    YUV422:对于一个像素都对应一个Y分量,但是每两个像素(或者说Y分量)对应一个U分量和一个V分量。

    YUV420:对于一个像素都对应一个Y分量,但是每四个像素(或者说Y分量)对应一个U分量和一个V分量。

2、YUV的存储格式:

    YUYUV在存储时是以数组的形式存储的,可以看做连续的三个一维数组。三个数组分别单独存储Y、U、V分量。以一幅100×100的YUV444图像为例,下图表示的YUV444的存储格式YUV420的存储格式

yuv444 yuv420_硬盘转速和缓存哪个重要   

  从总数据量来看,YUV444需要存储100×100×3个值,YUV422需要存储100×100×2个值,YUV420需要存储100×100×3/2个值。


二、YUV文件的读取和保存

1、读取YUV文件

    YUV文件实质上是保存了图像的YUV格式的原始数据,并没有像png、jpg等图像格式对图像的数据进行压缩。这也就是为什么,YUV格式的文件普遍大比较大了。既然 YUV文件是未经压缩的原始数据,那读取和保存YUV文件就十分简单了。基本方法是只需要调用C++的fopen()函数打开YUV文件获得指向该流的文件指针,然后使用fread()从文件流中直接读取YUV的数据即可。

    下面是实现读取YUV444和YUV420的完整代码:

	/*********************************************************	
	@brief         : 读取yuv图像文件,若输入的是多帧的图像文件,如yuv视频文件,则返回最后一帧的数据
	@param fileYUV : YUV文件
	@param w       : 宽width
	@param h       : 高height
	@param colorType: 颜色空间类型:CS_YUV444,CS_YUV420
	@return        : unsigned char* 返回YUV数据
	********************************************************/	
    unsigned char* read_yuvImage(string fileYUV, int w, int h, ColorSpace colorType) {
		FILE * pFileIn;      //输入CS_YUV444文件
		if (NULL == (pFileIn = fopen(fileYUV.c_str(), "rb"))) {
			printf("File input is can't open!\n");
			fclose(pFileIn);
			return nullptr;
		}
		int bufLen = 0;
		if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
			bufLen = w * h * 3;
		}
		else if (colorType == CS_YUV420) {//定义保存YUV420的数组
			bufLen = w*h * 3 / 2;
		}
		unsigned char* yuvBuf = new unsigned char[bufLen];
		//fread(yuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn);//返回第一帧
		while (fread(yuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn))//返回最后一帧
		{
		}
		fclose(pFileIn);
		return yuvBuf;
	}

Jetbrains全家桶1年46,售后保障稳定

    注意这里定义一个枚举类型ColorSpace

	enum ColorSpace {
		CS_YUV444,
		CS_YUV420
	};

说明:

    上面read_yuvImage函数若输入的是多帧的图像文件,如yuv视频文件,则返回最后一帧的YUV数据,当然了,你稍微改改就可以实现读取每一帧YUV数据了。下面章节会增加显示YUV数据部分,会借助OpenCV实现播放YUV的视频文件。


2、保存YUV文件

    保存YUV文件也十分简单,调用C++的fopen()函数打开YUV文件获得指向该流的文件指针,然后使用fwrite()把YUV的数据流保存到打开的文件即可。

    下面是实现保存YUV444和YUV420数据的完整代码:

	/*********************************************************
	@brief         : 保存YUV数据流
	@param fileYUV : 输出YUV文件的路径
	@param inbuf   : 需要保存的YUV数据流
	@param w       : 宽width
	@param h       : 高height
	@param colorType: 颜色空间类型:CS_YUV444,CS_YUV420
	@return        : void
	********************************************************/
	void write_yuvImage(string fileYUV, unsigned char* inframe, int w, int h, ColorSpace colorType) {
		FILE * pFileOut;     //输出YUV文件
		if (NULL == (pFileOut = fopen(fileYUV.c_str(), "wb"))) {
			printf("File output is can't open!\n");
			fclose(pFileOut);
			return;
		}
		int bufLen = 0;
		if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
			bufLen = w * h * 3;
		}
		else if (colorType == CS_YUV420) {//定义保存YUV420的数组
			bufLen = w*h * 3 / 2;
		}
		fwrite(inframe, bufLen * sizeof(unsigned char), 1, pFileOut);
		fclose(pFileOut);
	}

三、C++实现YUV420与YUV444互转

    OpenCV提供了RGB与YUV420/YUV444互转的接口:cvtColor(),但根尴尬OpenCV就是没有提供YUV444与YUV420互转的接口,如果你想用OpenCV转换,那就只能间接的方法了,将YUV420转为BGR(CV_YUV2BGR_I420),然后再将BGR转为YUV444(CV_BGR2YUV),这很蛋疼!效率太低了。

    实质上,只要我们理解了YUV420与YUV444的数据格式,完全可以自己转换的,下面使用C++实现YUV420与YUV444互转,这部分不依赖OpenCV,因此效率十分高的!!!


1、YUV420转YUV444

    YUV420转YUV444,实际就是对UV两个分量色度进行上采样,最为简单的实现思路是直接填充。

    以U分量为例,其序列如下

yuv444 yuv420_硬盘转速和缓存哪个重要

    对U进行插值,每个田字格四个位置使用一个U值。

yuv444 yuv420_硬盘转速和缓存哪个重要

    在代码中,可以直接通过对数组循环赋值即可完成。对V分量的操作相同。 填充方式实现简单,但效果较差,一般可以通过插值来完成上采样。

   下面是C++实现YUV420转YUV444的代码:

	void YUV420TOYUV444(unsigned char *inbuf, unsigned char *outbuf, int w, int h) {
		unsigned char *srcY = NULL, *srcU = NULL, *srcV = NULL;
		unsigned char *desY = NULL, *desU = NULL, *desV = NULL;
		srcY = inbuf;//Y
		srcU = srcY + w * h;//U
		srcV = srcU + w * h / 4;;//V

		desY = outbuf;
		desU = desY + w * h;
		desV = desU + w * h;
		memcpy(desY, srcY, w * h * sizeof(unsigned char));//Y分量直接拷贝即可
	   //UV分量转换
		int i, j;
		for (i = 0; i < h; i += 2) {//行
			for (j = 0; j < w; j += 2) {//列
										//U
				desU[i*w + j] = srcU[i / 2 * w / 2 + j / 2];
				desU[i*w + j + 1] = srcU[i / 2 * w / 2 + j / 2];
				desU[(i + 1)*w + j] = srcU[i / 2 * w / 2 + j / 2];
				desU[(i + 1)*w + j + 1] = srcU[i / 2 * w / 2 + j / 2];
				//V
				desV[i*w + j] = srcV[i / 2 * w / 2 + j / 2];
				desV[i*w + j + 1] = srcV[i / 2 * w / 2 + j / 2];
				desV[(i + 1)*w + j] = srcV[i / 2 * w / 2 + j / 2];
				desV[(i + 1)*w + j + 1] = srcV[i / 2 * w / 2 + j / 2];
			}
		}
	}

2、YUV444转YUV420

    与YUV420与YUV444思路类似的,我们反过来计算,将YUV444下采样为YUV420即可,

    下面是C++实现YUV444转YUV420的代码:

	void YUV444TOYUV420(unsigned char *inbuf, unsigned char *outbuf, int w, int h) {
		unsigned char *srcY = NULL, *srcU = NULL, *srcV = NULL;
		unsigned char *desY = NULL, *desU = NULL, *desV = NULL;
		srcY = inbuf;//Y
		srcU = srcY + w * h;//U
		srcV = srcU + w * h;//V

		desY = outbuf;
		desU = desY + w * h;
		desV = desU + w * h / 4;

		int half_width = w / 2;
		int half_height = h / 2;
		memcpy(desY, srcY, w * h * sizeof(unsigned char));//Y分量直接拷贝即可
		 //UV
		for (int i = 0; i < half_height; i++) {
			for (int j = 0; j < half_width; j++) {
				*desU = *srcU;
				*desV = *srcV;
				desU++;
				desV++;
				srcU += 2;
				srcV += 2;
			}
			srcU = srcU + w;
			srcV = srcV + w;
		}
	}

四、显示和播放YUV文件

1、显示YUV图像

    YUV数据需要转到RGB才能显示正常,显示部分需要OpenCV的支持,OpenCV的配置,就不说啦,自己搞搞吧!!!这里提供有一个鄙人已经写好的cv_imageshow()函数,可以实现将输入的YUV数据流转为BGR格式,再用OpenCV的imshow()直接进行显示。注意,这里提供cv_imageshow()只能显示一帧数据,即你输入的inbuf数据流必须是一帧的YUV数据。

	/*********************************************************
	@brief         : 显示YUV图片,这里会将YUV转到RGB上进行显示
	@param winname : 窗口显示的名称
	@param inbuf   : YUV数据流,直接将read_yuvImage返回的YUV数据流传入即可显示
	@param w       : 宽width
	@param h       : 高height
	@param colorType: 颜色空间类型:CS_YUV444,CS_YUV420
	@return        : void
	********************************************************/
	void cv_imageshow(string winname, unsigned char* inframe, int w, int h, ColorSpace colorType) {
		if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
			cv::Mat yuvMat = cv::Mat::zeros(h, w, CV_8UC3);
			std::vector<cv::Mat> yuvChannels;
			cv::split(yuvMat, yuvChannels);
			yuvChannels.at(0).data = (unsigned char*)inframe;//Y
			yuvChannels.at(1).data = (unsigned char*)inframe + w * h;//U
			yuvChannels.at(2).data = (unsigned char*)inframe + w * h * 2;//V
			cv::merge(yuvChannels, yuvMat);
			cv::Mat bgrMat;
			cv::cvtColor(yuvMat, bgrMat, CV_YUV2BGR);
			cv::imshow(winname, bgrMat);
			cv::waitKey(30);
		}
		else if (colorType == CS_YUV420) {//定义保存YUV420的数组
			int bufLen = w*h * 3 / 2;
			cv::Mat yuvImg = cv::Mat::zeros(h * 3 / 2, w, CV_8UC1);
			memcpy(yuvImg.data, inframe, bufLen * sizeof(unsigned char));
			//cv::imshow(winname, yuvImg);
			//cv::waitKey(30);
			cv::Mat bgrImg= cv::Mat::zeros(h , w, CV_8UC3);
			cv::cvtColor(yuvImg, bgrImg, CV_YUV2BGR_I420);
			cv::imshow(winname, bgrImg);
			cv::waitKey(30);
		}
	}

2、播放YUV数据 

    上面提供的cv_imageshow()为了显示图片,所以只能显示一帧数据,即你输入的inbuf数据流必须是一帧的YUV数据。但很多YUV文件实质上是多帧的视频文件,要实现YUV文件的播放功能也很简单:循环读取YUV数据流,使用OpenCV的imshow()一帧一帧的显示,就实现了播放YUV的功能了:

    下面是C++实现的cvPlayYUV444和cvPlayYUV420的函数,可以实现播放YUV444和YUV420的文件:

	/*********************************************************
	@brief         : 播放YUV420/YUV444文件
	@param fileYUV : YUV文件
	@param w       : 宽width
	@param h       : 高height
	@return        : void
	********************************************************/
	void cvPlayYUV444(string fileYUV, int w, int h) {
		FILE* pFileIn = fopen(fileYUV.c_str(), "rb+");
		int bufLen = w * h * 3;
		unsigned char* pYuvBuf = new unsigned char[bufLen];
		cv::Mat yuvMat = cv::Mat::zeros(h, w, CV_8UC3);
		std::vector<cv::Mat> yuvChannels;
		cv::split(yuvMat, yuvChannels);
		while (fread(pYuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn))
		{
			//cv::Mat Y(i, w, CV_8UC1, (unsigned char*)pSrc);
			//cv::Mat U(i, w, CV_8UC1, (unsigned char*)pSrc + w * i);
			//cv::Mat V(i, w, CV_8UC1, (unsigned char*)pSrc + w * i * 2);
			yuvChannels.at(0).data = (unsigned char*)pYuvBuf;//Y
			yuvChannels.at(1).data = (unsigned char*)pYuvBuf + w * h;//U
			yuvChannels.at(2).data = (unsigned char*)pYuvBuf + w * h * 2;//V
			cv::merge(yuvChannels, yuvMat);
			cv::Mat bgrMat;
			cv::cvtColor(yuvMat, bgrMat, CV_YUV2BGR);
			cv::imshow(" cvPlayYUV444", bgrMat);
			cv::waitKey(30);
		}
		delete[] pYuvBuf;
		fclose(pFileIn);
	}


	void cvPlayYUV420(string fileYUV, int w, int h)
	{
		FILE* pFileIn = fopen(fileYUV.c_str(), "rb+");
		int bufLen = w*h * 3 / 2;
		unsigned char* pYuvBuf = new unsigned char[bufLen];
		while (fread(pYuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn))
		{
			cv::Mat yuvImg, rgbImg;
			yuvImg.create(h * 3 / 2, w, CV_8UC1);
			memcpy(yuvImg.data, pYuvBuf, bufLen * sizeof(unsigned char));
			cv::Mat gray = yuvImg(cv::Rect(0, 0, w, h));
			cv::cvtColor(yuvImg, rgbImg, CV_YUV2BGR_I420);
			//
			cv::imshow(" cvPlayYUV420", rgbImg);
			cv::waitKey(30);
		}
		delete[] pYuvBuf;
		fclose(pFileIn);
	}

五、完整的代码

     整理一下,这里提供了YUV.h和YUV.cpp源文件和测试main程序,注意定义了namespace名称空间为cs

     YUV444和YUV420的测试文件,可以这里下载https://download.csdn.net/download/guyuealian/10697442


YUV.h头文件:

#ifndef YUV_H
#define YUV_H
#include<opencv2/opencv.hpp>
#include <string>
using namespace std;
namespace cs {
	enum ColorSpace {
		CS_YUV444,
		CS_YUV420
	};
	enum ConvertColorSpace {
		CS_YUV444TOYUV420,
		CS_YUV420TOYUV444
	};
	/*********************************************************	
	@brief         : 读取yuv图像文件,若输入的是多帧的图像文件,如yuv视频文件,则返回最后一帧的数据
	@param fileYUV : YUV文件
	@param w       : 宽width
	@param h       : 高height
	@param colorType: 颜色空间类型:CS_YUV444,CS_YUV420
	@return        : unsigned char* 返回YUV数据
	********************************************************/
	unsigned char* read_yuvImage(string fileYUV, int w, int h, ColorSpace colorType);

	/*********************************************************
	@brief         : 播放YUV420/YUV444文件
	@param fileYUV : YUV文件
	@param w       : 宽width
	@param h       : 高height
	@return        : void
	********************************************************/
	void cvPlayYUV420(string fileYUV, int w, int h);
	void cvPlayYUV444(string fileYUV, int w, int h);

	/*********************************************************
	@brief         : 显示YUV图片,这里会将YUV转到RGB上进行显示
	@param winname : 窗口显示的名称
	@param inbuf   : YUV数据流,直接将read_yuvImage返回的YUV数据流传入即可显示
	@param w       : 宽width
	@param h       : 高height
	@param colorType: 颜色空间类型:CS_YUV444,CS_YUV420
	@return        : void
	********************************************************/
	void cv_imageshow(string winname, unsigned char* inbuf, int w, int h, ColorSpace colorType);

	/*********************************************************
	@brief         : 保存YUV数据流
	@param fileYUV : 输出YUV文件的路径
	@param inbuf   : 需要保存的YUV数据流
	@param w       : 宽width
	@param h       : 高height
	@param colorType: 颜色空间类型:CS_YUV444,CS_YUV420
	@return        : void
	********************************************************/
	void write_yuvImage(string fileYUV, unsigned char* inbuf, int w, int h, ColorSpace colorType);

	/*********************************************************
	@brief         : 实现YUV420与YUV444数据之间的转换,实质上会分别调用YUV420TOYUV444和YUV444TOYUV420函数
	@param inbuf   : 输入YUV数据流
	@param w       : 宽width
	@param h       : 高height
	@param ConvertColorSpace: 转换颜色空间类型:
	                         CS_YUV444TOYUV420:实现YUV444转YUV420
							 CS_YUV420TOYUV444:实现YUV420转YUV444
	@return        : unsigned char* 返回转换后的YUV数据
	********************************************************/
	unsigned char* convertYUV(unsigned char* inbuf, int w, int h, ConvertColorSpace type);
	void YUV420TOYUV444(unsigned char *inbuf, unsigned char *outbuff, int w, int h);
	void YUV444TOYUV420(unsigned char *inbuf, unsigned char *outbuff, int w, int h);

	/*********************************************************
	@brief         : 将YUV数据流转为OpenCV的Mat类型,方便使用OpenCV显示
	@param inbuf   : 输入YUV数据流
	@param w       : 宽width
	@param h       : 高height
	@param colorType: 颜色空间类型:CS_YUV444,CS_YUV420
	@return        : Mat类型图像数据
	********************************************************/
	cv::Mat YUVBufTOYUVMat(unsigned char* inbuf, int w, int h, ColorSpace colorType);

	/*********************************************************
	@brief         : 将OpenCV的Mat类型图像转YUV数据流
	@param inbuf   : OpenCV的Mat类型图像
	@param colorType: Mat类型图像颜色空间类型:CS_YUV444,CS_YUV420
	@return        : unsigned char* 返回转换后的YUV数据流
	********************************************************/
	unsigned char* YUVMatTOYUVBUF(cv::Mat yuvMat, ColorSpace colorType);
}
#endif

 


YUV.cpp实现文件: 

#include "YUV.h"
#include <opencv2/opencv.hpp>
namespace cs {
//void read_yuvImage(string fileYUV, unsigned char* outYUV, int w, int i, ColorSpace colorType)
/*读取yuv图像文件,注意:若输入的是多帧的图像文件,如yuv视频文件,则返回最后一帧的数据*/
unsigned char* read_yuvImage(string fileYUV, int w, int h, ColorSpace colorType) {
FILE * pFileIn;      //输入CS_YUV444文件
if (NULL == (pFileIn = fopen(fileYUV.c_str(), "rb"))) {
printf("File input is can't open!\n");
fclose(pFileIn);
return nullptr;
}
int bufLen = 0;
if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
bufLen = w * h * 3;
}
else if (colorType == CS_YUV420) {//定义保存YUV420的数组
bufLen = w*h * 3 / 2;
}
unsigned char* yuvBuf = new unsigned char[bufLen];
//fread(yuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn);//返回第一帧
while (fread(yuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn))//返回最后一帧
{
}
fclose(pFileIn);
return yuvBuf;
}
void cvPlayYUV444(string fileYUV, int w, int h) {
FILE* pFileIn = fopen(fileYUV.c_str(), "rb+");
int bufLen = w * h * 3;
unsigned char* pYuvBuf = new unsigned char[bufLen];
cv::Mat yuvMat = cv::Mat::zeros(h, w, CV_8UC3);
std::vector<cv::Mat> yuvChannels;
cv::split(yuvMat, yuvChannels);
while (fread(pYuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn))
{
//cv::Mat Y(i, w, CV_8UC1, (unsigned char*)pSrc);
//cv::Mat U(i, w, CV_8UC1, (unsigned char*)pSrc + w * i);
//cv::Mat V(i, w, CV_8UC1, (unsigned char*)pSrc + w * i * 2);
yuvChannels.at(0).data = (unsigned char*)pYuvBuf;//Y
yuvChannels.at(1).data = (unsigned char*)pYuvBuf + w * h;//U
yuvChannels.at(2).data = (unsigned char*)pYuvBuf + w * h * 2;//V
cv::merge(yuvChannels, yuvMat);
cv::Mat bgrMat;
cv::cvtColor(yuvMat, bgrMat, CV_YUV2BGR);
cv::imshow(" cvPlayYUV444", bgrMat);
cv::waitKey(30);
}
delete[] pYuvBuf;
fclose(pFileIn);
}
void cvPlayYUV420(string fileYUV, int w, int h)
{
FILE* pFileIn = fopen(fileYUV.c_str(), "rb+");
int bufLen = w*h * 3 / 2;
unsigned char* pYuvBuf = new unsigned char[bufLen];
while (fread(pYuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn))
{
cv::Mat yuvImg, rgbImg;
yuvImg.create(h * 3 / 2, w, CV_8UC1);
memcpy(yuvImg.data, pYuvBuf, bufLen * sizeof(unsigned char));
cv::Mat gray = yuvImg(cv::Rect(0, 0, w, h));
cv::cvtColor(yuvImg, rgbImg, CV_YUV2BGR_I420);
//
cv::imshow(" cvPlayYUV420", rgbImg);
cv::waitKey(30);
}
delete[] pYuvBuf;
fclose(pFileIn);
}
void write_yuvImage(string fileYUV, unsigned char* inframe, int w, int h, ColorSpace colorType) {
FILE * pFileOut;     //输出YUV文件
if (NULL == (pFileOut = fopen(fileYUV.c_str(), "wb"))) {
printf("File output is can't open!\n");
fclose(pFileOut);
return;
}
int bufLen = 0;
if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
bufLen = w * h * 3;
}
else if (colorType == CS_YUV420) {//定义保存YUV420的数组
bufLen = w*h * 3 / 2;
}
fwrite(inframe, bufLen * sizeof(unsigned char), 1, pFileOut);
fclose(pFileOut);
}
void cv_imageshow(string winname, unsigned char* inframe, int w, int h, ColorSpace colorType) {
if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
cv::Mat yuvMat = cv::Mat::zeros(h, w, CV_8UC3);
std::vector<cv::Mat> yuvChannels;
cv::split(yuvMat, yuvChannels);
yuvChannels.at(0).data = (unsigned char*)inframe;//Y
yuvChannels.at(1).data = (unsigned char*)inframe + w * h;//U
yuvChannels.at(2).data = (unsigned char*)inframe + w * h * 2;//V
cv::merge(yuvChannels, yuvMat);
cv::Mat bgrMat;
cv::cvtColor(yuvMat, bgrMat, CV_YUV2BGR);
cv::imshow(winname, bgrMat);
cv::waitKey(30);
}
else if (colorType == CS_YUV420) {//定义保存YUV420的数组
int bufLen = w*h * 3 / 2;
cv::Mat yuvImg = cv::Mat::zeros(h * 3 / 2, w, CV_8UC1);
memcpy(yuvImg.data, inframe, bufLen * sizeof(unsigned char));
//cv::imshow(winname, yuvImg);
//cv::waitKey(30);
cv::Mat bgrImg= cv::Mat::zeros(h , w, CV_8UC3);
cv::cvtColor(yuvImg, bgrImg, CV_YUV2BGR_I420);
cv::imshow(winname, bgrImg);
cv::waitKey(30);
}
}
void YUV420TOYUV444(unsigned char *inbuf, unsigned char *outbuf, int w, int h) {
unsigned char *srcY = NULL, *srcU = NULL, *srcV = NULL;
unsigned char *desY = NULL, *desU = NULL, *desV = NULL;
srcY = inbuf;//Y
srcU = srcY + w * h;//U
srcV = srcU + w * h / 4;;//V
desY = outbuf;
desU = desY + w * h;
desV = desU + w * h;
memcpy(desY, srcY, w * h * sizeof(unsigned char));//Y分量直接拷贝即可
//UV分量转换
int i, j;
for (i = 0; i < h; i += 2) {//行
for (j = 0; j < w; j += 2) {//列
//U
desU[i*w + j] = srcU[i / 2 * w / 2 + j / 2];
desU[i*w + j + 1] = srcU[i / 2 * w / 2 + j / 2];
desU[(i + 1)*w + j] = srcU[i / 2 * w / 2 + j / 2];
desU[(i + 1)*w + j + 1] = srcU[i / 2 * w / 2 + j / 2];
//V
desV[i*w + j] = srcV[i / 2 * w / 2 + j / 2];
desV[i*w + j + 1] = srcV[i / 2 * w / 2 + j / 2];
desV[(i + 1)*w + j] = srcV[i / 2 * w / 2 + j / 2];
desV[(i + 1)*w + j + 1] = srcV[i / 2 * w / 2 + j / 2];
}
}
}
void YUV444TOYUV420(unsigned char *inbuf, unsigned char *outbuf, int w, int h) {
unsigned char *srcY = NULL, *srcU = NULL, *srcV = NULL;
unsigned char *desY = NULL, *desU = NULL, *desV = NULL;
srcY = inbuf;//Y
srcU = srcY + w * h;//U
srcV = srcU + w * h;//V
desY = outbuf;
desU = desY + w * h;
desV = desU + w * h / 4;
int half_width = w / 2;
int half_height = h / 2;
memcpy(desY, srcY, w * h * sizeof(unsigned char));//Y分量直接拷贝即可
//UV
for (int i = 0; i < half_height; i++) {
for (int j = 0; j < half_width; j++) {
*desU = *srcU;
*desV = *srcV;
desU++;
desV++;
srcU += 2;
srcV += 2;
}
srcU = srcU + w;
srcV = srcV + w;
}
}
unsigned char* convertYUV(unsigned char* inbuf, int w, int h, ConvertColorSpace type) {
int bufLen = 0;
if (type == CS_YUV420TOYUV444) {//定义保存CS_YUV444的数组
bufLen = w * h * 3;
unsigned char* pDst = new unsigned char[bufLen];//定义保存YUV420的数组
YUV420TOYUV444(inbuf, pDst, w, h);
return pDst;
}
else if (type == CS_YUV444TOYUV420) {
bufLen = w*h * 3 / 2;
unsigned char* pDst = new unsigned char[bufLen];//定义保存YUV420的数组
YUV444TOYUV420(inbuf, pDst, w, h);
return pDst;
}
}
cv::Mat YUVBufTOYUVMat(unsigned char* inbuf,int w,int h, ColorSpace colorType) {
if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
cv::Mat yuvMat = cv::Mat::zeros(h, w, CV_8UC3);
std::vector<cv::Mat> yuvChannels;
cv::split(yuvMat, yuvChannels);
yuvChannels.at(0).data = (unsigned char*)inbuf;//Y
yuvChannels.at(1).data = (unsigned char*)inbuf + w * h;//U
yuvChannels.at(2).data = (unsigned char*)inbuf + w * h * 2;//V
cv::merge(yuvChannels, yuvMat);
return yuvMat;
}
else if (colorType == CS_YUV420) {//定义保存YUV420的数组
int bufLen = w*h * 3 / 2;
cv::Mat yuvMat= cv::Mat::zeros(h * 3 / 2, w, CV_8UC1);
memcpy(yuvMat.data, inbuf, bufLen * sizeof(unsigned char));
return yuvMat;
}
}
unsigned char* YUVMatTOYUVBUF(cv::Mat yuvMat, ColorSpace colorType) {
if (colorType == CS_YUV444) {//定义保存CS_YUV444的数组
int w = yuvMat.cols;
int h = yuvMat.rows;
int bufLen = w*h * 3;
unsigned char* outbuf = new unsigned char[bufLen];
std::vector<cv::Mat> yuvChannels;
cv::split(yuvMat, yuvChannels);
memcpy(outbuf, yuvChannels.at(0).data, w * h * sizeof(unsigned char));//Y分量直接拷贝即可
memcpy(outbuf + w * h, yuvChannels.at(1).data, w * h * sizeof(unsigned char));//Y分量直接拷贝即可
memcpy(outbuf + w * h * 2, yuvChannels.at(2).data, w * h * sizeof(unsigned char));//Y分量直接拷贝即可
return outbuf;
}
else if (colorType == CS_YUV420) {//定义保存YUV420的数组
int w = yuvMat.cols;
int h = yuvMat.rows;
int bufLen = yuvMat.total();//w*h ;
unsigned char* outbuf = new unsigned char[bufLen];
//outbuf = yuvMat.data;
memcpy(outbuf,yuvMat.data, bufLen * sizeof(unsigned char));
return outbuf;
}
}
}

    YUV444与YUV420互转测试:

int main() {
string fileYUV = "D:\\imageEnhance\\YUVdata\\YUV444_1366_768.yuv";
//string fileYUV = "D:\\imageEnhance\\YUVdata\\yuv444_image_640_480.yuv";
//string fileYUV = "D:\\imageEnhance\\YUVdata\\sintel_640_360.yuv";
int w = 1366;
int h = 768;
char unsigned *yuv444_buf= cs::read_yuvImage(fileYUV, w, h, cs::CS_YUV444);//读取YUV数据
cs::cv_imageshow("CS_YUV444", yuv444_buf, w, h, cs::CS_YUV444);
char unsigned *yuv420_buf = cs::convertYUV(yuv444_buf, w, h, cs::CS_YUV444TOYUV420);//将YUV444转为YUV420
cs::cv_imageshow("CS_YUV420", yuv420_buf, w, h, cs::CS_YUV420);
cin.get();
return 0;
}

    YUV444与YUV420播放测试:

int main() {
//string fileYUV = "D:\\imageEnhance\\YUVdata\\YUV444_1366_768.yuv";
//string fileYUV = "D:\\imageEnhance\\YUVdata\\yuv444_image_640_480.yuv";
string fileYUV = "D:\\imageEnhance\\YUVdata\\sintel_640_360.yuv";
int w = 640;
int h = 360;
cs::cvPlayYUV420(fileYUV,w,h);
cin.get();
return 0;
}

yuv444 yuv420_硬盘转速和缓存哪个重要


参考资料:

[1]《YUV420转YUV444》https://blog.csdn.net/lin453701006/article/details/53053185,这个博客的思路不错,就是代码太烂了。

[2]《YUV444与YUV422下采样》https://blog.csdn.net/qq_36113899/article/details/68958344

如果你觉得该帖子帮到你,还望贵人多多支持,鄙人会再接再厉,继续努力的~

yuv444 yuv420_硬盘转速和缓存哪个重要

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/215495.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 草根程序员转型做项目管理走过的点点滴滴之_华为裁员感想

    草根程序员转型做项目管理走过的点点滴滴之_华为裁员感想自己一直假想还停留在29岁那个黄金年龄,仿佛明天就要30岁(老话里而立的年纪),因此总感觉要拼命的工作,拼命的学习好让明天立的更稳固一些。缘起百度了一把华为裁员的相关报道,又看了几篇别人写的华为裁员的理解已经对中国it行业的痛批文章,把我一下子拉回了现实,85年出生在农村的自己到现在恰好也是三十二几岁的阶段,发现也没啥立不立的,还是那个拼命三郎的状态,顿时有些迷惑与感伤。

  • zabbix邮箱告警的详细配置

    zabbix邮箱告警的详细配置

  • ireport使用教程_计算机初学者入门教程

    ireport使用教程_计算机初学者入门教程一、iReport 是什么    iReport是一个能够创建复杂报表的开源项目,并且它能调用JasperReports库应用于任何一种Java应用程序。本身是分布式的且由符合GNU通用公共许可的百分之百纯java编写。由于它丰富的图形界面,你能够很快的创建出任何一种你想要的报表。iReport能够让我们提高技术方面的信心,比如它能降低学习JasperReports的XML语法的难

  • AC餐饮指的是什么_餐饮tc和ac的区别

    AC餐饮指的是什么_餐饮tc和ac的区别奶牛们在吃饭方面十分挑剔。每头奶牛都有自己喜欢的食物和饮料,并且不会食用其他不喜欢的食物和饮料。农夫约翰为他的奶牛们做了美味的饭菜,但他忘了对照他们的喜好来检查菜单。虽然他可能无法令所有奶牛满意,但他想给尽可能多的奶牛提供一顿完整的用餐—-既有食物可吃,也有饮料可喝。农夫约翰一共烹制了 F 种食物,并提供了 D 种饮料。约翰共有 N 头奶牛,其中第 i 头奶牛有 Fi 种喜欢的食物以及 Di 种喜欢的饮料。约翰需要给每头奶牛分配一种食物和一种饮料,并使得有吃有喝的奶牛数量尽可能大。每种食物

  • Mysql 5.7解压版下载安装及配置教程

    Mysql 5.7解压版下载安装及配置教程最近在学习中用到了MySQL数据库,在安装过程中遇到了不少问题,在翻了大半天百度后,问题基本都解决了,所以写一篇MySQL5.7解压版的图文详细安装教程。至于为什么我会选择解压版而不是安装版,一是因为安装版没有64位版本;二是因为安装版的软件在重装系统或者挪动软件的位置后,就会出现无法使用的情况,而大部分绿色版或者解压版的软件就不存在这样的问题,只需要重新配置一下即可使用。如果你是刚接触MySQL的同学,安装版也是你不错的选择,安装时无脑点下一步基本就可以装好,默认参数程序都会给你配好,既简单又方.

  • uva 11151 Longest Palindrome (最长公共子序列)[通俗易懂]

    uva 11151 Longest Palindrome (最长公共子序列)[通俗易懂]uva11151LongestPalindromeApalindromeisastringthatreadsthesamefromtheleftasitdoesfromtheright.Forexample,I,GAGandMADAMarepalindromes,butADAMisnot.Here,weconsideralso

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号