2. 图像数据格式与内存布局基础
在STM32N6上做图像预处理,第一件必须搞清楚的事不是算法,而是“像素在内存里到底怎么排”。同一幅图像,RGB888、RGB565、YUV422、灰度8位,它们在内存中的字节数、访问粒度、DMA搬运效率完全不同。如果格式选错或stride没对齐,即使算法正确,帧率也可能掉一半。
一、三种主流格式的存储本质
RGB格式按像素打包颜色分量。RGB888每像素3字节,顺序通常为B、G、R(小端存储时低位在前);RGB565每像素2字节,用5位红、6位绿、5位蓝压缩,适合显示和带宽受限场景。RGB的优点是直观、便于色彩处理,缺点是数据量大,且三通道交织导致按通道访问时步长不连续。
YUV格式把亮度Y与色度UV分离。YUV444每像素3字节;YUV422每2个像素共享一组UV,平均每像素2字节;YUV420每4个像素共享一组UV,平均每像素1.5字节。STM32N6的ISP和DCMIPP通常输出YUV422,因为它在保留色彩信息的同时把带宽压到RGB888的约2/3。
灰度格式每像素1字节,只保留亮度。它没有色彩信息,但内存占用最小、访问最连续,非常适合边缘检测、二值化、光流等只依赖亮度的预处理。
二、平面存储与打包存储
YUV有两种典型布局。打包(packed/interleaved)把Y、U、V按像素顺序交织,例如YUYV:Y0 U0 Y1 V0 Y2 U1 Y3 V1……这种布局一次DMA就能搬完整行,缓存局部性好。平面(planar)把Y、U、V分别放在三个连续区域,先存完整Y平面,再存U平面、V平面。平面布局便于单独处理亮度通道,但访问色度时需要跳到另一块地址,cache命中率可能下降。
STM32N6的DCMIPP和DMA2D对打包YUV422支持更直接;如果算法需要频繁单独读Y,平面格式反而更省事。选择依据是“谁访问得多、访问是否连续”。
三、行对齐与stride
图像每行实际占用的字节数叫stride(行跨距),它不一定等于“宽度×每像素字节数”。硬件常要求stride按4字节、8字节或16字节对齐,目的是让每行起始地址落在总线突发边界上。例如宽度为641的灰度图,每行641字节,若要求16字节对齐,stride应取656(641向上取到16的倍数)。此时每行末尾有15字节填充,这些填充不参与显示,但必须计入地址计算。
访问像素(x, y)的地址公式为:
addr = base + y * stride + x * bytes_per_pixel
如果误用width代替stride,从第二行起就会整体错位,图像出现斜切。STM32N6的LTDC、DCMIPP、DMA2D都提供独立的stride寄存器,配置时必须显式写入对齐后的值。
四、位宽与字节序对访问效率的影响
STM32N6的Cortex-M55总线以32位为基本访问宽度,配合AXI突发传输。每像素1字节的灰度图,一次32位读取可拿到4个像素;RGB565一次可拿2个像素;RGB888则会出现跨字边界,需要两次访问才能凑齐一个像素,效率明显下降。因此,在带宽敏感的场景,优先选择2字节或1字节每像素的格式,并尽量让行起始地址32位对齐。
字节序方面,RGB888在内存中常按B、G、R排列,若按32位字读取,一个字的四个字节可能包含B0 G0 R0 B1,解析时必须按字节拆分。YUV422的YUYV打包中,U和V的顺序也依赖具体外设约定,DCMIPP输出与DMA2D输入若字节序理解不一致,会出现红蓝互换或色度错位。
五、面向STM32N6的布局选择建议
结合STM32N6的cache和DMA特性,可以给出如下实践取向:
- 只做亮度处理时,优先灰度8位,stride按16字节对齐,DMA一次搬多行。
- 需要色彩且带宽紧张时,选YUV422打包,stride按8字节对齐,避免平面跳转。
- 需要逐通道处理时,选平面YUV420,但注意U/V平面宽度是Y的一半,stride也要单独对齐。
- RGB565适合显示链路,RGB888仅在算法必须高精度色彩时使用,并接受带宽代价。
下面这张图把四种典型格式在内存中的排布、stride对齐和访问粒度放在一起对比,便于在选型时快速判断。