数据压缩 彩色空间转换
2017-03-07 19:10
141 查看
彩色空间转换
实验原理
YUV到RGB空间的转换公式由电视原理知识可知,数字视频系统中对色差信号的压缩公式为:
Cr=0.713(R−Y)
Cb=0.564(B−Y)
此时色差信号经过归一化处理,动态范围为-0.5-0.5,让色差零电平对应码电平128(8比特量化时),则有:
V=0.713(R−Y)+128
U=0.564(B−Y)+128
易推得YUV到RGB空间的转换公式为:
R=Y+1.4075(V−128)
G=Y−0.3455(U−128)−0.7169(V−128)
B=Y+1.779(U−128)
取样格式
YUV空间的取样格式为4:2:0,U、V两个色差信号的亮度信号取样频率的四分之一,在水平方向和垂直方向上的取样点数均为Y的一半。而RGB空间的取样格式为4:4:4,则需要对U、V分量做上采样,让水平方向和垂直方向上取样点数与Y一致。
存储方式与占用空间
YUV格式的视频将整帧图像的Y打包存储,依次再存整帧的U、V,然后再是下一帧的数据;YUV格式按4:2:0取样的视频所占空间大小为Width*Height*Frame*1.5(Width –宽、Height–高、Frame–帧数)。RGB格式的视频按每个像素B、G、R的顺序储存数据;所占空间大小为Width*Height*Frame*3。
YUV转换为RGB后颜色溢出的处理
经过上式计算,原来为整数的Y、U、V转换为浮点数R、G、B,由于RGB文件的颜色是8bit量化,则数值不在0-255范围内的颜色会出现溢出,显示错误。本实验采用了定义float型的中间变量存放计算RGB的直接结果,而后通过简单的判断防止颜色溢出。
带参数的主函数的参数输入
打开项目属性窗口,通过设置工作目录、命令参数完成主函数的参数输入。
YUV2RGB文件转换流程分析
程序初始化(打开两个文件、定义变量和缓冲区 等)读取YUV文件,抽取YUV数据写入缓冲区
调用YUV2RGB的函数实现YUV到RGB数据的转换
写RGB文件
程序收尾工作(关闭文件,释放缓冲区)
关键代码及其分析
分析部分写在代码注释中
YUVtoRGB.cpp
#include "stdlib.h" #include "YUVtoRGB.h" static float YUVRGB14075[256]; static float YUVRGB03455[256]; static float YUVRGB07169[256]; static float YUVRGB1779[256]; int YUV2RGB (int Width, int Height, void *rgb_out, void *y_in, void *u_in, void *v_in) { static int init_done = 0; long i, j, size; unsigned char *r, *g, *b; float rf, gf, bf;//中间变量,用来防止色彩溢出 unsigned char *y, *u, *v; unsigned char *y_buffer, *u_buffer, *v_buffer,*rgb_buffer; unsigned char *sub_u_buf, *sub_v_buf; if (init_done == 0) { InitLookupTable(); init_done = 1; } // check to s d2d0 ee if width and height are divisible by 2 if ((Width % 2) || (Height % 2)) return 1; size = Width * Height; y_buffer = (unsigned char *)y_in; u_buffer = (unsigned char *)u_in; v_buffer = (unsigned char *)v_in; rgb_buffer = (unsigned char *)rgb_out; sub_u_buf = (unsigned char *)malloc(Width*Height); sub_v_buf = (unsigned char *)malloc(Width*Height); //sub_u_buf、sub_v_buf用于存放宽高都上采样以后的U/V,便于计算RGB /************************上采样***********************/ for (i = 0; i < Height; i++) { for (j = 0; j < Width; j++) { *(sub_u_buf + i*Width + j) = *(u_buffer + (i / 2)*Width/2 + j / 2); *(sub_v_buf + i*Width + j) = *(v_buffer + (i / 2)*Width /2+ j / 2); } } /****************************************************/ b = rgb_buffer;//通过r/g/b三个指针改变rgb_buffer的内容值 y = y_buffer; u = sub_u_buf; v = sub_v_buf; for (i = 0; i < Height; i++) { for (j = 0; j < Width; j++) { g = b + 1;//RGB格式文件储存按照BGR的顺序 r = b + 2; rf= (*y + YUVRGB14075[*v]); gf = (*y - YUVRGB03455[*u] - YUVRGB07169[*v]); bf = (*y + YUVRGB1779[*u]); *r =(rf>0?(rf>255? 255:(unsigned char)rf):0); *g = (gf>0 ? (gf>255 ? 255 : (unsigned char)gf) : 0); *b = (bf>0 ? (bf>255 ? 255 : (unsigned char)bf) : 0); /*由YUV到RGB的转换公式可知,经过计算得到的RGB值都不是整数,由于计算 系数的精度,RGB值有可能出现超出0-255的范围。由于unsigned char型 数据占1字节,超出0-255的数值会溢出,发生彩色显示错误。例如256会变为 0。 可以采用一个float型中间变量(rf/bf/gf)来暂存由彩色转换公式计算得 来的RGB值,经过判断以后,再给unsigned char型的r/g/b进行赋值,大 于255则赋值为255,小于0则赋值为0,在0-255范围内的数值则进行强制类 型转换。*/ b += 3; y++; u++; v++; } } if (sub_u_buf != NULL) free(sub_u_buf); if (sub_v_buf != NULL) free(sub_v_buf); return 0; } 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++) YUVRGB1779[i] = (float)1.779 * (i-128); } /*提前计算彩色转换公式中的分量值。需要特别注意的是UV值需要提前 减128,也就是说,计算分量值时保证UV的范围在-128~127。*/
main.cpp
#include<stdio.h> #include<stdlib.h> #include<malloc.h> #include"YUVtoRGB.h" #define u_int8_t unsigned __int8 #define u_int unsigned __int32 #define u_int32_t unsigned __int32 //为了防止不同编程软件数据类型int的字节数不一致,利用define进行规定 int main(int argc,char ** argv) { u_int frameWidth = 352; u_int frameHeight = 240; int i; char *rgbFileName= NULL; char *yuvFileName= NULL; FILE *rgbFile=NULL; FILE *yuvFile=NULL; u_int8_t* rgbBUFFER = NULL; u_int8_t* yBUFFER = NULL; u_int8_t* uBUFFER= NULL; u_int8_t* vBUFFER = NULL; u_int32_t videoFramesWritten = 0; yuvFileName = argv[1]; rgbFileName = argv[2]; frameWidth = atoi(argv[3]); frameHeight = atoi(argv[4]); //argv[0]是缺省的,软件自动会装填Project当中的exe文件名 yuvFile = fopen(yuvFileName, "rb"); if (yuvFile == NULL) { printf("cannot find yuv file\n"); exit(1); } else { printf("The output yuv file is %s\n", yuvFileName); } rgbFile = fopen(rgbFileName, "wb"); if (rgbFile == NULL) { printf("cannot find rgb file\n"); exit(1); } else { printf("The input rgb file is %s\n", rgbFileName); } /* get an input buffer for a frame */ rgbBUFFER= (u_int8_t *)malloc(frameWidth * frameHeight * 3); /* get the output buffers for a frame */ yBUFFER= (u_int8_t *)malloc(frameWidth * frameHeight); uBUFFER= (u_int8_t *)malloc(frameWidth * frameHeight/4); vBUFFER= (u_int8_t *)malloc(frameWidth * frameHeight/4); if (rgbBUFFER == NULL || yBUFFER == NULL || uBUFFER == NULL || vBUFFER == NULL) { printf("no enought memory\n"); exit(1); } while(fread(yBUFFER,1,frameWidth*frameHeight,yuvFile) &&fread(uBUFFER,1,frameWidth*frameHeight/4,yuvFile) &&fread(vBUFFER,1,frameWidth*frameHeight/4,yuvFile)) /*当读入成功时fread函数返回实际读取的数据项个数,当整帧的YUV都能读 入时,进入while循环。由于文件指针自动向后移动到下一个未读字节,故该 程序也适用于视频文件,整段视频被读完fread函数返回0,则结束循环。*/ { if(YUV2RGB(frameWidth, frameHeight, rgbBUFFER, yBUFFER, uBUFFER, vBUFFER)) { printf("error"); return 0; } fwrite(rgbBUFFER, 1, frameWidth * frameHeight*3, rgbFile); printf("\r...%d", ++videoFramesWritten); } printf("\n%u %ux%u video frames written\n", videoFramesWritten, frameWidth, frameHeight); if(rgbFile!=NULL) fclose(rgbFile); if(yuvFile!=NULL) fclose(yuvFile); if(rgbBUFFER!=NULL) free(rgbBUFFER); if(yBUFFER!=NULL) free(yBUFFER); if(uBUFFER!=NULL) free(uBUFFER); if(vBUFFER!=NULL) free(vBUFFER); return(0); }
实验结果及其分析
将转换得的RGB文件输入已有的RGB2YUV程序,得到新的YUV文件,用YUVplayer打开新的YUV文件查看结果。down.yuv
由于计算系数精度、强制类型转换等带来的误差,经过彩色空间转换的YUV值会存在些许差异,但从画面、数据上看,这个差异都不算太明显。
没有采用中间变量,彩色溢出的情况
下面给出另外三个YUV视频文件进行彩色空间转换的结果,佐证该程序是正确的。
akiyo.yuv
src01.yuv
src04.yuv
相关文章推荐
- RGB和YUV 多媒体编程基础详细介绍
- JavaScript实现把rgb颜色转换成16进制颜色的方法
- JavaScript 十六进制RGB色码转换器
- RGB 加成色 说明
- php颜色转换函数hex-rgb(将十六进制格式转成十进制格式)
- php Imagick获取图片RGB颜色值
- PHP实现将颜色hex值转换成rgb的方法
- javascript实现十六进制颜色值(HEX)和RGB格式相互转换
- jquery获取css的color值返回RGB的方法
- 每周总结20130814——Android NDK环境的搭建和使用,YUV420SP格式图像的处理
- PHP实现将颜色hex值转换成rgb的方法
- ps做出RGB三原色的光学红绿蓝叠加效果
- RGB与HSI颜色空间互换函数(matlab)
- RGB/YUV的来历及其相互转换
- RGB、YUY2、YUYV、YVYU、UYVY与AYUV(转)
- RGB和RGBA之间的转换
- Android 常用色彩及其RGB值列表
- CSS中background-color属性(一)
- python3使用Image库由rgb值生成jpg图片
- RGB格式详解(三)---RGB像素格式