一、实验目的
YUV与RGB空间的转换
二、实验原理
(1)YUV与RGB空间的相互转换由电视原理可知,亮度和色差信号的构成如下:
Y=0.2990R+0.5870G+0.1140B
R-Y=0.7010R-0.5870G-0.1140B
B-Y=-0.2990R-0.5870G+0.8860B
为了使色差信号的动态范围控制在0.5之间,需要进行归一化,对色差信号引入压缩系数。归一化后的色差信号为:
U=-0.1684R-0.3316G+0.5B
V=0.5R-0.4187G-0.0813B
(2) 码电平分配及数字表达式
亮电平信号量化后码电平分配
在对分量信号进行8比特均匀量化时,共分为256个等间隔的量化级。为了防止信号变动造成过载,在256级上端留20级,下端留16级作为信号超越动态范围的保护带。
色差信号量化后码电平分配
色差信号经过归一化处理后,动态范围为-0.5-0.5,让色差零电平对应码电平128, 色差信号总共占225个量化级。在256级上端留15级,下端留16级作为信号超越动态范围 的保护带。
(3)色度格式
4:2:0格式是指色差信号U,V的取样频率为亮度信号取样频率的四分之一,在水平方 向和垂直方向上的取样点数均为Y的一半
三、实验内容
1、关键代码:YUV2GRGB的转换代码
根据色度公式和色差公式。可以推出由YUV分量表示RGB的算法如下
在进行YUV2RGB的转换时,得到的RGB三个数据可能超过了unsigned char类型可以表示的范围,即可能<0或者>255。因此需要对yuv2rgb进行适当的修正,将>255的值都直接=255,<0的值都直接=0。
由此可得算法代码如下
void yuv2rgb(unsigned long picHeight, unsigned long picWidth, unsigned char *bufferYuv, int *r, int *g, int *b, FILE *rgb)
{
unsigned int i,j;
unsigned char *y, *u, *v,*u444,*v444;
y = (unsigned char *)malloc(picHeight * picWidth);
u = (unsigned char *)malloc(picHeight * picWidth /4);
v = (unsigned char *)malloc(picHeight * picWidth /4);
u444 = (unsigned char *)malloc(picHeight * picWidth);
v444 = (unsigned char *)malloc(picHeight * picWidth);
for (i = 0;i < picHeight*picWidth;i++)
{
*(y + i) = *(bufferYuv + i);
}
for (i = 0;i < picHeight*picWidth/4;i++)
{
*(u + i) = *(bufferYuv + i + picHeight*picWidth);
*(v + i) = *(bufferYuv + i + picHeight*picWidth * 5 / 4);
}
int k = 0;
for (i = 0;i < picHeight/2 ;i++)
{
for (j = 0;j < picWidth/2 ;j++)
{
*(u444 + picWidth * 2 * i + 2 * j) = *(u + k);
*(u444 + picWidth * 2 * i + 2 * j + 1) = *(u + k);
*(u444 + picWidth * (2 * i + 1) + 2 * j) = *(u + k);
*(u444 + picWidth * (2 * i + 1) + 2 * j + 1) = *(u + k);
*(v444 + picWidth * 2 * i + 2 * j) = *(v + k);
*(v444 + picWidth * 2 * i + 2 * j + 1) = *(v + k);
*(v444 + picWidth * (2 * i + 1) + 2 * j) = *(v + k);
*(v444 + picWidth * (2 * i + 1) + 2 * j + 1) = *(v + k);
k++;
}
}
for (i = 0;i < picHeight*picWidth;i++)
{
*(r + i) = int((*(y + i) * 298 + *(v444 + i) * 411 - 57344) / 255);
*(g + i) = int((*(y + i) * 298 - *(u444 + i) * 101 - *(v444 + i) * 211 + 34739) / 255);
*(b + i) = int((*(y + i) * 298 + *(u444 + i) * 519 - 71117) / 255);
//修正
if (*(r + i) < 0)
*(r + i) = 0;
if (*(r + i) > 255)
*(r + i) = 255;
if (*(g + i) < 0)
*(g + i) = 0;
if (*(g + i) > 255)
*(g + i) = 255;
if (*(b + i) < 0)
*(b + i) = 0;
if (*(b + i) > 255)
*(b + i) = 255;
}
unsigned char *rgbBuffer;
rgbBuffer = (unsigned char *)malloc(picHeight*picWidth * 3);
for (i = 0;i < picHeight*picWidth;i++)
{
*(rgbBuffer + 3 * i) = *(b + i);
*(rgbBuffer + 3 * i + 1) = *(g + i);
*(rgbBuffer + 3 * i + 2) = *(r + i);
}
fwrite(rgbBuffer, 1, picHeight*picWidth * 3, rgb);
free(y);
free(u);
free(v);
free(u444);
free(v444);
free(rgbBuffer);
}
2、主函数
#include <stdio.h>
#include <stdlib.h>
#include "yuv2rgb.h"
int main(int argc, const char * argv[])
{
FILE *yuv = NULL;
FILE *rgb = NULL;
if ((rgb = fopen(argv[2], "wb")) == NULL)
{
printf("rgb file fail!");
exit(0);
}
unsigned long picHeight, picWidth;
picHeight = atoi(argv[3]);
picWidth = atoi(argv[4]);
if ((yuv = fopen(argv[1], "rb")) == NULL)
{
printf("yuv file fail!");
exit(0);
}
int buffer2size = picHeight * picWidth * 3 / 2;//256*256
printf("yuvFile length:%d\n", buffer2size);
unsigned char *bufferYuv;
int *r, *g, *b;
bufferYuv = (unsigned char *)malloc(buffer2size);
r = (int *)malloc(sizeof(int)* picHeight*picWidth);
g = (int *)malloc(sizeof(int)* picHeight*picWidth);
b = (int *)malloc(sizeof(int)* picHeight*picWidth);
fread(bufferYuv, 1, buffer2size, yuv);
yuv2rgb(picHeight,picWidth,bufferYuv,r,g,b,rgb);
free(bufferYuv);
free(r);
free(g);
free(b);
fclose(yuv);
fclose(rgb);
return 0;
}
三、实验结果
1、原RGB图像
2、由YUV转换后的RGB图像
四、误差分析
从两张图片中可以看出存在一定的色度差异。可能是在YUV转换RGB过程中丢失了一部分色度信息,导致误差。