git地址:
GitHub - Evayangelion/EYUVConverter: A YUV converter implemented by cpp
上一次学习了YUV各种采样和存储方式的区别(YUV知识存档)
接下来一起学习一下RGB格式的知识和YUV到RGB的转换方式
RGB色彩模式的分类
RGB的分类相较YUV来说就比较简单和直观,总体来说遵循“怎么取样就怎么存储的”分类方式
按照每个像素信息占据的空间分类,RGB格式可以分成以下几种:
RGB16:每个像素占据的空间是16bit
RGB16分类下还有两种细分类别:
RGB565:R\G\B分量分别占用5bit、6bit、5bit
R | R | R | R | R | G | G | G | G | G | G | B | B | B | B | B |
可以用这几个掩码来分离RGB三个分量:
R = RGB & 0xF800
G = RGB & 0x07E0
B = RGB & 0x001F
RGB555:R\G\B分量分别占用5bit、5bit、5bit,留下最高位不用
R | R | R | R | R | G | G | G | G | G | B | B | B | B | B |
可以用这几个掩码来分离RGB三个分量:
R = RGB & 0x7C00
G = RGB & 0x03E0
B = RGB & 0x001F
RGB24:每个像素占据的空间是24bit,其中R\G\B分量分别占用8bit、8bit、8bit
B | B | B | B | B | B | B | B | G | G | G | G | G | G | G | G | R | R | R | R | R | R | R | R |
可以用这几个掩码来分离RGB三个分量:
R = RGB & 0x7C00
G = RGB & 0x03E0
B = RGB & 0x001F
RGB32:每个像素占据的空间是32bit,其中R\G\B分量分别占用8bit、8bit、8bit,多出的8bit用来存alpha分量,也就是透明分量
B | B | B | B | B | B | B | B | G | G | G | G | G | G | G | G |
R | R | R | R | R | R | R | R | A | A | A | A | A | A | A | A |
可以用这几个掩码来分离RGB三个分量:
R = RGBA & 0x0000FF00
G = RGBA & 0x00FF0000
B = RGBA & 0xFF000000
A = RGBA & 0x000000FF
YUV420到RGB格式的转换
简单说完了RGB的储存原理和分类方式,接下来需要知道RGB和YUV各个分量的转化办法,这里直接给出转换公式:
R = Y + 1.402 * (V -128);
G = Y - 0.34414 * (U - 128) - 0.71414 * (V - 128);
B = Y + 1.772 * (U - 128);
由于YUV三个分量是有复数值的,而RGB分量的值都在0-255中间,所以需要将YUV分量进行量化
有上面的知识,加上之前对YUV的了解,下来就可以尝试将一张YUV420的图片转换成RGB888
void YUV420toRGB(unsigned char *yuv420, unsigned char*rgb ,int width, int height) {int Ylen = width * height;unsigned char *p_Y420 = yuv420;unsigned char *p_U420 = p_Y420 + Ylen;unsigned char *p_V420 = p_U420 + Ylen / 4;int rgbIndex = 0;int R,G,B,Y,U,V;for(int y = 0; y < height; y++) {for(int x = 0; x < width; x++){Y = *(p_Y420 + y * width + x);U = *(p_U420 + (y / 2) * (width / 2) + x / 2);V = *(p_V420 + (y / 2) * (width / 2) + x / 2);/* * 在网络上搜索出的UV分量取值大多是 (y * width / 4) + x / 2这样* 我认为写成(y / 2) * (width / 2) + x / 2可以帮助理解* 原因如下:* 1.因为是YUV420的采样方式,每2×2个y分量公用一个u/v分量* 也就是对于偶数i,共用一个ui/vi的y分量有:* yi yi+1* yi+w yi+w+1* 所以在y和x方向分别需要/2* 2.width/2的原因是uv分量的行宽是y分量的一半* y分量进入下一行需要+width个y分量* 那么uv分量进入下一行则需要+width/2个uv分量*/R = Y + 1.402 * (V -128);G = Y - 0.34414 * (U - 128) - 0.71414 * (V - 128);B = Y + 1.772 * (U - 128);R = R < 255 ? R : 255;G = G < 255 ? G : 255;B = B < 255 ? B : 255;R = R < 0 ? 0 : R;G = G < 0 ? 0 : G;B = B < 0 ? 0 : B;*(rgb + rgbIndex++) = R;*(rgb + rgbIndex++) = G;*(rgb + rgbIndex++) = B;}}
}
参考:
《图像处理》Part1 YUV4:2:2toYUV4:2:0、YUV420toYUV422、YUV422toRGB24、YUV420toRGB24算法_梁Rio的博客-CSDN博客
图解RGB565、RGB555、RGB16、RGB24、RGB32、ARGB32等格式的区别_handy周的博客-CSDN博客_rgb565