图像基础与色彩空间:RGB、ARGB、索引色、灰度图

做嵌入式GUI,说白了就是跟像素打交道。你想想看,一个屏幕上有几十万个点,每个点怎么存、怎么算,直接决定了你的Flash够不够用、刷屏快不快。我刚开始做嵌入式产品时,总觉得图像压缩是上层的事,底层只管送数据就行。直到有一次,一个简单的开机动画就把128KB的Flash撑爆了……嗯,从那以后我再也不敢忽视图像格式的选择了。

这一章,我们就把几种常见的色彩空间掰开揉碎,看看它们到底长什么样,以及——最关键的是——它们对压缩有什么影响。

2.1 RGB:最朴素的真彩色

RGB是最基础的色彩模型。红、绿、蓝三个通道,每个通道8位,组合起来就是24位真彩色。一个像素占3个字节,能表示1677万种颜色。

核心公式: 一张RGB888图像的大小 = 宽度 × 高度 × 3 字节

举个例子:一个320×240的QVGA屏,全屏RGB888图像占多少?

320 × 240 × 3 = 230,400 字节 ≈ 225 KB

225KB!对于很多MCU来说,这已经是一半的RAM了。所以,裸用RGB888在嵌入式里基本是奢侈的。我个人习惯是,除非屏幕特别大或者对色彩要求极高,否则尽量别碰24位图。

2.2 ARGB:带透明通道的“胖子”

ARGB就是在RGB基础上加了一个Alpha通道,用来控制透明度。每个像素变成4个字节:A、R、G、B各8位。

格式 位深 每像素字节 颜色数 典型场景
RGB888 24位 3 16.7M 照片、高保真图标
ARGB8888 32位 4 16.7M + 256级透明 UI叠加层、鼠标指针
RGB565 16位 2 65K 嵌入式主流、LCD屏
ARGB1555 16位 2 32K + 1位透明 简单透明图标

我曾经踩过的坑: 有一次做手表UI,图标用了ARGB8888,结果一个48×48的图标就占了9KB。整张表盘放了20个图标,Flash直接报警。后来全部换成ARGB1555,体积砍了一半,肉眼几乎看不出区别。

为什么会这样?因为透明通道在压缩时很难被预测。RLE(游程编码)遇到Alpha值频繁变化时,压缩率会急剧下降。所以我的建议是:能用纯色背景就别用透明,能用1位透明就别用8位。

2.3 索引色:嵌入式压缩的“老朋友”

索引色,也叫调色板模式。它不直接存每个像素的颜色值,而是存一个“颜色编号”。这个编号指向一个颜色表(调色板)。

举个例子:一张图只有16种颜色,那么每个像素只需要4位(16种编号),而不是24位。调色板本身只占16×3=48字节。

// 索引色示例:4位索引 + 16色调色板
// 像素数据:0x1A 0x3F ... (每个字节存两个像素)
// 调色板:{R0,G0,B0, R1,G1,B1, ... R15,G15,B15}

关键优势: 索引色在嵌入式GUI中压缩率极高。同样的320×240图像,用4位索引色只需要38.4KB,是RGB888的1/6。

我在项目中遇到过很多次:客户给的UI设计稿是24位PNG,我二话不说先转成索引色。只要颜色数不超过256,视觉损失几乎为零,但体积能省一大截。尤其是按钮、图标这类色块分明的图形,索引色简直是神器。

2.4 灰度图:最简单的压缩对象

灰度图只有一个通道,每个像素8位,表示亮度从0(黑)到255(白)。没有颜色信息,只有明暗。

你想想看,灰度图为什么好压缩?因为相邻像素的亮度值变化通常很平滑。RLE、LZ77这类算法在灰度图上表现极好。我做过测试:一张128×64的灰度图,原始大小8KB,用RLE压缩后只有1.2KB,压缩率85%。

格式 每像素位数 128×64大小 RLE压缩后 压缩率
灰度8位 8 8KB ~1.2KB 85%
灰度4位 4 4KB ~0.8KB 80%
二值图 1 1KB ~0.3KB 70%

实用技巧: 如果你的嵌入式设备只需要显示文字或简单波形,直接用二值图(1位/像素)。一个汉字点阵16×16,用二值图只需要32字节。我做过一个温控器项目,所有界面字符全用二值图,整个字库才2KB。

2.5 色彩空间对压缩的影响:一张图说清楚

下面这张图是我自己总结的,把几种色彩空间在“体积”、“压缩潜力”、“色彩丰富度”三个维度上做了对比。你一看就明白。

色彩空间对比:体积 vs 压缩潜力 vs 色彩丰富度 压缩潜力 低 高 色彩丰富度 → 灰度图 索引色 RGB565 RGB888 ARGB8888 说明:越靠左上角,压缩潜力越大、体积越小,但色彩丰富度越低。嵌入式GUI中,索引色和灰度图是性价比最高的选择。 ARGB8888虽然色彩最丰富,但压缩率最低,除非必要,否则慎用。

2.6 实战选择建议

说了这么多,到底怎么选?我根据自己的项目经验,整理了一个决策流程:

  1. 先问自己: 这张图需要透明吗?不需要 → 去掉Alpha通道。
  2. 再问: 颜色数能减少吗?能少于256色 → 用索引色。
  3. 再问: 只需要亮度信息吗?是 → 用灰度图甚至二值图。
  4. 最后: 以上都不行,才考虑RGB565或RGB888。

我的经验法则: 在嵌入式GUI中,80%的图标和按钮可以用索引色,15%的纯文字界面可以用灰度图,只有不到5%的高清图片才需要RGB565。RGB888和ARGB8888,能不用就不用。