图像基础与色彩空间: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 色彩空间对压缩的影响:一张图说清楚
下面这张图是我自己总结的,把几种色彩空间在“体积”、“压缩潜力”、“色彩丰富度”三个维度上做了对比。你一看就明白。
2.6 实战选择建议
说了这么多,到底怎么选?我根据自己的项目经验,整理了一个决策流程:
- 先问自己: 这张图需要透明吗?不需要 → 去掉Alpha通道。
- 再问: 颜色数能减少吗?能少于256色 → 用索引色。
- 再问: 只需要亮度信息吗?是 → 用灰度图甚至二值图。
- 最后: 以上都不行,才考虑RGB565或RGB888。
我的经验法则: 在嵌入式GUI中,80%的图标和按钮可以用索引色,15%的纯文字界面可以用灰度图,只有不到5%的高清图片才需要RGB565。RGB888和ARGB8888,能不用就不用。