一、实验目的
- 进一步理解彩色空间的概念并掌握不同彩色空间转换的基本方程。
- 通过逐步设计程序,掌握编程细节:如查找表的设计,内存分配,对 U 和 V 信号进行下采样,文件读写过程等。掌握程序调试的基本方法。
- 编写RGB转化为YUV程序,重点掌握函数定义,部分查找表的初始化和调用,缓冲区分配。将得到的RGB文件转换为YUV文件,用YUV Viewer播放器观看,验证是否正确。
- 编写将YUV转换为RGB的程序。将给定的实验数据用该程序转换为RGB文件。并与原RGB文件进行比较,如果有误差,分析误差来自何处。
二、实验内容
(1)YUV 与 RGB 空间的相互转换
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.1684 R-0.3316 G+0.5 B
V=0.5 R-0.4187 G-0.0813 B
为使色差零电平对应码电平128,引入128的偏置,使变化范围在【0,255】。
最后得到Y、U、V三者计算公式为:
Y=0.2990 R+0.5870 G+0.1140 B
U=-0.1684 R-0.3316 G+0.5 B+128
V=0.5 R-0.4187 G-0.0813 B+128
YUV——>RGB
由上述公式反解可以得到:
(注意 UV 要各减128才能在对应的范围)
R=Y+1.4075(V-128);
G=Y-0.3455(U-128)-0.7169(V-128);
B=Y+1.779(U-128);
(2) 码电平分配及数字表达式
- 亮电平信号量化后码电平分配
在对分量信号进行8比特均匀量化时,共分为256个等间隔的量化级。为了防止信号变动造成过载,在256级上端留20级,下端留16级作为信号超越动态范围的保护带。 - 色差信号量化后码电平分配
色差信号经过归一化处理后,动态范围为-0.5-0.5,让色差零电平对应码电平128,色差信号总共占225个量化级。在256级上端留15级,下端留16级作为信号超越动态范围
的保护带。
(3)色度格式
4:2:0格式是指色差信号U,V的取样频率为亮度信号取样频率的四分之一,在水平方向和垂直方向上的取样点数均为Y的一半。
三、实验思路
RGB to YUV
对UV数据进行下采样
YUV to RGB
对UV数据进行上采样
四、示例实验代码
1.示例所给的代码关键
1)定义字节长度
#define u_int8_t unsigned __int8
#define u_int unsigned __int32
#define u_int32_t unsigned __int32
#define FALSE false
#define TRUE true
2)所有用到的计算结果的声明
static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];
3)所有用到的计算结果的计算,即形成查找表
(查找表虽然浪费一定空间,但是每次运算直接查找即可,无需每次都算一编,提高效率)
void InitLookupTable()
{
int i;
for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}
2.运行结果
- 原本的 rgb 文件
- 程序运行后生成的 yuv 文件
五、自己编写的实验代码
1.RGB to YUV
- rgb2yuv_ziji.h
int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out);
void InitLookupTable();
- main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include<math.h>
#include "rgb2yuv_ziji.h"
int main(int argc, char** argv)
{
int frameWidth ;
int frameHeight ;
char* rgbFileName = NULL;
char* yuvFileName = NULL;
FILE* rgbFile = NULL;
FILE* yuvFile = NULL;
unsigned char* rgbBuf = NULL;
unsigned char* yBuf = NULL;
unsigned char* uBuf = NULL;
unsigned char* vBuf = NULL;
//
rgbFileName = argv[1];
yuvFileName = argv[2];
frameWidth = atoi(argv[3]);
frameHeight = atoi(argv[4]);
//打开RGB文件
fopen_s(&rgbFile,rgbFileName,"rb");
if (rgbFile == NULL)
{
printf("cannot find rgb file\n");
exit(1);
}
else
{
printf("The input rgb file is %s\n", rgbFileName);
}
//打开yuv文件
fopen_s(&yuvFile,yuvFileName,"wb");
if (yuvFile == NULL)
{
printf("cannot find y