数据压缩实验一:彩色空间转换实验(yuv2rgb)

    xiaoxiao2021-03-25  68

    一、基本原理

    1、rgb转yuv公式

    Y=0.2990*R+0.5870*G+0.1140*B

    R-Y=0.7010*R-0.5870*G-0.1140*B

    B-Y=-0.2990*R-0.5870*G+0.8860*B

    为了使色差信号的动态范围控制在0.5之间,需要进行归一化。

    U= 0.492*(B-Y)= -0.147*R-0.289*G+0.436*B 

    V= 0.877*(R-Y)= 0.615*R-0.515*G-0.100*B

    色差信号经过归一化处理后,动态范围为-0.5-0.5,让色差零电平对应码电平128,色差信号总共占225个量化级。在256级上端留15级,下端留16级作为信号超越动态范围的保护带。

    U=-0.1684R-0.3316G+0.5B

    V=0.5R-0.4187G-0.0813B

    2、yuv转rgb公式

    R = Y + 1.140*V G = Y - 0.394*U - 0.581*V B = Y + 2.032*U 经过归一化处理,使其动态范围控制在-0.5—0.5之间,并让零电平对应码电平128。 R = Y + 1.4075 *(V-128)        G = Y – 0.3455 *(U –128) – 0.7169 *(V –128)        B = Y + 1.779 *(U – 128)

    3、rgb与yuv存储格式

    (1)rgb存储格式

    RGB格式的图像存储的顺序,是以B、G、R的顺序进行存储的。(4:4:4) BGRBGR                    

    (2)yuv存储格式

    yuv格式的图像每四个Y共用一组UV分量, 色差信号U,V的取样频率为亮度信号取样频率的四分之一,在水平方向和垂直方向上的取样点数均为Y的一半。(4:2:0) Y Y Y YYYYY                        V   U           

    二、实验流程分析

    1、rgb2yuv

    (1)定义指针,确定类型并开辟空间 (2)再读入rgb文件,根据公式计算出yuv (3)对uv分量进行下采样 (4)写入yuv文件

    2、yuv2rgb

    (1)定义指针,确定类型并开辟空间 (2)打开yuv文件 (3)对uv分量进行上采样     (4)根据公式计算出rgb (5)写入rgb文件

    三、关键代码及其分析(yuv2rgb)

    1、定义指针并开辟空间

    u_int8_t* rgbBuf = NULL; u_int8_t* yBuf = NULL; u_int8_t* uBuf = NULL; u_int8_t* vBuf = NULL; /* get an input buffer for a frame */ yBuf = (u_int8_t*)malloc(frameWidth * frameHeight); uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);//yuv文件中v分量为v分量的1/4 vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);//yuv文件中u分量为y分量的1/4 /* get the output buffers for a frame */ rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);//rgb文件由rgb三个分量所构成,所以其存储大小应为一帧图像大小的三倍

    2、打开yuv文件

    char* rgbFileName = NULL; char* yuvFileName = NULL; FILE* rgbFile = NULL; FILE* yuvFile = NULL; /* open the YUV file */ yuvFile = fopen(yuvFileName, "rb"); if (yuvFile == NULL) { printf("cannot find yuv file\n"); exit(1); } else { printf("The input yuv file is %s\n", yuvFileName); } /* open the RAW file */ rgbFile = fopen(rgbFileName, "wb"); if (rgbFile == NULL) { printf("cannot find rgb file\n"); exit(1); } else { printf("The output rgb file is %s\n", rgbFileName); }

    3、YUV2RGB

    (1)函数变量定义 int YUV2RGB(int x_dim, int y_dim, void *rgb, void *yr, void *ur, void *vr,int flip)   函数中指针的定义 unsigned char *r, *g, *b;//分别指向输出的rgb文件中的r,g,b unsigned char *y, *u, *v;//分别指向输入的yuv文件中的y,u,v unsigned char *y_buffer, *u_buffer, *v_buffer;//分别寄存yuv文件中的y,u,v unsigned char *sub_u_buf, *sub_v_buf;//分别寄存上采样后的u,v unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv;//用于u,v的上采样 y_buffer = (unsigned char *)yr; sub_u_buf = (unsigned char *)ur; sub_v_buf = (unsigned char *)vr; u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char)); v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char)); b= (unsigned char *)rgb; y = y_buffer; u = u_buffer; v = v_buffer; (2)定义查找表,方便计算 static float YUVRGB14075[256]; static float YUVRGB03455[256], YUVRGB07169[256]; static float YUVRGB17790[256]; void InitLookupTable() { int i; for (i = 0; i < 256; i++) YUVRGB14075[i] = (float)1.4075 *(i - 128); for (i = 0; i < 256; i++) YUVRGB03455[i] = (float)0.3455* (i - 128); for (i = 0; i < 256; i++) YUVRGB07169[i] = (float)0.7169 * (i - 128); for (i = 0; i < 256; i++) YUVRGB17790[i] = (float)1.7790 *(i - 128); } (3)对uv分量进行上采样 for (j = 0; j < y_dim / 2; j++) { psu = sub_u_buf + j * x_dim / 2; psv = sub_v_buf + j * x_dim / 2; pu1 = u_buffer + 2 * j * x_dim; pu2 = u_buffer + (2 * j + 1) * x_dim; pv1 = v_buffer + 2 * j * x_dim; pv2 = v_buffer + (2 * j + 1) * x_dim; for (i = 0; i < x_dim / 2; i++) { *pu1 = *psu; *(pu1 + 1) = *pu1; *pu2 = *psu; *(pu2 + 1) = *pu2; *pv1 = *psv; *(pv1 + 1) = *pv1; *pv2 = *psv; *(pv2 + 1) = *pv2; psu++; psv++; pu1 += 2; pu2 += 2; pv1 += 2; pv2 += 2; } }(4)根据公式计算出rgb for (i = 0; i < size; i++) { float br; float gr; float rr;//用来判断是否溢出,小于0则为0,大于255则为255 g = b + 1; r = b + 2; br = *y + YUVRGB17790[*u]; if (br < 0) br = 0; if (br > 255) br = 255; *b = (unsigned char)br; gr = *y - YUVRGB03455[*u] - YUVRGB07169[*v]; if (gr < 0) gr = 0; if (gr > 255) gr = 255; *g = (unsigned char)gr; rr = *y + YUVRGB14075[*v]; if (rr < 0) rr = 0; if (rr > 255) rr = 255; *r = (unsigned char)rr; b += 3; y++; u++; v++; }

    4、写入rgb文件

    while (fread(yBuf, 1, frameWidth * frameHeight, yuvFile) &&fread(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile) && fread(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile)) { if (YUV2RGB(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf,flip)) { printf("error"); return 0; } for (i = 0; i < frameWidth*frameHeight*3; i++) { if (rgbBuf[i] < 16) rgbBuf[i] = 16; if (rgbBuf[i] > 235) rgbBuf[i] = 235; } fwrite(rgbBuf, 1, frameWidth * frameHeight * 3, rgbFile); printf("\r...%d", ++videoFramesWritten); }

    四、实验结果及分析

    1、实验结果

    (1)rgb2yuv

    (2)yuv2rgb

    由以上几幅图观察得知:yuv转成rgb时,会有色差出现,红色会偏蓝,蓝色会偏红。

    2、实验中出现的问题

    (1)rgb文件中出现红点,yuv文件中出现蓝点(此图中还有色差错误下一标题解释) 原因:在转换RGB是没有进行数值判断,导致溢出。 原代码:                                                                                                                                                                      改正后:                                            (2)生成的yuv文件与原yuv文件存在色差,生成的yuv文件偏红 原因:公式写错了,rgb文件格式是以bgr的顺序存放的,而本人在编写代码时没有认真查看,把本应该是r的公式写到了b的位置,把b的公式写到了r处,导致产生了色差。 在这里温馨提示:编写代码时一定要认真仔细,不要犯这种低级错误,给后来查错添不必要的麻烦。 原代码:                                                                                                            改正后:                                   

    五、总结

    通过本次实验,我练习了rgb与yuv图片格式之间的转换,熟悉了VS的编程环境以及调试程序的过程;同时了解了yuv和rgb图像的格式和存储原理。
    转载请注明原文地址: https://ju.6miu.com/read-36535.html

    最新回复(0)