2. 图像数据流特点

做图像处理的硬件加速,第一件事就是搞清楚数据长什么样。我见过不少新手,上来就写RTL,结果发现数据格式不对,整个架构推倒重来。嗯,咱们今天就把这个基础打牢。

像素数据格式

图像说白了就是一堆像素点。每个像素点怎么表示?这取决于色彩空间和位宽。

常见的像素格式:

  • 灰度图(Gray8):每个像素8位,0-255表示亮度。我在做医疗影像项目时,CT图像基本都是这个格式,简单直接。
  • RGB888:红绿蓝各8位,共24位。这是显示器的标准格式,也是我们做图像加速最常碰到的。
  • RGB565:红5位、绿6位、蓝5位,共16位。嵌入式设备里常见,省带宽。
  • YUV420:亮度Y单独,色度UV共用。视频编码标准格式,H.264/H.265都用它。

重点:在FPGA里,像素数据通常以AXI4-Stream的形式传输。每个像素可能占1个或多个beat。比如RGB888,我习惯用32位总线,一个beat传一个像素,高8位闲置。

行/帧同步信号

图像数据不是一股脑儿倒进来的。它有节奏——行同步和帧同步。

典型的同步信号包括:

  • VSYNC(帧同步):一帧开始时的脉冲。高电平有效或低电平有效,看具体协议。
  • HSYNC(行同步):一行开始时的脉冲。
  • DE(数据使能):有效数据指示。这个信号我最喜欢用,因为它直接告诉硬件「这拍数据是有效的」。

举个例子,1080p@60fps的时序:

参数 值
有效像素/行 1920
行消隐 280(含HSYNC)
有效行/帧 1080
帧消隐 45(含VSYNC)
总行/帧 1125

我的经验:在AXI4-Stream里,我们用TLAST信号表示行结束,TVALID和TREADY做握手。TUSER可以携带帧起始信息。我曾经在一个项目中,因为TLAST位置算错了一拍,导致整帧图像错位,排查了两天才找到问题。所以,同步信号的时序仿真一定要做。

带宽计算

带宽是硬件设计的命门。算不对,后面全白干。

带宽公式很简单:

带宽 = 分辨率 × 帧率 × 每像素位数

举个例子:

  • 1080p@60fps,RGB888:1920×1080×60×24 = 2.99 Gbps
  • 4K@30fps,YUV420:3840×2160×30×12 = 2.99 Gbps

你看,4K YUV420的带宽和1080p RGB888差不多。这就是为什么视频编码喜欢用YUV420——省带宽。

实际工程中要考虑的:

  • AXI总线效率不是100%。我一般按70%-80%估算。
  • DDR带宽要留余量,至少1.5倍。
  • 多路视频处理时,带宽要累加。

缓存需求

图像处理离不开缓存。为什么?因为算法需要「看」到相邻像素。

常见的缓存场景:

  • 行缓存(Line Buffer):做3×3滤波,至少需要缓存2行。我习惯用BRAM实现,深度等于图像宽度。
  • 帧缓存(Frame Buffer):做帧间处理,比如运动估计,需要存1-2帧。这个量就大了,1080p RGB888一帧要1920×1080×3 = 6.2 MB。BRAM肯定不够,得上DDR。
  • 窗口缓存(Window Buffer):做局部处理,比如去噪,缓存一个N×N的窗口。

注意:行缓存的深度必须等于图像的实际宽度,不是有效像素数。因为你要考虑消隐区。我曾经有个项目,图像宽度设成了1920,但实际行总长2200,结果缓存溢出,图像底部出现花屏。嗯,这个坑我替你们踩过了。

知识体系总览

下面这张图,是我总结的图像数据流核心知识点。你看一眼,心里就有谱了。

图像数据流核心知识体系 像素数据格式 Gray8 / RGB888 / RGB565 YUV420 / Bayer RAW 行/帧同步信号 VSYNC / HSYNC / DE TLAST / TVALID / TREADY 带宽计算与缓存 带宽 = 分辨率×帧率×位宽 行缓存 / 帧缓存 / 窗口缓存 设计要点总结 ① 确认像素格式 → ② 对齐同步信号 → ③ 计算带宽需求 → ④ 规划缓存策略 ⑤ 留足余量 → ⑥ 仿真验证时序 → ⑦ 上板实测

说白了,图像数据流就是三件事:数据长什么样、怎么告诉硬件数据来了、硬件需要多少资源来处理。搞清楚了这三点,后面的设计就顺了。

个人建议:开始写RTL之前,先花一天时间把数据流图画出来。像素格式、同步信号、带宽、缓存大小,全部标清楚。我每次都是这么干的,省得后面返工。