實驗一:
編寫RGB轉化爲YUV程序,重點掌握函數定義,部分查找表的初始化和調用,緩衝區分配。將得到的RGB文件轉換爲YUV文件,用YUV Viewer播放器觀看,驗證是否正確。
編寫將YUV轉換爲RGB的程序。將給定的實驗數據用該程序轉換爲RGB文件。並與原
RGB文件進行比較,如果有誤差,分析誤差來自何處。
之前寫過一版單純的文件與的文件的轉換,鏈接如下,此版文章在前文的基礎上進行了轉換公式的推導以及採樣的實現,若是隻關注兩種類型的轉換可以直接去不採樣版查看代碼及思路。
文章目錄
(一)YUV和RGB的轉換公式及文件存儲格式
以上公式是已經量化過的公式。
1.1 轉換公式推導
1.1.1 模擬信號的轉換公式
根據電視原理的知識,我們可以知道得到如下公式:
1.1.2 數字信號的轉換公式
歸一化
爲了便於處理,模擬信號轉換爲數字信號的時候需要進行歸一化處理,使得色差信號的動態範圍控制在之間。
歸一話之後得到公式:
由於上述的取值範圍在之間,所以需要引入的偏置。公式變爲:
亮度信號量化後碼電平分配
亮度信號量化後的碼電平分配如圖所示(圖源《數字電視廣播原理與應用》P36):
可見,亮度信號的峯值白電平對應碼電平235,消隱電平對應碼電平16,爲了預防信號變動造成過載,上端留20級、下端留16級作爲信號超越動態範圍的保護帶。其中碼電平0和255爲保護電平,是不允許出現在視頻數據流中的,碼字00和FF用於傳送同步信息。亮度信號動態範圍共佔220個量化級。
色差信號量化後碼電平分配
色差信號的碼電平分配如圖所示,圖源《數字電視廣播原理與應用》P37):
色差信號峯值的峯值白電平對應碼電平240,0電平對應碼電平16,爲了預防信號變動造成過載,上端留15級,下端留16級作爲信號超越動態範圍的保護帶。色差信號動態範圍共佔225個量化級。
碼電平數字表達式
亮度信號和色差信號量化以後取其最鄰近的整數作爲碼電平值,其數字化表達式爲:
將前面所推得的帶入上式,可得:
將式子寫成矩陣的形式:
令矩陣爲矩陣,則原式可轉化爲:
由於的數量級過於小,因此先將中的每個元素縮小爲原來的得到。則上式轉換爲:
將係數取整,可得下式:
1.2 文件的存儲格式
查閱資料可知,文件的存儲格式爲,文件的存儲格式爲先存全部的,再存全部的,最後存全部的。
(二)main函數的命令行參數
2.1 表示方法
一個程序的函數可以包含兩個參數:
- 第一個參數爲類型;
- 第二個參數爲字符串數組;
通常情況下,將第一個參數命名爲,第二個參數爲。由於字符串數組在函數頭中的聲明可以有兩種形式,所以函數也有兩種寫法。
-
函數寫法一:
int main(int argc, char** argv) { return 0; }
-
函數寫法二:
int main(int argc, char* argv[]) { return 0; }
2.2 使用方法
-
參數的含義:
int argc:表示字符串的數量。argc = 1 + 用戶輸入的字符串數目,argc的值由操作系統自動完成計算,程序員不需要對其進行賦值。
char argv[]*:存放的是多個字符串,字符串的形式如下:
argv[0] = 可執行文件的名稱。例如change.exe。(這個字符串不需要用戶輸入,與argc相同,操作系統可自動生成。
argv[1] = 字符串1
argv[2] = 字符串2
argv[3] = 字符串3
-
編程模式下如何進行參數輸入?
使用平臺爲,需要使用的文件爲,需要生成的文件爲,參數輸入的步驟如下圖流程所示:
1.打開上方任務欄調試界面的屬性窗口 | |
---|---|
2.選擇配置屬性中的調試 | |
3.按照要求修改命令參數 |
(三)彩色空間轉換(不採樣)代碼初步實現
由上述知識,可以輕易地進行彩色空間轉換的初步實現。代碼由頭文件和源文件組成。
解決方案資源管理器如下圖所示:
實驗代碼如下:
main.cpp
#include <iostream>
#include <cstdio>
#include <fstream>
#include "rgb2yuv.h"
#include "yuv2rgb.h"
using namespace std;
#define size 196608
#define usize 65536
#define vsize 131072
using namespace std;
int main(int argc, char** argv)
{
ifstream infile(argv[1],ios::binary);
ofstream outYUV(argv[2], ios::binary);
ofstream outRGB(argv[3], ios::binary);
if (!infile) { cout << "error to open file1!" << endl; }
if (!outYUV) { cout << "error to open file2" << endl; }
if (!outRGB) { cout << "error to open file3" << endl; }
unsigned char* in = new unsigned char[size];
unsigned char* YUV = new unsigned char[size];
unsigned char* RGB = new unsigned char[size];
infile.read((char*)in, size);
rgb2yuv(in,YUV,size, usize, vsize);//第一次轉換
yuv2rgb(YUV, RGB, usize, vsize);//第二次轉換
/*for (int i = 0; i < size; i++)
{
if (abs(in[i] - RGB[i]) > 5)
cout << "i=" << i << " in[" << i << "]=" << int(in[i]) << " RGB[" << i << "]=" << int(RGB[i]) << endl;
}*/
outYUV.write((char*)YUV, size);
outRGB.write((char*)RGB, size);
delete in;
delete YUV;
delete RGB;
infile.close();
outYUV.close();
outRGB.close();
return 0;
}
rgb2yuv.h
#pragma once
void rgb2yuv(unsigned char* rgb, unsigned char* yuv, int size,int usize,int vsize);
rgb2yuv.cpp
void rgb2yuv(unsigned char* rgb, unsigned char* yuv,int size,int usize,int vsize)
{
unsigned char r, g, b, y, u, v;
int j = 0;
for (int i = 0;i < size;)
{
b = *(rgb + i);
g = *(rgb + i + 1);
r = *(rgb + i + 2);
y = ((66 * r + 129 * g + 25 * b) >> 8) + 16;
u = ((-38 * r - 74 * g + 112 * b) >> 8) + 128;
v = ((112 * r - 94 * g - 18 * b) >> 8) + 128;
*(yuv + j) = y;
*(yuv + j + usize) = u;
*(yuv + j + vsize) = v;
i = i + 3;//每個rgb爲1組
j++;
}
}
yuv2rgb.h
#pragma once
void yuv2rgb(unsigned char* yuv, unsigned char* rgb,int usize,int vsize);
yuv2rgb.cpp
#pragma once
#include "yuv2rgb.h"
#include <iostream>
using namespace std;
void yuv2rgb(unsigned char* yuv, unsigned char* rgb,int usize,int vsize)
{
unsigned char r, g, b, y, u, v;
int j = 0;
for (int i = 0; i < usize; i++)
{
y = *(yuv + i);
u = *(yuv + i + usize);
v = *(yuv + i + vsize);
r = (298 * y + 411 * v - 57344) >> 8;
g = (298 * y - 101 * u - 211 * v + 34739) >> 8;
b = (298 * y + 519 * u - 71117) >> 8;
*(rgb + j) = b;
*(rgb + j + 1) = g;
*(rgb + j + 2) = r;
j = j + 3;
}
}
實驗結果
down.rgb | up.yuv | cho.rgb |
---|---|---|
其中,和使用打開的打開方式爲:
打開的圖像是倒置的圖像(由於圖像格式是倒着存儲的,所以圖像用方式打開時會倒)。上述表格中的圖片爲了便於分辨,已經用微信進行過旋轉,但是文件和文件之間依然有鏡像的翻轉,不過不影響觀看與比對。
使用打開的方式爲:
由三幅圖像的對比圖可知,的實驗成功完成,而的實驗有一點問題,轉出的圖像中有較多紅色的雜點。
(四)實驗錯誤原因分析及代碼修改
錯誤修改
推斷可得,在進行的轉換時,得到的三個數據可能超過了類型可以表示的範圍,即可能或者。
因此需要對文件進行適當的修正,的值都直接,的值都直接。
修改後的如下:
#pragma once
#include "yuv2rgb.h"
#include <iostream>
using namespace std;
void yuv2rgb(unsigned char* yuv, unsigned char* rgb,int usize,int vsize)
{
int r, g, b, y, u, v;
int j = 0;
for (int i = 0; i < usize; i++)
{
y = int(*(yuv + i));
u = int(*(yuv + i + usize));
v = int(*(yuv + i + vsize));
r = (298 * y + 411 * v - 57344) >> 8;
if (r > 255) { r = 255; }
if (r < 0) { r = 0; }
g = (298 * y - 101 * u - 211 * v + 34739) >> 8;
if (g > 255) { g = 255; }
if (g < 0) { g = 0; }
b = (298 * y + 519 * u - 71117) >> 8;
if (b > 255) { b = 255; }
if (b < 0) { b = 0; }
*(rgb + j) = unsigned char(b);
*(rgb + j + 1) = unsigned char(g);
*(rgb + j + 2) = unsigned char(r);
j = j + 3;
}
}
實驗結果
down.rgb | up.yuv | cho.rgb |
---|---|---|
至此,差不多完成了和兩個實驗。
(五)優化代碼(使用查找表的方法)
利用查找表,對代碼進行了優化。代碼由頭文件和源文件組成。
解決方案資源管理器如下圖所示:
main.cpp
#include <iostream>
#include <cstdio>
#include <fstream>
#include "yuvrgb.h"
using namespace std;
#define size 196608
#define usize 65536
#define vsize 131072
#define height 256
#define weight 256
//查找表初始化
int* RGBYUV298 = new int[256];
int* RGBYUV411 = new int[256];
int* RGBYUV101 = new int[256];
int* RGBYUV211 = new int[256];
int* RGBYUV519 = new int[256];
int* RGBYUV66 = new int[256];
int* RGBYUV129 = new int[256];
int* RGBYUV25 = new int[256];
int* RGBYUV38 = new int[256];
int* RGBYUV74 = new int[256];
int* RGBYUV112 = new int[256];
int* RGBYUV94 = new int[256];
int* RGBYUV18 = new int[256];
int main(int argc, char** argv)
{
initLookupTable();
ifstream infile(argv[1],ios::binary);
ofstream outYUV(argv[2], ios::binary);
ofstream outRGB(argv[3], ios::binary);
if (!infile) { cout << "error to open file1!" << endl; }
if (!outYUV) { cout << "error to open file2" << endl; }
if (!outRGB) { cout << "error to open file3" << endl; }
unsigned char* infi = new unsigned char[size];
unsigned char* YUVfi = new unsigned char[size];
unsigned char* RGBfi = new unsigned char[size];
infile.read((char*)infi, size);
rgb2yuv(infi, YUVfi, size, usize, vsize);
yuv2rgb(YUVfi, RGBfi, usize, vsize);
outYUV.write((char*)YUVfi, size);
outRGB.write((char*)RGBfi, size);
fileend(infi,YUVfi,RGBfi);
infile.close();
outYUV.close();
outRGB.close();
return 0;
}
yuvrgb.h
#pragma once
void yuv2rgb(unsigned char* yuv, unsigned char* rgb,int usize,int vsize);
void rgb2yuv(unsigned char* rgb, unsigned char* yuv, int size, int usize, int vsize);
void initLookupTable();
void fileend(unsigned char* infi, unsigned char* YUVfi, unsigned char* RGBfi);
yuvrgb.cpp
#pragma once
#include "yuvrgb.h"
#include <iostream>
using namespace std;
extern int* RGBYUV298;
extern int* RGBYUV411;
extern int* RGBYUV101;
extern int* RGBYUV211;
extern int* RGBYUV519;
extern int* RGBYUV66 ;
extern int* RGBYUV129;
extern int* RGBYUV25 ;
extern int* RGBYUV38 ;
extern int* RGBYUV74 ;
extern int* RGBYUV112;
extern int* RGBYUV94 ;
extern int* RGBYUV18 ;
void initLookupTable()
{
for (int i = 0; i < 256; i++)
{
RGBYUV298[i] = 298 * i;
RGBYUV411[i] = 411 * i;
RGBYUV101[i] = 101 * i;
RGBYUV211[i] = 211 * i;
RGBYUV519[i] = 519 * i;
RGBYUV66[i] = 66 * i;
RGBYUV129[i] = 129 * i;
RGBYUV25[i] = 25 * i;
RGBYUV38[i] = 38 * i;
RGBYUV74[i] = 74 * i;
RGBYUV112[i] = 112 * i;
RGBYUV94[i] = 94 * i;
RGBYUV18[i] = 18 * i;
}
}
void yuv2rgb(unsigned char* yuv, unsigned char* rgb,int usize,int vsize)
{
int r, g, b, y, u, v;
int j = 0;
for (int i = 0; i < usize; i++)
{
y = int(*(yuv + i));
u = int(*(yuv + i + usize));
v = int(*(yuv + i + vsize));
/*r = (298 * y + 411 * v - 57344) >> 8;*/
r = (RGBYUV298[y]+ RGBYUV411[v]-57344)>>8;
if (r > 255) { r = 255; }
if (r < 0) { r = 0; }
/*g = (298 * y - 101 * u - 211 * v + 34739) >> 8;*/
g = (RGBYUV298[y] - RGBYUV101[u] - RGBYUV211[v] + 34739) >> 8;
if (g > 255) { g = 255; }
if (g < 0) { g = 0; }
/*b = (298 * y + 519 * u - 71117) >> 8;*/
b = (RGBYUV298[y] + RGBYUV519[u] - 71117) >> 8;
if (b > 255) { b = 255; }
if (b < 0) { b = 0; }
*(rgb + j) = unsigned char(b);
*(rgb + j + 1) = unsigned char(g);
*(rgb + j + 2) = unsigned char(r);
j = j + 3;
}
}
void rgb2yuv(unsigned char* rgb, unsigned char* yuv, int size, int usize, int vsize)
{
int r, g, b, y, u, v;
int j = 0;
for (int i = 0; i < size;)
{
b = int(*(rgb + i));
g = int(*(rgb + i + 1));
r = int(*(rgb + i + 2));
/*y = ((66 * r + 129 * g + 25 * b) >> 8) + 16;*/
y = ((RGBYUV66[r] + RGBYUV129[g] + RGBYUV25[b]) >> 8) + 16;
/*u = ((-38 * r - 74 * g + 112 * b) >> 8) + 128;*/
u = ((-RGBYUV38[r] - RGBYUV74[g] + RGBYUV112[b]) >> 8) + 128;
/*v = ((112 * r - 94 * g - 18 * b) >> 8) + 128;*/
v = ((RGBYUV112[r] - RGBYUV94[g] - RGBYUV18[b]) >> 8) + 128;
/*if ((y > 255) || (u > 255) || (v > 255) || (y < 0) || (u < 0) || (v < 0))
{
cout << "y=" << y << "u=" << u << "v=" << v << endl;
}*/
*(yuv + j) = unsigned char(y);
*(yuv + j + usize) = unsigned char(u);
*(yuv + j + vsize) = unsigned char(v);
i = i + 3;//每個rgb爲1組
j++;
}
}
void fileend(unsigned char* infi, unsigned char* YUVfi, unsigned char* RGBfi)
{
delete infi;
delete YUVfi;
delete RGBfi;
delete RGBYUV298;
delete RGBYUV411;
delete RGBYUV101;
delete RGBYUV211;
delete RGBYUV519;
delete RGBYUV66;
delete RGBYUV129;
delete RGBYUV25;
delete RGBYUV38;
delete RGBYUV74;
delete RGBYUV112;
delete RGBYUV94;
delete RGBYUV18;
}
實驗結果
down.rgb | up.yuv | cho.rgb |
---|---|---|
至此,完成了4:4:4的文件與4:4:4的文件之間的轉換。
(六)彩色空間轉換(採樣)代碼實現
如圖所示是4:2:0的色度取樣格式。因此可以得到從4:4:4的文件轉換爲4:2:0的文件的思路,即保留原有的分量,信號和信號都是取奇數行的奇數點。所以在原有的代碼上稍加改動,按照上述思路,添加一個由4:4:4的文件得到4:2:0的文件的函數,可以實現從文件到文件的轉換。
關於從文件到文件的轉換,由於像素之間的相關性,可以想到,保留原有的分量,分量可以通過複製來得到缺失的分量,重新轉換成4:4:4的文件。按照上述思路,添加一個由4:2:0的文件得到4:4:4的文件的函數,可以實現從文件到文件的轉換。
實驗代碼如下:
main.cpp
#include <iostream>
#include <cstdio>
#include <fstream>
#include "yuvrgb.h"
using namespace std;
#define size 196608
#define csize 98304
#define usize 65536
#define vsize 131072
#define height 256
#define weight 256
//查找表初始化
int* RGBYUV298 = new int[256];
int* RGBYUV411 = new int[256];
int* RGBYUV101 = new int[256];
int* RGBYUV211 = new int[256];
int* RGBYUV519 = new int[256];
int* RGBYUV66 = new int[256];
int* RGBYUV129 = new int[256];
int* RGBYUV25 = new int[256];
int* RGBYUV38 = new int[256];
int* RGBYUV74 = new int[256];
int* RGBYUV112 = new int[256];
int* RGBYUV94 = new int[256];
int* RGBYUV18 = new int[256];
int main(int argc, char** argv)
{
initLookupTable();
ifstream infile(argv[1],ios::binary);
ofstream outYUV444(argv[2], ios::binary);
ofstream outYUV420(argv[3], ios::binary);
ofstream outYUV4442(argv[4], ios::binary);
ofstream outRGB(argv[5], ios::binary);
if (!infile) { cout << "error to open file1!" << endl; }
if (!outYUV444) { cout << "error to open file2" << endl; }
if (!outYUV420) { cout << "error to open file3" << endl; }
if (!outYUV4442) { cout << "error to open file4" << endl; }
if (!outRGB) { cout << "error to open file5" << endl; }
unsigned char* infi = new unsigned char[size];
unsigned char* YUV444fi = new unsigned char[size];
unsigned char* YUV420fi = new unsigned char[csize];
unsigned char* YUV4442fi = new unsigned char[size];
unsigned char* RGBfi = new unsigned char[size];
infile.read((char*)infi, size);
rgb2yuv(infi, YUV444fi, size, usize, vsize);
yuv444Tyuv420(YUV444fi,YUV420fi,size,weight);
yuv420Tyuv444(YUV420fi, YUV4442fi, size, weight);
yuv2rgb(YUV4442fi, RGBfi, usize, vsize);
outYUV444.write((char*)YUV444fi, size);
outYUV420.write((char*)YUV420fi, csize);
outYUV4442.write((char*)YUV4442fi, size);
outRGB.write((char*)RGBfi, csize);
fileend(infi,YUV444fi,YUV420fi,RGBfi);
infile.close();
outYUV444.close();
outYUV420.close();
outRGB.close();
return 0;
}
yuvrgb.h
#pragma once
void initLookupTable();
void yuv2rgb(unsigned char* yuv, unsigned char* rgb,int usize,int vsize);
void rgb2yuv(unsigned char* rgb, unsigned char* yuv, int size, int usize, int vsize);
void fileend(unsigned char* infi, unsigned char* YUV444fi, unsigned char* YUV420fi, unsigned char* RGBfi);
void yuv444Tyuv420(unsigned char* yuv444,unsigned char* yuv420,int size,int weight);
void yuv420Tyuv444(unsigned char* YUV420, unsigned char* YUV444, int size, int weight);
yuvrgb.cpp
#pragma once
#include "yuvrgb.h"
#include <iostream>
using namespace std;
extern int* RGBYUV298;
extern int* RGBYUV411;
extern int* RGBYUV101;
extern int* RGBYUV211;
extern int* RGBYUV519;
extern int* RGBYUV66 ;
extern int* RGBYUV129;
extern int* RGBYUV25 ;
extern int* RGBYUV38 ;
extern int* RGBYUV74 ;
extern int* RGBYUV112;
extern int* RGBYUV94 ;
extern int* RGBYUV18 ;
void initLookupTable()
{
for (int i = 0; i < 256; i++)
{
RGBYUV298[i] = 298 * i;
RGBYUV411[i] = 411 * i;
RGBYUV101[i] = 101 * i;
RGBYUV211[i] = 211 * i;
RGBYUV519[i] = 519 * i;
RGBYUV66[i] = 66 * i;
RGBYUV129[i] = 129 * i;
RGBYUV25[i] = 25 * i;
RGBYUV38[i] = 38 * i;
RGBYUV74[i] = 74 * i;
RGBYUV112[i] = 112 * i;
RGBYUV94[i] = 94 * i;
RGBYUV18[i] = 18 * i;
}
}
void yuv2rgb(unsigned char* yuv, unsigned char* rgb,int usize,int vsize)
{
int r, g, b, y, u, v;
int j = 0;
for (int i = 0; i < usize; i++)
{
y = int(*(yuv + i));
u = int(*(yuv + i + usize));
v = int(*(yuv + i + vsize));
r = (RGBYUV298[y]+ RGBYUV411[v]-57344)>>8;
if (r > 255) { r = 255; }
if (r < 0) { r = 0; }
g = (RGBYUV298[y] - RGBYUV101[u] - RGBYUV211[v] + 34739) >> 8;
if (g > 255) { g = 255; }
if (g < 0) { g = 0; }
b = (RGBYUV298[y] + RGBYUV519[u] - 71117) >> 8;
if (b > 255) { b = 255; }
if (b < 0) { b = 0; }
*(rgb + j) = unsigned char(b);
*(rgb + j + 1) = unsigned char(g);
*(rgb + j + 2) = unsigned char(r);
j = j + 3;
}
}
void rgb2yuv(unsigned char* rgb, unsigned char* yuv, int size, int usize, int vsize)
{
int r, g, b, y, u, v;
int j = 0;
for (int i = 0; i < size;)
{
b = int(*(rgb + i));
g = int(*(rgb + i + 1));
r = int(*(rgb + i + 2));
y = ((RGBYUV66[r] + RGBYUV129[g] + RGBYUV25[b]) >> 8) + 16;
u = ((-RGBYUV38[r] - RGBYUV74[g] + RGBYUV112[b]) >> 8) + 128;
v = ((RGBYUV112[r] - RGBYUV94[g] - RGBYUV18[b]) >> 8) + 128;
*(yuv + j) = unsigned char(y);
*(yuv + j + usize) = unsigned char(u);
*(yuv + j + vsize) = unsigned char(v);
i = i + 3;//每個rgb爲1組
j++;
}
}
void yuv444Tyuv420(unsigned char* yuv444, unsigned char* yuv420,int size,int weight)
{
int Ysize = size / 3;
int j = 0;
for (int i = 0; i < Ysize; i++)//Y分量的計算
{
*(yuv420 + j) = *(yuv444 + i);
j++;
}
for (int i = 0; i < Ysize; )//U分量的計算
{
if (i % 2 == 1)
{
i++;
continue;
}
if ((i) % (2 * weight) == 0)
{
i = i + weight;
continue;
}
*(yuv420 + j) = *(yuv444 + i + Ysize);
j++;
i++;
}
for (int i = 0; i < Ysize; )//U分量的計算
{
if (i % 2 == 1)
{
i++;
continue;
}
if ((i) % (2 * weight) == 0)
{
i = i + weight;
continue;
}
*(yuv420 + j) = *(yuv444 + i + Ysize + Ysize);
j++;
i++;
}
}
void yuv420Tyuv444(unsigned char* YUV420, unsigned char* YUV444, int size, int weight)
{
int Ysize = size / 3;
int j = 0;
for (int i = 0; i < Ysize; i++)//Y分量的計算
{
*(YUV444 + i) = *(YUV420 + j);
j++;
}
for (int i = 0; i < Ysize; )//U分量的計算
{
if (i % 2 == 1)
{
j = j - 1;
*(YUV444 + i + Ysize) = *(YUV420 + j);
i++;
j++;
continue;
}
if ((i) % (2 * weight) == 0)
{
j = j - weight/2;
*(YUV444 + i + Ysize) = *(YUV420 + j);
i++;
j++;
continue;
}
*(YUV444 + i + Ysize) = *(YUV420 + j);
j++;
i++;
}
for (int i = 0; i < Ysize; )//U分量的計算
{
if (i % 2 == 1)
{
j = j - 1;
*(YUV444 + i + Ysize + Ysize) = *(YUV420 + j);
i++;
j++;
continue;
}
if ((i) % (2 * weight) == 0)
{
j = j - weight/2;
*(YUV444 + i + Ysize + Ysize) = *(YUV420 + j);
i++;
j++;
continue;
}
*(YUV444 + i + Ysize + Ysize) = *(YUV420 + j);
j++;
i++;
}
}
void fileend(unsigned char* infi, unsigned char* YUV444fi,unsigned char* YUV420fi, unsigned char* RGBfi)
{
delete infi;
delete YUV444fi;
delete YUV420fi;
delete RGBfi;
delete RGBYUV298;
delete RGBYUV411;
delete RGBYUV101;
delete RGBYUV211;
delete RGBYUV519;
delete RGBYUV66;
delete RGBYUV129;
delete RGBYUV25;
delete RGBYUV38;
delete RGBYUV74;
delete RGBYUV112;
delete RGBYUV94;
delete RGBYUV18;
}
實驗結果
實驗結果有5幅圖,最開始的,轉換成4:4:4的,再轉換成4:2:0的,再轉成4:4:4的,再轉成。結果如下表:
down | 444 | 420 | 4442 | cho |
---|---|---|---|---|
至此,全部工作已完成。
(七)實驗誤差分析
誤差來源可能是下述原因:
- 文件和文件相互轉換的公式推導時,經過了多次量化和小數點的捨去,使得轉換公式本身便存在誤差。
- 在4:4:4取樣格式轉換爲4:2:0取樣格式時,捨去了較多的色差信號。
- 在4:2:0取樣格式轉換爲4:4:4取樣格式時,使用了同一點的像素值來代替缺失點的像素。
- 在文件轉換的過程中,產生了數據的溢出,並將溢出的點向上變爲0或者向下變爲255,也導致了誤差的出現。