Mutual conversion between YUV and RGB

YUV and RGB conversion

Analog signal
RGB to 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 to RGB

R = Y + 1.14V
G = Y-0.394U-0.581V
B = Y + 2,032U

Digital signal

In the digital signal, in order to facilitate processing, it needs to be normalized before quantization.
Cb = 0.564 (BY)
Cr = 0.713 (VY) In
8-bit quantization, the brightness signal has 20 levels at the upper end and 16 levels at the lower end as guard bands.
In the chrominance signal, the upper 15 levels and the lower 16 levels, and after the color difference signal is normalized, the level range is -0.5 ~ 0.5, so the zero level of the color difference signal should correspond to the 128th level.

RGB to YCbCr

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

YCbCr to 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)

Chroma format

Sampling format

Common chroma sampling formats are 4: 4: 4, 4: 2: 2, 4: 2: 0, 4: 1: 1.
4: 2: 2 format was selected in this experiment

Storage format

Store all y first, then all u, and finally all v, then proceed to the next frame

Code

head.h
  • Declare the function used
#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
  • Define a function to convert rgb to 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
  • Define a function to convert yuv to 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
  • Define a function that compares the converted rgb file with the original file and outputs a different number of data
#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
  • Define the main function
//
#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;
   
}

The output results are as follows.
Insert picture description here
There are 153,981 data that are different, about 78.3% of the data.
Insert picture description here
Use the yuv viewer to open the output yuv file as above

Analysis error

  • Errors occur when sampling chroma
  • Quantization errors when rgb and yuv are interchanged
  • Errors occur during data conversion
Published 5 original articles · Likes0 · Visits 203

Guess you like

Origin blog.csdn.net/m0_46340275/article/details/105175945