YUVとRGB間の相互変換

YUVおよびRGB変換

アナログ信号
RGBからYUV

Y = 0.299R + 0.587G + 0.114B
U = 0.493 (BY)=-0.147R-0.289G + 0.436B
V = 0.877 (RY)= 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(BY)
Cr = 0.713(VY)
8ビット量子化では、輝度信号は上端に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;
   
}

出力結果は次のとおりです。
ここに画像の説明を挿入
異なるデータは153,981で、データの約78.3%です。
ここに画像の説明を挿入
上記のように、yuvビューアを使用して出力されたyuvファイルを開きます。

分析エラー

  • クロマのサンプリング時にエラーが発生する
  • rgbとyuvが交換されるときの量子化エラー
  • データ変換中にエラーが発生する
元の記事を5件公開 Likes0 訪問数203

おすすめ

転載: blog.csdn.net/m0_46340275/article/details/105175945