LV01-图像-02-色彩空间-02-RGB

本文主要是色彩编码——YUV的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
PC端开发环境 Windows Windows11
Ubuntu Ubuntu20.04.6的64位版本
VMware® Workstation 17 Pro 17.0.0 build-20800274
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Win32DiskImager Win32DiskImager v1.0
Linux开发板环境 Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
点击查看本文参考资料
点击查看相关文件下载
------

一、RGB是什么?

1. 简介

百度百科RGB(颜色系统)_百度百科 (baidu.com)是这样说的:RGB 色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB 即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。

RGB

RGB是从颜色发光的原理来设计定的,通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于三者亮度之总和,越混合亮度越高,即加法混合。

红、绿、蓝三盏灯的叠加情况,中心三色最亮的叠加区为白色,加法混合的特点:越叠加越明亮。红、绿、蓝三个颜色通道每种色各分为256阶亮度,在0时“灯”最弱——是关掉的,而在255时“灯”最亮。当三色灰度数值相同时,产生不同灰度值的灰色调,即三色灰度都为0时,是最暗的黑色调;三色灰度都为255时,是最亮的白色调。

RGB 颜色称为加成色,因为我们通过将 R、G 和 B 添加在一起(即所有光线反射回眼睛)可产生白色。加成色用于照明光、电视和计算机显示器。例如,显示器通过红色、绿色和蓝色荧光粉发射光线产生颜色。绝大多数可视光谱都可表示为红、绿、蓝 (RGB) 三色光在不同比例和强度上的混合。这些颜色若发生重叠,则产生黄、青和紫。

img

任何基于RGB颜色模型加色色彩空间都属于RGB色彩空间。RGB色彩空间由红绿蓝三原色色度定义,借此可以定义出相应的色三角(英语:Color triangle),生成其它颜色。完整的RGB色彩空间定义还需要给出白点的色度和伽玛校正曲线。目前最常见的RGB色彩空间是sRGB色彩空间

Thumb image

CIE1931色彩空间的色度图上比较不同RGB色彩空间的色域

2. 分类

RGB 格式目前主要有两类:

  • 像素格式

这是我们比较常用的格式,R,G,B 分别分开,用N个位来表示。例如 RGB24格式 中 R 占 8位,G 占 8位,B 占8 位,所以一个像素占 24位。这种格式可以混合生成 256 * 256 * 256 = 16,777,216 种颜色,但缺点是占用空间大。

  • 索引格式

RGB 的值是一个索引,不是真正的颜色值,例如 RGB 的值 占 1位,那只有两个值 0 跟 1,通常用于黑白颜色,这种情况下 一个像素只占 1位,大大节省了空间。0 跟 1 到底是什么颜色,是通过 索引表(也叫调色板)来定位的,不一定是 黑白,也可以是其他的颜色。所以叫索引格式。只占 1 位的 RGB 称为 RGB1,还有 RGB4 占 4 位,索引表有 16 种颜色, RGB8 占 8 位,索引表有 256 种颜色。

不需要 索引表/调色板 的 RGB 模式 称为 真彩色

二、RGB的格式

RGB三种颜色在进行编码的时候,根据位数有RDB16、RGB24和RGB32三种。

1. RGB16 格式

RGB16就是每个像素点占16位,也就是R、G和B三种颜色一共占16位,那这三者各多少位呢?有两种:RGB565和RGB555。

1.1 RGB565

RGB565的每个像素用 16 bits 表示,占 2 个字节,R,G,B 分量分别使用 5 位、6 位、5 位。

image-20221120223849290

从上面排列格式,我们使用C语言得到 RGB565 各分量的值:

1
2
3
4
5
6
#define RGB565_MASK_RED   0xF800      // 1111 1000 0000 0000
#define RGB565_MASK_GREEN 0x07E0 // 0000 0111 1110 0000
#define RGB565_MASK_BLUE 0x001F // 0000 0000 0001 1111
R = (color & RGB565_MASK_RED) >> 11; // 取值范围0-31
G = (color & RGB565_MASK_GREEN) >> 5; // 取值范围0-63
B = color & RGB565_MASK_BLUE; // 取值范围0-31

1.2 RGB555

RGB555每个像素用 16 bits 表示,占 2 个字节,R,G,B 分量都使用 5 位(最高位不用)。

image-20221120224305348

从上面排列格式,我们使用C语言得到 RGB555 各分量的值:

1
2
3
4
5
6
7
#define RGB555_MASK_RED   0x7C00      // 0111 1100 0000 0000
#define RGB555_MASK_GREEN 0x03E0 // 0000 0011 1110 0000
#define RGB555_MASK_BLUE 0x001F // 0000 0000 0001 1111
R = (color & RGB555_MASK_RED) >> 10; // 取值范围0-31
G = (color & RGB555_MASK_GREEN) >> 5; // 取值范围0-31
B = color & RGB555_MASK_BLUE; // 取值范围0-31

2. RGB24 格式

RGB24格式也可以叫RGB888,每个像素用 24 bits 表示,占 3 个字节,R,G,B 分量都使用 8 位。

image-20221120224805272

从上面排列格式,我们使用C语言得到 RGB888 各分量的值:

1
2
3
4
5
6
#define RGB24_MASK_RED   0xFF0000
#define RGB24_MASK_GREEN 0x00FF00
#define RGB24_MASK_BLUE 0x0000FF
R = (color & RGB24_MASK_RED) >> 16;
G = (color & RGB24_MASK_GREEN) >> 8;
B = color & RGB24_MASK_BLUE;

注意:在内存中RGB各分量的排列顺序为:BGR BGR BGR ……,主要还是看大小端。

3. RGB32 格式

3.1 一般格式

一般来说,RGB32格式每个像素用 32 比特位表示,占 4 个字节,R,G,B,X 分量都使用 8 位(X表示不使用)。

image-20221120225212447

从上面排列格式,我们使用C语言得到 RGB32 各分量的值:

1
2
3
4
5
6
7
8
#define RGB32_MASK_RED   0xFF000000
#define RGB32_MASK_GREEN 0x00FF0000
#define RGB32_MASK_BLUE 0x0000FF00
#define RGB32_MASK_X 0x000000FF
R = (color & RGB32_MASK_RED) >> 24;
G = (color & RGB32_MASK_GREEN) >> 16;
B = (color & RGB32_MASK_BLUE) >> 8;
X = color & RGB32_MASK_X;

注意:在内存中RGB各分量的排列顺序为可能是BGRX BGRX BGRX ……这样,具体可能是跟大小端有关。

3.2 ARGB32

很多时候我们也会使用ARGB32,它与RGB32的区别在于保留的 8 个 bit 用来表示透明度,也就是 alpha 的值。需要注意的是,虽然名字是ARGB,但是实际A分量是使用的低8位,也就是说ARGB格式在内存中是RGBA RGBA … 这样排列的(但也可能反过来,主要是大小端的原因导致)

image-20221120225535745

从上面排列格式,我们使用C语言得到 ARGB32 各分量的值:

1
2
3
4
5
6
7
8
#define ARGB_MASK_RED   0xFF000000
#define ARGB_MASK_GREEN 0x00FF0000
#define ARGB_MASK_BLUE 0x0000FF00
#define ARGB_MASK_ALPHA 0x000000FF
R = (color & ARGB_MASK_RED) >> 24;
G = (color & ARGB_MASK_GREEN) >> 16;
B = (color & ARGB_MASK_BLUE) >> 8;
A = color & ARGB_MASK_ALPHA;

三、ARGB格式

上边我们学习RGB格式的时候了解到了ARGB32这种格式,其实我们经常还会看到ARGB4444、ARGB1555、ARGB8888等,这些又是什么格式?我们也来了解一下吧。

1. 简介

一种色彩模式,也就是RGB(Alpha,Red,Green,Blue)色彩模式附加上Alpha(透明度)通道,常见于32位位图的存储结构。如,8位(#1e000000)ARGB 头两位是透明度,00是完全透明,ff是完全不透明,后6位是RGB值,比较适中的透明度值。

2. ARGB1555

每个像素用16比特位表示,占2个字节,透明通道用1位来表示,RGB分量都使用5位:

image-20230519195340899

3. ARGB4444

每个像素用16比特位表示,占2个字节,透明通道用4位来表示,RGB分量都使用4位:

image-20230519195512529

3. ARGB8888

每个像素用32比特位表示,占4个字节,Alpha和RGB分量都使用8位:

image-20230519195717137

四、RGB颜色格式转换

我们使用的LCD屏幕可能使用的是RGB565这样的数据格式,而我们一般给颜色值都是给一个RGB888格式的,所以很多时候我们还需要对颜色格式进行转换。

1. RGB888转RGB565

1.1 转换思路

我们将RGB888转换为RGB565的主要思路就是:

  • R:将RGB888的(R)高5位(R7 R6 R5 R4 R3)与RGB565(r7 r6 r5 r4 r3)相对应,即R值&0x1F(取高5位),然后左移11位→(R & 0x1F)<<11;
  • G:将RGB888的(G)高6位(G7 G6 G5 G4 G3 G2)与RGB565(g7 g6 g5 g4 g3 g2)相对应,即G值&0x3F(取高6位),然后左移5位→ (G & 0x3F)<<5;
  • B:将RGB888的(B)高5位(B7 B6 B5 B4 B3)与RGB565(b7 b6 b5 b4 b3)相对应,即B值&0x1F(取高5位)→(B & 0x1F) << 0;
image-20221120230719070

1.2 宏实现

我们可以定义一个宏,也可以在函数内实现,这里写一下宏定义的方式:

1
2
3
4
5
6
#define argb8888_to_rgb565(color)   ({ \
unsigned int temp = (color); \
((temp & 0xF80000UL) >> 8) | \
((temp & 0xFC00UL) >> 5) | \
((temp & 0xF8UL) >> 3); \
})

1.3函数实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define RGB888_RED      0x00ff0000
#define RGB888_GREEN 0x0000ff00
#define RGB888_BLUE 0x000000ff

#define RGB565_RED 0xf800
#define RGB565_GREEN 0x07e0
#define RGB565_BLUE 0x001f

unsigned short RGB888ToRGB565(unsigned int n888Color)
{
unsigned short n565Color = 0;

// 获取RGB单色,并截取高位
unsigned char cRed = (n888Color & RGB888_RED) >> 19;
unsigned char cGreen = (n888Color & RGB888_GREEN) >> 10;
unsigned char cBlue = (n888Color & RGB888_BLUE) >> 3;

// 连接
n565Color = (cRed << 11) + (cGreen << 5) + (cBlue << 0);
return n565Color;
}

unsigned int RGB565ToRGB888(unsigned short n565Color)
{
unsigned int n888Color = 0;

// 获取RGB单色,并填充低位
unsigned char cRed = (n565Color & RGB565_RED) >> 8;
unsigned char cGreen = (n565Color & RGB565_GREEN) >> 3;
unsigned char cBlue = (n565Color & RGB565_BLUE) << 3;

// 连接
n888Color = (cRed << 16) + (cGreen << 8) + (cBlue << 0);
return n888Color;
}