Data compression (5)-color space conversion (full version) (2024)

experiment one:

  • Write RGB to YUV program, focus on function definition, initialization and calling of some lookup tables, buffer allocation. Convert the obtained RGB file to YUV file and watch it with YUV Viewer player to verify whether it is correct.

  • Write a program to convert YUV to RGB. Use this program to convert the given experimental data into RGB files. And with the original

    RGB files are compared, and if there are errors, analyze where the errors come from.

  I wrote a simple version before4444:4:4444ofRGBRGBRGBFile and4:4:44:4:44:4:4ofYUVYUVYUVFor file conversion, the link is as follows. This version of the article derives the conversion formula and the realization of sampling based on the previous article. If you only focus on two types of conversion, you can go directly to the non-sampling version to view the code and ideas.

Data compression (four)-color space conversion (non-sampling version)

Article Directory

  • (1) Conversion formula and file storage format of YUV and RGB
    • 1.1 Derivation of conversion formula
      • 1.1.1 Conversion formula of analog signal
      • 1.1.2 Conversion formula of digital signal
        • Normalized
        • Code level distribution after luminance signal quantization
        • Code level distribution after color difference signal quantization
        • Code level digital expression
    • 1.2 File storage format
  • (Two) the command line parameters of the main function
    • 2.1 Representation
    • 2.2 How to use
  • (3) Initial realization of color space conversion (no sampling) code
    • main.cpp
    • rgb2yuv.h
    • rgb2yuv.cpp
    • yuv2rgb.h
    • yuv2rgb.cpp
    • Experimental results
  • (4) Analysis of the causes of experimental errors and code modification
    • Error correction
    • Experimental results
  • (5) Optimize the code (using the lookup table method)
    • main.cpp
    • yuvrgb.h
    • yuvrgb.cpp
    • Experimental results
  • (6) Color space conversion (sampling) code implementation
    • main.cpp
    • yuvrgb.h
    • yuvrgb.cpp
    • Experimental results
  • (7) Analysis of experimental error

R=(298×Y+411×V57376)>>8G=(298×Y101×U211×V+35168)>>8B=(298×Y+519×U71200)>>8Y=(66×R+129×G+25×B)>>8+16U=(38×R74×G+112×B)>>8+128V=(112×R94×G18×B)>>8+128\begin{aligned} &R=(298\times Y+411\times V-57376)>>8\\ &G=(298\times Y-101\times U-211\times V+35168)>>8\\ &B=(298\times Y+519\times U-71200)>>8\\ &Y=(66\times R+129\times G+25\times B)>>8+16\\ &U=(-38\times R-74\times G+112\times B)>>8+128\\ &V=(112\times R-94\times G-18\times B)>>8+128 \end{aligned}R=(298×Y+411×V57376)>>8G=(298×Y101×U211×V+35168)>>8B=(298×Y+519×U71200)>>8Y=(66×R+129×G+25×B)>>8+16U=(38×R74×G+112×B)>>8+128V=(112×R94×G18×B)>>8+128

  The above formula is already quantified.

1.1 Derivation of conversion formula

1.1.1 Conversion formula of analog signal

  According to the knowledge of TV principles, we can know the following formula:
Y=0.2990×R+0.5870×G+0.1140×BU=BY=0.2990×R0.5870×G+0.8860×BV=RY=0.7010×R0.5870×G0.1140×B\begin{aligned} &Y=0.2990\times R+0.5870\times G+0.1140\times B\\ &U=B-Y=-0.2990\times R-0.5870\times G+0.8860\times B\\ &V=R-Y=0.7010\times R-0.5870\times G-0.1140\times B \end{aligned}Y=0.2990×R+0.5870×G+0.1140×BU=BY=0.2990×R0.5870×G+0.8860×BV=RY=0.7010×R0.5870×G0.1140×B

1.1.2 Conversion formula of digital signal

Normalized

  In order to facilitate processing, the analog signal needs to be normalized when it is converted into a digital signal, so that the dynamic range of the color difference signal is controlled within0.50.5-0.5\sim0.50.50.5between.

  After returning to one sentence, the formula is obtained:
U=0.564×(BY)=0.564×(0.2990×R0.5870×G+0.8860×B)V=0.713×(RY)=0.713×(0.7010×R0.5870×G0.1140×B)\begin{aligned} &U'=0.564\times (B-Y)=0.564\times (-0.2990\times R-0.5870\times G+0.8860\times B)\\ &V'=0.713\times (R-Y)=0.713\times (0.7010\times R-0.5870\times G-0.1140\times B) \end{aligned}U=0.564×(BY)=0.564×(0.2990×R0.5870×G+0.8860×B)V=0.713×(RY)=0.713×(0.7010×R0.5870×G0.1140×B)
  Due to the aboveUVU'、V'UVThe value range of±350mv\pm 350mv±350mvBetween, so you need to introduce+350mv+350mv+350mv bias. The formula becomes:
U=0.564×(BY)+0.35V=0.713×(RY)+0.35\begin{aligned} &U''=0.564\times (B-Y)+0.35\\ &V''=0.713\times (R-Y)+0.35 \end{aligned}U=0.564×(BY)+0.35V=0.713×(RY)+0.35

Code level distribution after luminance signal quantization

  The code level distribution after the quantization of the luminance signal is shown in the figure (source "Digital TV Broadcasting Principles and Applications" P36):

Data compression (5)-color space conversion (full version) (1)

  It can be seen that the peak white level of the brightness signal corresponds to the code level 235, and the blanking level corresponds to the code level 16. In order to prevent overload caused by signal changes, 20 levels at the upper end and 16 levels at the lower end are used as protection bands for the signal to exceed the dynamic range. The code levels 0 and 255 are protection levels, which are not allowed to appear in the video data stream, and the code words 00 and FF are used to transmit synchronization information. The dynamic range of the luminance signal occupies a total of 220 quantization levels.

Code level distribution after color difference signal quantization

  The code level distribution of the color difference signal is shown in the figure, the source of the picture is "Digital TV Broadcasting Principles and Applications" P37):

Data compression (5)-color space conversion (full version) (2)

  Color difference signalCbwithCrC_b and C_rCbwithCrThe peak white level of the peak corresponds to the code level 240, and the 0 level corresponds to the code level 16. In order to prevent overload caused by signal changes, 15 levels at the upper end and 16 levels at the lower end are used as the protection band for the signal to exceed the dynamic range. The dynamic range of the color difference signal occupies a total of 225 quantization levels.

Code level digital expression

  After the quantization of the luminance signal and the color difference signal, the nearest integer is taken as the code level value. The digitized expression is:
DY=INT[(219Y+16)×2n8]DCB=INT[(224Cb+128)×2n8]DCR=INT[(224Cr+128)×2n8]\begin{aligned} &D_Y=INT[(219Y+16)\times 2^{n-8}]\\ &D_{CB}=INT[(224C_b+128)\times 2^{n-8}]\\ &D_{CR}=INT[(224C_r+128)\times 2^{n-8}]\end{aligned}DY=INT[(219Y+16)×2n8]DCB=INT[(224Cb+128)×2n8]DCR=INT[(224Cr+128)×2n8]

  Push the previousY,U,VY,U'',V''Y,U,VBringing into the above formula, you can get:
Y=(66×R+129×G+25×B)>>8+16U=(38×R74×G+112×B)>>8+128V=(112×R94×G18×B)>>8+128\begin{aligned} &Y=(66\times R+129\times G+25\times B)>>8+16\\ &U=(-38\times R-74\times G+112\times B)>>8+128\\ &V=(112\times R-94\times G-18\times B)>>8+128\end{aligned}Y=(66×R+129×G+25×B)>>8+16U=(38×R74×G+112×B)>>8+128V=(112×R94×G18×B)>>8+128

   Write the expression in the form of a matrix:
[YUV]=1256[661292538741121129418][RGB]+[16128128]\begin{aligned}\begin{bmatrix}Y\\U\\V\end{bmatrix}=\frac{1}{256}\begin{bmatrix}66&129&25\\-38&-74&112\\112&-94&-18\end{bmatrix}\begin{bmatrix}R\\G\\B\end{bmatrix}+\begin{bmatrix}16\\128\\128\end{bmatrix}\end{aligned}YUV=2561663811212974942511218RGB+16128128

   order matrix[661292538741121129418]\begin{bmatrix}66&129&25\\-38&-74&112\\112&-94&-18\end{bmatrix}663811212974942511218MatrixAAA, The original formula can be transformed into:[RGB]=256A1[Y16U128V128]\begin{aligned}\begin{bmatrix}R\\G\\B\end{bmatrix}=256A^{-1}\begin{bmatrix}Y-16\\U-128\\V-128\end{bmatrix}\end{aligned}RGB=256A1Y16U128V128

  Because ofA1A^{-1}A1Is too small, so firstAAAEach element in is reduced to the original1256×256\frac{1}{256\times 256}256×2561getA1A_1A1. Then the above formula is converted to:[RGB]=A11[Y16G128B128]÷256\begin{aligned}\begin{bmatrix}R\\G\\B\end{bmatrix}=A_1^{-1}\begin{bmatrix}Y-16\\G-128\\B-128\end{bmatrix}\div 256\end{aligned}RGB=A11Y16G128B128÷256

  Rounding the coefficient to the whole, the following formula can be obtained:
R=(298×Y+411×V57376)>>8G=(298×Y101×U211×V+35168)>>8B=(298×Y+519×U71200)>>8\begin{aligned} &R=(298\times Y+411\times V-57376) >>8 \\ &G=(298\times Y-101\times U-211\times V+35168)>>8 \\ &B=(298\times Y+519\times U-71200)>>8 \end{aligned}R=(298×Y+411×V57376)>>8G=(298×Y101×U211×V+35168)>>8B=(298×Y+519×U71200)>>8

1.2 File storage format

  Check the information,RGBRGBRGBThe file storage format isBGRBGRBGRBGR BGR BGR\cdotsBGRBGRBGR,YUVYUVYUVThe file storage format is first save allYYY, Save allUUUAnd finally save allVVV

2.1 Representation

  One programmain()main()main()The function can contain two parameters:

  • The first parameter isintintintTypes of;
  • The second parameter is a string array;

  Usually, the first parameter is namedargcargcargc, The second parameter isargvargvargv. Since the declaration of the string array in the function header can have two forms, somain()main()main()There are also two ways to write functions.

  1. main()main()main()functionWriting one

    int main(int argc, char** argv){ return 0;}
  2. main()main()main()functionWriting two:

    int main(int argc, char* argv[]){ return 0;}

2.2 How to use

  • The meaning of the parameters:

      int argc​: Represents the number of strings.argc = 1 + the number of strings entered by the user, The value of argc is calculated automatically by the operating system, and the programmer does not need to assign it.

      char argv[]*: It stores multiple strings, the form of the string is as follows:

    argv[0] = the name of the executable file. For example, change.exe. (This string does not require user input, and is the same as argc, which can be automatically generated by the operating system.

    argv[1] = string 1

    argv[2] = string 2

    argv[3] = string 3

    \vdots

  • How to input parameters in programming mode?

  The platform used isVisualStudio2019Visual Studio 2019VisualStudio2019, The file to be used isdown.rgbdown.rgbdown.rgb, The file to be generated isup.yuv,cho.rgbup.yuv,cho.rgbup.yuv,cho.rgb,The steps of parameter input are shown in the following figure:

1. Open the properties window of the upper taskbar debugging interfaceData compression (5)-color space conversion (full version) (3)
2. Select debug in configuration propertiesData compression (5)-color space conversion (full version) (4)
3. Modify the command parameters as requiredData compression (5)-color space conversion (full version) (5)

  Based on the above knowledge, the preliminary realization of color space conversion can be easily carried out. Header filergb2yuv.h,yuv2rgb.hrgb2yuv.h,yuv2rgb.hrgb2yuv.h,yuv2rgb.hAnd source filesmain.cpp,rgb2yuv.cpp,yuv2rgb.cppmain.cpp,rgb2yuv.cpp,yuv2rgb.cppmain.cpp,rgb2yuv.cpp,yuv2rgb.cppcomposition.

  Solution Explorer is shown in the figure below:

Data compression (5)-color space conversion (full version) (6)
  Experiment codeas follows:

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 131072using 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);//First conversionyuv2rgb(YUV, RGB, usize, vsize);//The second conversion/*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 oncevoid 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;//Each rgb is 1 groupj++;}}

yuv2rgb.h

#pragma oncevoid 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;}}

Experimental results

down.rgbup.yuvcho.rgb
Data compression (5)-color space conversion (full version) (7)Data compression (5)-color space conversion (full version) (8)Data compression (5)-color space conversion (full version) (9)

among them,down.rgbdown.rgbdown.rgbwithcho.rgbcho.rgbcho.rgbuseYUVviewerPlusYUVviewerPlusYUVviewerPlusThe way to open is:

Data compression (5)-color space conversion (full version) (10)
  The opened image is an inverted image (due tobmpbmpbmpThe image format is stored backwards, so.rgb.rgb.rgbImage usebmpbmpbmpIt will fall when the mode is opened). The pictures in the above table have been rotated using WeChat for easy identification, butYUVYUVYUVFiles andRGBRGBRGBThere is still mirror flipping between files, but it does not affect viewing and comparison.

  up.yuvup.yuvup.yuvuseYUVviewerPlusYUVviewerPlusYUVviewerPlusThe way to open is:

Data compression (5)-color space conversion (full version) (11)

  It can be seen from the comparison chart of the three images,RGBtoYUVRGB to YUVRGBtoYUV'S experiment was successfully completed, andYUVtoRGBYUVtoRGBYUVtoRGBThere is a problem with the experiment, which is transferred outcho.rgbcho.rgbcho.rgbThere are more red noise in the image.

Error correction

  Inferred available, in progressYUVtoRGBYUVtoRGBYUVtoRGBWhen you getRGBRGBRGBThree figures may exceedunsignedcharunsigned\ charunsignedcharThe range that the type can represent, that is, possible<0<0<0or>255>255>255

   So it’s necessary toyuv2rgb.cppyuv2rgb.cppyuv2rgb.cppThe file is appropriately revised,>255>255>255Values ​​are direct=255=255=255,<0<0<0Values ​​are direct=0=0=0

  After modificationyuv2rgb.cppyuv2rgb.cppyuv2rgb.cppIs as follows:

#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;}}

Experimental results

down.rgbup.yuvcho.rgb
Data compression (5)-color space conversion (full version) (12)Data compression (5)-color space conversion (full version) (13)Data compression (5)-color space conversion (full version) (14)

  So far, almost doneRGBtoYUVRGB to YUVRGBtoYUVwithYUVtoRGBYUVtoRGBYUVtoRGBTwo experiments.

  Using a lookup table to optimize the code. Header fileyuvrgb.hyuvrgb.hyuvrgb.hAnd source filesmain.cpp,yuvrgb.cppmain.cpp,yuvrgb.cppmain.cpp,yuvrgb.cppcomposition.

  Solution Explorer is shown in the figure below:

Data compression (5)-color space conversion (full version) (15)

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//Lookup table initializationint* 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 oncevoid 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;//Each rgb is 1 groupj++;}}void fileend(unsigned char* infi, unsigned char* YUVfi, unsigned char* RGBfi){delete infi;delete YUVfi;delete RGBfi;deleteRGBYUV298;deleteRGBYUV411;deleteRGBYUV101;deleteRGBYUV211;deleteRGBYUV519;deleteRGBYUV66;deleteRGBYUV129;deleteRGBYUV25;deleteRGBYUV38;deleteRGBYUV74;deleteRGBYUV112;deleteRGBYUV94;deleteRGBYUV18;}

Experimental results

down.rgbup.yuvcho.rgb
Data compression (5)-color space conversion (full version) (16)Data compression (5)-color space conversion (full version) (17)Data compression (5)-color space conversion (full version) (18)

  So far, 4:4:4 is completedRGBRGBRGBFile with 4:4:4YUVYUVYUVConversion between files.

Data compression (5)-color space conversion (full version) (19)

  As shown in the figure, it is a 4:2:0 chroma sampling format. So you can get from 4:4:4YUVYUVYUVThe file is converted to 4:2:0YUVYUVYUVThe idea of ​​the document is to keep the originalYYYWeight,UUUSignal andVVVThe signals are all odd points in odd rows. So slightly modify the original code, and add a 4:4:4 according to the above ideaYUVYUVYUVFile gets 4:2:0YUVYUVYUVThe function of the file can be realized fromRGBRGBRGBFile to420YUV4:2:0YUV420YUVFile conversion.

  About from420YUV4:2:0YUV420YUVFile toRGBRGBRGBFile conversion, due to the correlation between pixels, it is conceivable that the originalYYYWeight,UVUVUVThe components can be copied to get the missingUVUVUVWeight, re-converted to 4:4:4YUVYUVYUVfile. According to the above ideas, add a 4:2:0YUVYUVYUVFile gets 4:4:4YUVYUVYUVThe function of the file can be realized from420YUV4:2:0YUV420YUVFile toRGBRGBRGBFile conversion.

  The experiment code is as follows:

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//Lookup table initializationint* 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 oncevoid 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;//Each rgb is 1 groupj++;}}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++)//Calculation of Y component{*(yuv420 + j) = *(yuv444 + i);j++;}for (int i = 0; i < Ysize; )//Calculation of U component{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; )//Calculation of U component{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++)//Calculation of Y component{*(YUV444 + i) = *(YUV420 + j);j++;}for (int i = 0; i < Ysize; )//Calculation of U component{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; )//Calculation of U component{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;deleteRGBYUV298;deleteRGBYUV411;deleteRGBYUV101;deleteRGBYUV211;deleteRGBYUV519;deleteRGBYUV66;deleteRGBYUV129;deleteRGBYUV25;deleteRGBYUV38;deleteRGBYUV74;deleteRGBYUV112;deleteRGBYUV94;deleteRGBYUV18;}

Experimental results

  The results of the experiment have 5 pictures, the firstdown.rgbdown.rgbdown.rgb, Converted to 4:4:4down444.yuvdown444.yuvdown444.yuv, And then converted to 4:2:0down420.yuvdown420.yuvdown420.yuv, And then converted to 4:4:4down4442.yuvdown4442.yuvdown4442.yuv, Then turn intocho.rgbcho.rgbcho.rgb. The results are as follows:

down4444204442cho
Data compression (5)-color space conversion (full version) (20)Data compression (5)-color space conversion (full version) (21)Data compression (5)-color space conversion (full version) (22)Data compression (5)-color space conversion (full version) (23)Data compression (5)-color space conversion (full version) (24)

  So far, all the work has been completed.

  The source of error may be the following reasons:

  1. RGBRGBRGBFiles andYUVYUVYUVWhen the formula for file conversion is deduced, it has been quantified and rounded off for many times, so that the conversion formula itself has errors.
  2. When the 4:4:4 sampling format is converted to the 4:2:0 sampling format, more color difference signals are discarded.
  3. When the 4:2:0 sampling format is converted to the 4:4:4 sampling format, the pixel value of the same point is used to replace the pixel of the missing point.
  4. In the process of file conversion, data overflow occurred, and the overflow point was changed upward to 0 or downward to 255, which also caused errors.
Data compression (5)-color space conversion (full version) (2024)

References

Top Articles
Latest Posts
Article information

Author: Gov. Deandrea McKenzie

Last Updated:

Views: 6256

Rating: 4.6 / 5 (66 voted)

Reviews: 89% of readers found this page helpful

Author information

Name: Gov. Deandrea McKenzie

Birthday: 2001-01-17

Address: Suite 769 2454 Marsha Coves, Debbieton, MS 95002

Phone: +813077629322

Job: Real-Estate Executive

Hobby: Archery, Metal detecting, Kitesurfing, Genealogy, Kitesurfing, Calligraphy, Roller skating

Introduction: My name is Gov. Deandrea McKenzie, I am a spotless, clean, glamorous, sparkling, adventurous, nice, brainy person who loves writing and wants to share my knowledge and understanding with you.