4、图像格式与色彩空间:YUV/RGB/JPEG格式对比、色彩空间转换(CSC)硬件加速、像素格式对内存的影响
说到嵌入式网络摄像头的内存优化,图像格式和色彩空间是绕不开的核心话题。我刚开始做摄像头项目时,也踩过不少坑——明明硬件性能够,为什么帧率上不去?内存占用为什么比预期高出一大截?后来才发现,问题往往出在像素格式的选择上。
4.1 YUV vs RGB vs JPEG:三种格式的底层差异
先聊聊这三种最常见的图像格式。你想想看,摄像头传感器拍到的原始数据是什么?其实是Bayer格式的RAW数据。但我们在嵌入式系统里处理时,通常不会直接用RAW,而是转换成YUV、RGB或者JPEG。
RGB格式:每个像素由红、绿、蓝三个分量组成。一个常见的RGB888像素,每个分量占8位,一个像素就是24位(3字节)。
YUV格式:把亮度信息(Y)和色度信息(U、V)分开。人眼对亮度更敏感,对色度不那么敏感。所以我们可以对色度进行压缩——这就是YUV420的由来。
JPEG格式:有损压缩格式。它利用离散余弦变换(DCT)和量化表,把图像数据压缩到原来的十分之一甚至更小。但代价是解码需要额外的CPU开销。
核心对比:
- RGB:显示友好,但内存占用大。一个1080p的RGB888图像需要 1920×1080×3 ≈ 6.2MB。
- YUV420:存储友好,Y分量全分辨率,UV分量各为1/4。同样1080p只需要 1920×1080×1.5 ≈ 3.1MB,省了一半。
- JPEG:压缩比最高,但编解码需要算力。1080p的JPEG通常只有几百KB。
我个人习惯在视频流处理链路中这样选:传感器输出用YUV420,显示或AI推理时转RGB,存储或传输时用JPEG。这样能平衡内存和性能。
4.2 色彩空间转换(CSC)硬件加速
色彩空间转换,说白了就是把YUV转成RGB,或者反过来。这个操作在摄像头应用中太频繁了——传感器输出YUV,但显示器和AI模型通常要RGB。
软件做CSC其实很慢。一个简单的转换公式:
// YUV到RGB的转换(简化版)
R = Y + 1.402 * (V - 128)
G = Y - 0.344 * (U - 128) - 0.714 * (V - 128)
B = Y + 1.772 * (U - 128)
你看,每个像素都要做三次乘法和三次加法。1080p图像有200多万个像素,纯软件跑一遍CSC,CPU占用率直接飙到30%以上。
我的经验:我在一个项目中用过纯软件CSC,结果帧率从30fps掉到了12fps。后来改用硬件CSC模块,帧率直接回到30fps,CPU占用率降到5%以下。硬件加速不是锦上添花,是刚需。
大多数嵌入式SoC(比如海思、瑞芯微、全志)都内置了CSC硬件模块。你只需要配置寄存器,告诉它输入格式是YUV420,输出格式是RGB888,它就能在几个时钟周期内完成一帧的转换。
硬件CSC的优势:
- 零CPU开销:转换过程不占用CPU
- 低延迟:通常只需要几行数据的缓冲时间
- 高吞吐:可以做到实时处理4K@60fps
注意:硬件CSC的精度通常是8位或10位。如果你需要高精度(比如HDR场景),要确认硬件是否支持12位或更高位宽。我曾经因为没注意这个,导致HDR图像出现色带,排查了两天才找到原因。
4.3 像素格式对内存的影响
嗯,这里要重点讲。像素格式直接决定了你的内存带宽和存储需求。
我们用一个表格来对比常见格式的内存占用:
| 格式 | 每像素位数 | 1080p一帧大小 | 30fps带宽需求 |
|---|---|---|---|
| RGB888 | 24 | 6.2 MB | 186 MB/s |
| RGB565 | 16 | 4.1 MB | 123 MB/s |
| YUV420 | 12 | 3.1 MB | 93 MB/s |
| YUV422 | 16 | 4.1 MB | 123 MB/s |
| NV12 | 12 | 3.1 MB | 93 MB/s |
看到没?从RGB888换成YUV420,内存带宽直接砍半。这对嵌入式系统来说太关键了——DDR带宽往往是瓶颈。
我建议你这样选:
- 显示场景:用RGB565或RGB888。如果屏幕是16位色,RGB565就够了,省带宽。
- 视频编码:用YUV420或NV12。编码器通常原生支持这些格式,不需要额外转换。
- AI推理:看模型要求。很多模型要RGB888,那就得在推理前做CSC。
- 存储/传输:用JPEG或H.264/H.265。别存原始YUV,太占空间。
避坑指南:我曾经在一个项目里用了RGB888做视频编码,结果编码器不支持,只能先转YUV420再编码。多了一次CSC操作,帧率掉了10fps。后来我直接让传感器输出YUV420,省掉了这一步。所以,尽量让数据流中的格式转换次数最少。
4.4 实战建议:如何选择最优像素格式
说了这么多,总结几条实战经验:
- 从传感器开始规划:查一下你的摄像头传感器支持哪些输出格式。大多数CMOS传感器都支持YUV420和RGB565。选YUV420作为默认。
- 利用硬件CSC:如果SoC有硬件CSC,别犹豫,用起来。配置方法通常很简单,几行寄存器操作就行。
- 避免内存拷贝:用DMA或硬件模块直接操作内存,别用CPU逐像素拷贝。我见过有人用memcpy拷贝YUV图像,结果带宽跑满,CPU干不了别的。
- 考虑对齐要求:很多硬件模块要求图像数据按16字节或32字节对齐。不对齐的话,性能会下降,甚至报错。
- 测试实际带宽:别只看理论值。用性能计数器测一下实际DDR带宽,有时候缓存命中率会影响很大。
一个小技巧:如果你不确定选什么格式,先跑一个YUV420的流水线。它兼容性最好,内存占用低,而且大多数硬件都原生支持。等性能瓶颈出现时,再针对性优化。
好了,这一章就聊到这里。下一章我们会深入讲内存分配策略——怎么避免碎片化,怎么用内存池。到时候见。