实验内容: 掌握彩色空间转换的基本思想及转换公式; 用所熟悉的程序语言编写RGB转YUV、YUV转换为RGB的程序
YUV与RGB的互转公式
RGB转YUV
小数型
Y=0.2990R+0.5870G+0.1140B;
U=-0.1684R-0.3316G+0.5000B+128;
V=0.5000R-0.4184G-0.0813B+128;
整数型
Y=((66R+129G+25B)>>8)+16;
U=(-38R-74G+112B)>>8+128;
V=(112R-94G-18B)>>8+128;
YUV转RGB
小数型
R=Y+1.4074(V-128);
G=Y-103455(U-128);
B=Y+1.779(U-128);
整数型
R=(298Y+411V-57344)>>8;
G=(298Y-101U-211V+34739)>>8;
B=(298Y+519U-71117)>>8;
代码实现
main.cpp
#include <iostream>
#include<fstream>
#include<stdlib.h>
#include <stdio.h>
#include "rgb2yuv.h"
#include"yuv2rgb.h"
using namespace std;
#define SIZE 65536
int main()
{
//定义缓冲区
unsigned char* source_Buffer=new unsigned char[SIZE * 3];
unsigned char* yuv_Buffer= new unsigned char[SIZE*3];
unsigned char* rgb_Buffer= new unsigned char[SIZE*3];
//打开文件
ifstream source_file("down.rgb", ios::binary);
if (!source_file)
{
cout << "Cannot open source file!" << endl;
abort();
}
ofstream yuv_file("down.yuv", ios::binary);
if (!yuv_file)
{
cout << "Cannot open yuv file!" << endl;
abort();
}
ofstream rgb_file("restore.rgb", ios::binary);
if (!rgb_file)
{
cout << "Cannot restore rgb file!" << endl;
abort();
}
//读文件
source_file.read((char*)source_Buffer, SIZE * 3);
//实现RGB转YUV并写出
RGB2YUV(SIZE, source_Buffer, yuv_Buffer);
yuv_file.write((char*)yuv_Buffer, SIZE * 3);
//实现YUV转RGB并写出
YUV2RGB(SIZE, yuv_Buffer, rgb_Buffer);
rgb_file.write((char*)rgb_Buffer, SIZE * 3);
//关闭文件
source_file.close();
yuv_file.close();
rgb_file.close();
}
RGB to YUV的实现:
定义unsigned char型指针*r,*g,*b
unsigned char* r, * g, * b;
b=rgb;
获取rgb的首地址后,利用循环依次获取r、g、b的值并代入转换公式计算:
for (int i = 0; i < size; i++)
{
g = b + 1;
r = b + 2;
y = 0.2990 * r + 0.5870 * g + 0.1140 * b;
u = -0.1684 * r - 0.3316 * g + 0.5000 * b + 128;
v = 0.5000 * r + 0.4187 * g + 0.0813 * b + 128;
*(yuv + i) = y;
*(yuv + i + usize) = u;
*(yuv + i + vsize) = v;
b += 3;
}
用部分查找表法优化代码:
因为RGB转YUV用的是小数型转换公式,所以定义的是static float型数组;YUV转RGB时用的是整数型公式,要相应地改成static int型数组。
static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256],RGBYUV01684[256], RGBYUV03316[256],RGBYUV04187[256], RGBYUV00813[256];
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;
}
最终的rgb2yuv.cpp
#include "stdlib.h"
#include"rgb2yuv.h"
static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];
void RGB2YUV(int size, unsigned char* rgb, unsigned char* yuv)
{
static int init_done;
int usize = size;
int vsize = size * 2;
unsigned char* r, * g, * b;
/*unsigned char* y = new unsigned char[size];
unsigned char* u = new unsigned char[size];
unsigned char* v = new unsigned char[size];*/
int y, u, v;
if (init_done == 0)
{
InitLookupTable();
init_done = 1;
}
//RGB YUV转换
b = rgb;
for (int i = 0; i < size; i++)
{
g = b + 1;
r = b + 2;
y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
u = (unsigned char)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);
v = (unsigned char)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);//部分查找表法
/*y = 0.2990 * r + 0.5870 * g + 0.1140 * b;
u = -0.1684 * r - 0.3316 * g + 0.5000 * b + 128;
v = 0.5000 * r + 0.4187 * g + 0.0813 * b + 128;*/
*(yuv + i) = y;
*(yuv + i + usize) = u;
*(yuv + i + vsize) = v;
b += 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;
}
头文件rgb2yuv.h中对函数的声明:
void RGB2YUV(int size, unsigned char* rgb, unsigned char* yuv);
void InitLookupTable();
YUV to RGB的实现
思路与RGB2YUV一样,但需要对溢出部分进行修正
if (r > 255){ r = 255;}
else if (r < 0){r = 0;}
if (g > 255){ g = 255;}
else if (g < 0){g = 0;}
if (b > 255){ b = 255;}
else if (b < 0){b = 0;}
最终yuv2rgb.cpp
#include "stdlib.h"
#include"yuv2rgb.h"
static int YUVRGB298[256], YUVRGB411[256], YUVRGB101[256],YUVRGB519[256],YUVRGB211[256];
void YUV2RGB(int size, unsigned char* yuv, unsigned char* rgb)
{
static int init_done;
int usize = size;
int vsize = size * 2;
unsigned char* y, * u, * v;
/*unsigned char* r = new unsigned char[size];
unsigned char* g = new unsigned char[size];
unsigned char* b = new unsigned char[size];*/
int r, g, b;
//int y, u, v;
if (init_done == 0)
{
LookupTable();
init_done = 1;
}
y = yuv;
for (int i = 0; i < usize; i++)
{
u = y + usize;
v = y + vsize;
r = (YUVRGB298[*y] + YUVRGB411[*v] - 57344) >> 8;
if (r > 2){ r = 255;}
else if (r < 0){r = 0;}
g = (YUVRGB298[*y] - YUVRGB101[*u] - YUVRGB211[*v] + 34739) >> 8;
if (g > 255){g = 255;}
else if (g < 0){g = 0;}
b = (YUVRGB298[*y] + YUVRGB519[*u] - 71117) >> 8;
if (b > 255){b = 255;}
else if (b < 0){b = 0;}
/*r[i] = *y + (float)1.4075 * (*v - 128);
g[i] = *y - (float)0.3455 * (*u - 128) - (float)0.7169 * (*v - 128);
b[i] = *y + (float)1.779 - (*u - 128);*/
*(rgb + i) = b;
*(rgb + i + 1) = g;
*(rgb + i + 2) = r;
y ++;
}
}
void LookupTable()
{
int i;
for (i = 0; i < 256; i++) YUVRGB298[i] = 298 * i;
for (i = 0; i < 256; i++) YUVRGB411[i] = 411 * i;
for (i = 0; i < 256; i++) YUVRGB101[i] = 101 * i;
for (i = 0; i < 256; i++) YUVRGB519[i] = 519 * i;
for (i = 0; i < 256; i++) YUVRGB211[i] = 211 * i;
}
头文件yuv2rgb.h中对函数的声明:
void YUV2RGB(int size, unsigned char* rgb, unsigned char* yuv);
void LookupTable();
实验结果
从左向右一次为原图down.rgb、RGB转YUV的down.yuv、YUV转RGB的restore.rgb