YUV和RGB的互转

YUV和RGB的转换

模拟信号
RGB转YUV

Y=0.299R+0.587G+0.114B
U=0.493(B-Y)=-0.147R-0.289G+0.436B
V=0.877(R-Y)=0.615R-0.515G-0.100B

YUV转RGB

R=Y+1.14V
G=Y-0.394U-0.581V
B=Y+2.032U

数字信号

数字信号中,为了便于处理,需要在量化前做归一化处理
Cb=0.564(B-Y)
Cr=0.713(V-Y)
8bit量化中,亮度信号上端留20级下端留16级作为保护带。
而在色度信号中上端15级下端16级,且色差信号进行归一处理后,电平范围为-0.5~0.5,故色差信号的零电平应对应第128级。

RGB转YCbCr

Y=((66R+129G+25B+128)>>8)+16
Cb=((-38R-74G+112B+128)>>8)+128
Cr=((112R-94G-18B+128)>>8)+128

YCbCr转RGB

R=1.164(Y-16)+1.596(Cr-128)
G=1.164(Y-16)-0.813(Cr-128)-0.392(Cb-128)
B=1.164(Y-16)+2.017(Cb-128)

色度格式

取样格式

常见色度取样格式有4:4:4,4:2:2,4:2:0,4:1:1
这次实验中选择了4:2:2格式

存储格式

先存所有的y,再存所有的u,最后存所有的v,之后进行下一帧

代码

head.h
  • 声明所用的函数
#ifndef HEAD_H
#define HEAD_H
#include<iostream>
#include<cstdio>
#include<fstream>

extern int rgb2yuv(char*, char*);
extern int yuv2rgb(char*, char*);
extern int check(char*, char*);
#endif HEAD_H
rgb2yuv.cpp
  • 定义将rgb转换为yuv的函数
#include"head.h"
using namespace std;

int rgb2yuv(char*pathin, char*pathout)
{
	unsigned char*buffer_1=new unsigned char[256*256*3];
	unsigned char*buffer_2 = new unsigned char[256*256];
	unsigned char*buffer_3 = new unsigned char[256 * 256];
	unsigned char*buffer_4 = new unsigned char[256 * 256];
	unsigned char*buffer_5 = new unsigned char[256 * 128+1];
	unsigned char*buffer_6 = new unsigned char[256 * 128+1];
	unsigned char y, u, v, r, g, b;
	ifstream in(pathin, ios::binary);
	ofstream out(pathout, ios::binary);
	if (!in.is_open()) { cout << "open failed" << endl; }
	in.read((char*)buffer_1, 256 * 256*3);
	int pos = 0,y_pos=0;
	while (pos<256*256*3)
	{		
		for (auto i : { &b,&g,&r }) { *i = buffer_1[pos++]; }
		y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
		u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
		v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
		buffer_2[y_pos] = y;
		buffer_3[y_pos] = u;
		buffer_4[y_pos] = v;
		y_pos++; 
	}
	int samp_pos = 0;
	for (int i=0; i < 256 * 256; i++)
	{
		buffer_5[samp_pos++] = (buffer_3[i] + buffer_3[++i])/2;
	}
	 samp_pos = 0;
	for (int i = 0; i < 256 * 256; i++)
	{
		buffer_6[samp_pos++] = (buffer_4[i] + buffer_4[++i])/2;
	}
	out.write((char*)buffer_2, 256 * 256);
	out.write((char*)buffer_5, 256 * 128);
	out.write((char*)buffer_6, 256 * 128);
	out.close();
	system("pause");
	return 0;
}
yuv2rgb.cpp
  • 定义将yuv转为rgb的函数
#include"head.h"
using namespace std;

int yuv2rgb(char*pathin, char*pathout)
{
	unsigned char*buffer_1=new unsigned char[3];
	unsigned char*y = new unsigned char[256*256];
	unsigned char*u = new unsigned char[256 * 256];
	unsigned char*v = new unsigned char[256 * 256];
	unsigned char*u_buf = new unsigned char[256 * 128];
	unsigned char*v_buf = new unsigned char[256 * 128];
	ifstream in(pathin, ios::binary);
	ofstream out(pathout, ios::binary);
	if (!in.is_open()) { cout << "open failed" << endl; }
	int pos = 0;
	in.read((char*)y, 256 * 256);
	in.read((char*)u_buf, 256 * 128);
	in.read((char*)v_buf, 256 * 128);
	for (int i = 0; i < 256 * 256; pos++)
	{
		u[i++] = u_buf[pos];
		u[i++] = u_buf[pos];
	}
	pos = 0;
	for (int i = 0; i < 256 * 256; pos++)
	{
		v[i++] = v_buf[pos];
		v[i++] = v_buf[pos];
	}
	pos = 0;
	unsigned char r, g, b;
	while (pos<256*256)
	{
		int n = 0;
		r = 1.164*(y[pos]-16) + 1.596*(v[pos]-128);
		g = 1.164*(y[pos]) - 0.392*(u[pos]-128) - 0.813*(v[pos]-128);
		b = 1.164*(y[pos]-16) + 2.017*(u[pos]-128);
		pos++;
		for (auto i : { b,g,r }) { buffer_1[n++]=i; }
		out.write((char*)buffer_1, 3);
	}
	in.close();
	out.close();
	system("pause");
	return 0;
}
check.cpp
  • 定义将转换回来的rgb文件与原文件比较并输出不相同数据个数的函数
#include"head.h"
using namespace std;
int check(char*path1, char*path2)
{
	ifstream in(path1, ios::binary);
	ifstream check(path2, ios::binary);
	unsigned char*buffer_1 = new unsigned char[3];
	unsigned char*buffer_2 = new unsigned char[3];
	int aggregate = 0;
	while (!in.eof() && !check.eof())
	{
		in.read((char*)buffer_1, 3);
		check.read((char*)buffer_2, 3);
		for (int i = 0; i < 3; i++)
		{
			if (!(buffer_1[i] == buffer_2[i]))
			{
				aggregate++;
				
			}
		}
	}
	in.close();
	check.close();
	cout << aggregate << endl;
	system("pause");
	return 0;
}
MAIN.cpp
  • 定义主函数
//
#include"stdafx.h"
#include"head.h"
using namespace std;
int main()
{
   char*path_in=new char[10];
   cin.getline(path_in, 20, '\n');
   char*path_out=new char[10];
   cin.getline(path_out, 20, '\n');
   char*path_check = new char[10];
   cin.getline(path_check, 20, '\n');

   rgb2yuv(path_in, path_out); 
   yuv2rgb(path_out,path_check);
   check(path_in, path_check);
   
   return 0;
   
}

输出结果如下
在这里插入图片描述
可见 有153981个数据不一样,大约是78.3%的数据
在这里插入图片描述
用yuv viewer打开输出的yuv文件如上

分析误差

  • 色度取样时会出现误差
  • rgb和yuv互转时量化会出现误差
  • 数据转换时会出现误差
发布了5 篇原创文章 · 获赞 0 · 访问量 203

猜你喜欢

转载自blog.csdn.net/m0_46340275/article/details/105175945