1、参考
总结各种RGB转YUV的转换公式
RGB24转YUV422转换算法
RGB24转YUV420
总结各种RGB转YUV的转换公式
Android视频编码——RGBA、RGB、BGRA、BGR转YUV420P、YUV420SP
YUV2RGB
YUV420P转换为RGB32格式
YUV与RGB互转各种公式 (YUV与RGB的转换公式有很多种,请注意区别!!!)
YUV格式学习:YUV420P、YV12、NV12、NV21格式转换成RGB24
YUV / RGB 格式及快速转换算法 YUV RGB 转换公式
2、视频颜色空间标准BT601/BT709差异
参考:【Codecs系列】视频格式国际标准:BT601/BT709/BT2020
BT.601格式的颜色空间转换:
//YUV--->RGB
//R = 1.164(Y - 16) + 1.596(V - 128)
//G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
//B = 1.164(Y - 16) + 2.018(U - 128)
//RGB--->YUV
//Y = 16 + 0.257 * R + 0.504 * G + 0.098 *B
//U = 128 - 0.148 * R - 0.291 * G + 0.439 * B
//V = 128 + 0.439 * R - 0.368 * G - 0.071 * B
BT.709格式的颜色空间转换:
// RGB--->YUV
// Y = 16 + 0.183 * R + 0.614 * G + 0.062 * B
// Cb = 128 - 0.101 * R - 0.339 * G + 0.439 * B
// Cr = 128 + 0.439 * R - 0.399 * G - 0.040 * B
// YUV--->RGB
// R = 1.164 *(Y - 16) + 1.792 *(Cr - 128)
// G = 1.164 *(Y - 16) - 0.213 *(Cb - 128) - 0.534 *(Cr - 128)
// B = 1.164 *(Y - 16) + 2.114 *(Cb - 128)
3、YUV420P转BGR24
/*********************************************************************
/* Function: YUV420pToBGR24
/* Usage: colorspace convertion from YUV420P(I420) to BGR24
/* Parameters:
/* pYUV [In] - source YUV data
/* pBGR24 [Out] - output RGB data
/* width [In] - image width
/* height [In] - image height
/*
/* Modified: 2019.7.13
/*********************************************************************/
int YUV420pToBGR24(unsigned char *pYUV, unsigned char *pBGR24, int width, int height)
{
int bgr[3];
int i,j,k;
int yIdx, uIdx, vIdx, idx;
int len = width * height;
if(!pYUV || !pBGR24 || width < 1 || height < 1)
return -1;
unsigned char* yData = pYUV;
unsigned char* uData = &yData[len];
unsigned char* vData = &uData[len>>2];
for(i = 0; i < height; i++)
{
for(j = 0; j < width; j++)
{
yIdx = i*width+j;
vIdx = (i/2)*(width/2)+(j/2);
uIdx = vIdx;
// BT. 601
bgr[0] = (298*(yData[yIdx] - 16) + 517 * (uData[uIdx] - 128) + (1<<7)) >> 8; // b分量值
bgr[1] = (298*(yData[yIdx] - 16) - 208 * (vData[vIdx] - 128) - 100 * (uData[uIdx] - 128) + (1<<7))>>8;// g分量值
bgr[2] = (298*(yData[yIdx] - 16) + 409 * (vData[vIdx] - 128) + (1<<7))>>8; // r分量值
for(k=0; k<3; k++)
{
idx = (i*width+j)*3+k;
pBGR24[idx] = CLIP_COLOR(bgr[k]);
}
}
}
return 0;
}
4、BGR24转YUV420P
/*********************************************************************
/* Function: BGR24toYUV420P
/* Usage: colorspace convertion from BGR24 to YUV420P(I420)
/* Parameters:
/* pBGR24 [In] - source RGB data
/* pYUV [Out] - output YUV data
/* width [In] - image width
/* height [In] - image height
/*
/* Modified: 2019.7.13
/*********************************************************************/
int BGR24toYUV420P(unsigned char *pBGR24, unsigned char *pYUV, int width, int height)
{
int i,j,index;
unsigned char *bufY, *bufU, *bufV, *bufRGB;
unsigned char y, u, v, r, g, b;
if(!pYUV || !pBGR24 || width < 1 || height < 1)
return -1;
memset(pYUV, 0 ,width*height*3/2*sizeof(unsigned char));
bufY = pYUV;
bufU = bufY + width*height;
bufV = bufU + (width*height*1/4);
for(j=0; j < height; j++)
{
bufRGB = pBGR24 + width*j*3;
for(i=0; i < width; i++)
{
index = j*width+i;
b = *(bufRGB++);
g = *(bufRGB++);
r = *(bufRGB++);
y = (unsigned char)((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = (unsigned char)((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = (unsigned char)((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
*(bufY++) = CLIP_COLOR(y);
if(j%2==0 && index%2==0)
{
*(bufU++) = CLIP_COLOR(u);
*(bufV++) = CLIP_COLOR(v);
}
}
}
return 0;
}
5、测试Demo
//Demo: This demo used to test YUV2BGR and BGR2YUV
int main(int argc, char *argv[])
{
FILE *fin, *fou;
unsigned char *pInYUVBuf, *pYBuf, *pUBuf, *pVBuf;
unsigned char *pBGRBuf;
int index, framesize;
if (argc < 4)
{
printf("Usage: ./BGR24toYUV420P.exe inputYUV outputYUV width height\n");
return -1;
}
char* input = argv[1];
char* output = argv[2];
int width = atoi(argv[3]);
int height = atoi(argv[4]);
Mat mBGR_to_show = Mat(height, width, CV_8UC3);
fin = fopen(input, "rb");
if(NULL == fin)
{
printf("[demo] error: open fin failed!!!\n");
return -1;
}
fou = fopen(output, "wb");
if(NULL == fou)
{
printf("[demo] error: open fou failed!!!\n");
return -1;
}
pInYUVBuf = (unsigned char*) malloc(width*height*3/2); // YUV buffer
if(NULL == pInYUVBuf)
{
printf("[demo] error: open pInYUVBuffer failed!!!\n");
return -1;
}
pYBuf = pInYUVBuf;
pUBuf = pYBuf + width*height;
pVBuf = pUBuf + width*height/4;
framesize = width*height*3/2;
pBGRBuf = (unsigned char*) malloc(width*height*3); // BGR buffer
if(NULL == pBGRBuf)
{
printf("[demo] error: open pBGRBuf failed!!!\n");
return -1;
}
index = 0;
while(framesize == fread(pInYUVBuf,1,width*height*3/2,fin))
{
YUV420pToBGR24(pInYUVBuf, pBGRBuf, width, height);
memcpy(mBGR_to_show.data, pBGRBuf, sizeof(unsigned char)*width*height*3);
namedWindow("RGB", CV_WINDOW_NORMAL);
imshow("RGB", mBGR_to_show);
waitKey(2);
BGR24toYUV420P(pBGRBuf, pInYUVBuf, width, height);
fwrite(pInYUVBuf, 1, width*height*3/2, fou);
index++;
printf("[demo] info: %d frame process ok!!!\n", index);
}
system("pause");
return 0;
}
6、效果图
7、分析
将YUV420P转换成BGR24,然后再转换到YUV420P,会有一定的损失,转换的后的YUV与原始YUV会有1~5个像素值的差异 。
THE END!
本博文只能阅读,谢绝转载,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2963033731@qq.com