数据压缩原理实验1_实验报告
2017-03-19 22:25
417 查看
数据压缩原理实验1_彩色空间转换实验(yuv转rgb)
一、实验原理(1)RGB转YUV
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)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,因此在代码中真正的RGB转换公式如下:
R=Y+1.1402*(V-128)
G=Y-0.34414*(U-128)-0.71414*(V-128)
B=Y+1.772*(U-128)
(3)YUV文件到RGB文件的转换
4:2:0格式是指色差信号U,V的取样频率为亮度信号取样频率的四分之一,在水平方向和垂直方向上的取样点数均为Y的一半。
在文件存储中,RGB文件存储方式是每一个像素点都按照B、G、R的顺序进行存储,每一帧占用空间为width * height * 3个字节的空间。YUV文件存储方式为每一帧的YUV分开存储,先存Y,占用的空间为width * height,之后是U和V,所占用的空间分别为width * height /4。
要生成的RGB文件的取样格式为4:4:4,所以进行yuv到rgb的转换时,对给定的Y保持不变,对U和V进行上采样,使其可与RGB的存储空间相同。
二、实验流程分析
1.定义变量,设置参数,打开两个文件,申请缓冲区
2.读入YUV文件,抽取YUV数据写入缓冲区
3.将U、V块分别进行上采样,使其与Y块的大小相同
4.将4:4:4的Y、U、V通过转换公式计算得到R、G、B值并写出RGB文件
5.关闭文件,释放缓冲区
三、关键代码及分析
1、main2.cpp文件代码:
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include "yuv2rgb.h" #define u_int8_t unsigned __int8 #define u_int unsigned __int32 #define u_int32_t unsigned __int32 #define FALSE false #define TRUE true /* * yuv2rgb * required arg1 should be the input RAW RGB24 file * required arg2 should be the output RAW YUV12 file */ int main(int argc, char** argv) { /* variables controlable from command line */ u_int frameWidth = 352; /* --width=<uint> 帧宽 */ u_int frameHeight = 240; /* --height=<uint> 帧高 */ bool flip = TRUE; /* --flip */ unsigned int i; /* internal variables */ char* yuvFileName = NULL; char* rgbFileName = NULL; FILE* yuvFile = NULL; FILE* rgbFile = NULL; u_int8_t* yuvBuf = NULL; u_int8_t* rgbBuf = NULL; u_int32_t videoFramesWritten = 0; /* begin process command line */ /* point to the specified file names */ yuvFileName = argv[1]; //rgb、yuv文件名(down.rgb down.yuv )和宽高(256、256)被赋值 rgbFileName = argv[2]; frameWidth = atoi(argv[3]); frameHeight = atoi(argv[4]); /* 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); } /* get the input buffer for a frame 申请内存空间 */ //因为色度格式是4:2:0,所以u、v都是每四个像素取一个,所以存储大小是一帧图像的1.5倍 yuvBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 1.5); /* get an output buffer for a frame */ //每个像素有rgb三个分量,所以是3倍 rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3); if (rgbBuf == NULL || yuvBuf == NULL ) //判断buffer是否已满 { printf("no enought memory\n"); exit(1); } //buffer:要读/写的数据块地址,size :要读/写的每个数据项的字节数 ,count :要读/写的数据项数量,fp :文件指针 //读入yuv文件,存在内存区,直到文件结束 while (fread(yuvBuf, 1, frameWidth * frameHeight * 1.5, yuvFile)) { if(YUV2RGB(frameWidth, frameHeight, yuvBuf, rgbBuf, flip)) //判断函数是否运行成功 { printf("error"); return 0; } fwrite(rgbBuf,1,frameWidth * frameHeight*3,rgbFile); printf("\r...%d", ++videoFramesWritten); // \r按回车换行 } printf("\n%u %ux%u video frames written\n", videoFramesWritten, frameWidth, frameHeight); // \n自动换行 /* cleanup 关闭文件,释放缓存区*/ if (rgbFile != NULL) fclose(rgbFile); if (yuvFile != NULL) fclose(yuvFile); if (rgbBuf != NULL) free(rgbBuf); if (yuvBuf != NULL) free(yuvBuf); return(0); }
2、
4000
yuv2rgb.cpp文件代码:
/************************************************************************** * * rgb2yuv.c, 24-bit RGB bitmap to YUV converter * * Copyright (C) 2001 Project Mayo * * Adam Li * * DivX Advance Research Center <darc@projectmayo.com> * **************************************************************************/ /* This file contains YUV to RGB transformation functions. */ /* changetime 2017.3.18 */ #include "stdlib.h" #include "yuv2rgb.h" static float /*YUVRGB[256],*/ YUVRGB1402[256]; static float YUVRGB034414[256], YUVRGB071414[256]; static float YUVRGB1772[256]; int YUV2RGB (int x_dim, int y_dim, void *yuv_in, void *rgb_out, int flip)//宽、高、yuvBuf、rgbBuf、 flip { static int init_done = 0; long i, j, size; unsigned char *r, *g, *b; //用于分别指向输出的rgb文件中的R、G、B三个部分 unsigned char *y, *u, *v; //用于分别指向读入的yuv文件中的Y、U、V三个部分 unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv; //用于UV上采样的中间指针 /* unsigned char *y_buffer, *u_buffer, *v_buffer; */ unsigned char *rgb_buffer; //用于寄存输出rgb文件的缓冲区 unsigned char *sub_u_buf, *sub_v_buf; //用于寄存UV上采样后文件的缓冲区 float rk, gk, bk; //用于判断数据是否溢出的中间变量 if (init_done == 0) { InitLookupTable(); init_done = 1; } // check to see if x_dim and y_dim are divisible by 2 if ((x_dim % 2) || (y_dim % 2)) return 1; size = x_dim * y_dim; //计算得到一帧图像的大小,用于确定之后开辟缓冲区的大小 // allocate memory rgb_buffer = (unsigned char *)rgb_out; //UV上采样后,变成444格式,大小和Y所占大小一样 sub_u_buf = (unsigned char *)malloc(size * sizeof(unsigned char)); sub_v_buf = (unsigned char *)malloc(size * sizeof(unsigned char)); //用yuv文件中y,u,v三个数据分别赋值。 y = (unsigned char *)yuv_in; //yuv文件中先存储y数据,然后是u,最后是v u = y +size; v = y +size +size/4; // u,v上采样 for (i = 0; i < y_dim / 2; i++) { pu1 = sub_u_buf + 2 * i * x_dim; pu2 = sub_u_buf + (2 * i + 1) * x_dim; pv1 = sub_v_buf + 2 * i * x_dim; pv2 = sub_v_buf + (2 * i + 1) * x_dim; psu = u + i * x_dim / 2; //psu指向输入u文件中的每行第一个数据 psv = v + i * x_dim / 2; //psv指向输入v文件中的每行第一个数据 for (j = 0; j < x_dim / 2; j++) { *pu1 = *psu; *pu2 = *psu; pu1++; pu2++; *pu1 = *psu; *pu2 = *psu; *pv1 = *psv; *pv2 = *psv; pv1++; pv2++; *pv1 = *psv; *pv2 = *psv; pu1++; pu2++; pv1++; pv2++; psu++; psv++; } } //yuv转rgb b = rgb_buffer; //rgb数据倒序穿插存储 g = b + 1; r = b + 2; for (i = 0; i < size; i++) { //bk,gk,rk 为中间变量,用于判断是否有数据溢出,将数据控制在0-255之间 bk = (*y + YUVRGB1772[*sub_u_buf ]); gk = (*y - YUVRGB034414[*sub_u_buf ] - YUVRGB071414[*sub_v_buf ]); rk = (*y + YUVRGB1402[*sub_v_buf ]); if(bk>0 ) { if(bk>255) *b=255; else *b=(unsigned char)bk; } else *b=0; /* *b = (bk>0 ? (bk>255 ? 255 : (unsigned char)bk) : 0); */ *g = (gk>0 ? (gk>255 ? 255 : (unsigned char)gk) : 0); //条件运算符 *r = (rk>0 ? (rk>255 ? 255 : (unsigned char)rk) : 0); b += 3; g += 3; r += 3; y++; sub_u_buf++; sub_v_buf++; } //啊啊啊啊,要释放sub_u_buf,sub_v_buf指向的两个缓存空间,必须要把指针指到空间的开头,之前的循环,指针指在了缓存空间最后的数的下一个!!! sub_u_buf -= size; sub_v_buf -= size; if (sub_u_buf) free(sub_u_buf); if (sub_v_buf) free(sub_v_buf); /* if (rgb_buffer) free(rgb_buffer); */ return 0; } void InitLookupTable() { int i; for (i = 0; i < 256; i++) YUVRGB1402[i] = (float)1.402 * (i-128); for (i = 0; i < 256; i++) YUVRGB034414[i] = (float)0.34414 * (i-128); for (i = 0; i < 256; i++) YUVRGB071414[i] = (float)0.71414 * (i-128); for (i = 0; i < 256; i++) YUVRGB1772[i] = (float)1.772 * (i-128); }
3、yuv2rgb.h文件代码:
#ifndef YUV2RGB_H_ #define YUV2RGB_H_ int YUV2RGB (int x_dim, int y_dim, void *yuv_in, void *rgb_out, int flip); void InitLookupTable(); #endif
四、实验结果及分析
1、程序运行成功后,会跳出如下对话框
用yuv播放器打开原始yuv文件(左)和转换后的yuv文件(右)
(1)
(2)
(3)
(4)
2、错误及分析
(1)yuv文件中先存储完y的所有数据,然后是u,最后是v。
rgb文件中是按照b g r 的顺序穿插存储。
(2)要有bk,gk,rk中间变量,以将转换后的rgb数据控制在[0~255]范围内。(小于0则等于0,大于255则等于255)
(3)释放缓存空间要把指向空间的指针指在空间的第一个数据。
(4)yuv2rgb.cpp文件中的指针*rgb_buffer是指向main2.cpp文件中的空间 rgbBuf ,所以释放空间的操作应在main2.cpp文件中进行。
五、结论
本次实验主要是进行了RGB与YUV文件之间的转换,帮助理解了彩色空间的概念并掌握了不同彩色空间转换的基本方程,加深了对数据类型转换、指针和缓冲区联系的认识。
相关文章推荐
- 数据压缩原理实验5_实验报告
- 数据压缩原理实验2_实验报告
- 数据压缩原理与应用 图像文件的读写和转换(BMP2YUV)实验报告
- 数据压缩原理实验4_实验报告
- 数据压缩原理实验6_实验报告
- 数据压缩原理与应用之彩色空间转换 实验报告1
- 数据压缩原理实验3_实验报告
- 数据压缩实验二:bmp转yuv格式实验报告
- 数据压缩原理 实验二 图像文件的读写和转换
- 数据压缩原理实验6_MPEG音频编码
- 数据压缩原理 实验六 MPEG音频编码
- 数据压缩原理 实验五 JPEG原理分析及JPEG解码器的调试
- 数据压缩原理实验2_BMP2YUV文件转换
- 数据压缩原理实验5_JPEG编解码原理及代码分析
- 数据压缩原理实验1_彩色空间转换实验YUVtoRGB
- 数据压缩第二次实验报告——用C语言实现bmp to yuv的图片格式转化
- 数据压缩第一次实验报告(rgb与yuv的转换)
- 数据压缩原理 实验四 DPCM压缩系统的实现和分析
- 数据压缩实验一实验报告
- 数据压缩原理 实验三 Huffman编解码算法实现与压缩效率分析