欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

转换详解:YUV420到YUV444的转换方法,以及YUV420和YUV444的数据读取、储存技巧,深入解析YUV颜色空间的显示与播放功能

最编程 2024-07-24 14:39:57
...
#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;
}
}
}