2026年,FPGA大赛用国产紫光同创FPGA做实时视频去雾,暗通道先验算法BRAM不够,怎么用分块处理和流水线重排硬挤出来?求具体操作步骤

开放6 回答 6 浏览

我在备赛2026年FPGA大赛,选了实时视频去雾这个题目,用的是紫光同创的FPGA,暗通道先验算法在硬件化时BRAM资源爆了。我尝试了分块处理,但流水线设计还是乱,求大佬给个具体的分块大小和流水线重排步骤,比如怎么划分图像块、怎么调整数据流避免冲突,最好有伪代码或关键Verilog代码片段,急!

分享:
  • 数字电路入门生

    看到你用的是紫光同创的FPGA,这类国产器件的BRAM分布和Xilinx不太一样,分块策略得调成匹配其硬宏结构的尺寸,不能照搬论文里的16×16。先确认一下你的视频分辨率——如果是1080p,16×16块内缓存一行需要大约1920像素的line buffer,紫光同创的BRAM单块深度一般只有9K或18K位,16位灰度图的话一块BRAM只能存大约512个像素,所以要存一行得拼4到8块,这个开销要算进去。我建议你把块大小降到8×8甚至4×4,虽然暗通道估计的准确度会降一点点,但换来的是BRAM占用直接砍半。具体流水线重排步骤:第一级,用两个512深度的双口RAM做乒乓读入,一个块在写的时候另一个块在做暗通道最小值计算;第二级,把暗通道结果暂存在一个寄存器阵列里,不用BRAM,用LUT搭的分布式RAM,因为8×8才64个点,LUT完全够用;第三级,透射率和去雾计算可以复用同一个BRAM做系数查找表。关键点是让BRAM只在图像输入阶段密集使用,计算阶段完全释放掉。你现在的流水线乱,大概率是因为在读数据和算暗通道之间插了太多等待周期,正确的做法是让写BRAM和算暗通道在同一个时钟沿触发,数据写进去的同时从另一个端口读出来做比较,省掉一个存储周期。伪代码的话,大致是:always @(posedge clk) begin if( wr_en ) mem[wr_addr] <= din; if( rd_en ) dout <= mem[rd_addr]; if( rd_en & ~wr_en ) min_val <= (dout < min_val) ? dout : min_val; end 注意rd_addr要比wr_addr提前一拍,这样流水线能压到两拍出结果。另外,紫光同创的BRAM有独立写使能,可以同时读写不同地址,一定要利用这个特性。你当前卡在哪个步骤?是综合时BRAM超了,还是时序不收敛?

  • 零号程序员

    分块大小不要死磕16×16,紫光同创的BRAM单块深度浅,换成8×8或者4×4,流水线里把读数据和算最小值合并到同一拍,能省至少一半BRAM。具体怎么合并参考上面那位的伪代码就行。

  • 电子爱好者小李

    你的问题本质是BRAM用量和吞吐率的权衡。暗通道算法里最吃BRAM的是滑动窗口的line buffer,如果你用16×16块,至少需要16行缓存,每行1920像素,按8位算就是30Kb,紫光同创的PGL系列单块BRAM只有9Kb,光line buffer就得吃掉60块以上,再加上其他模块肯定爆。我的建议是换一个思路:不做分块,而是做局部暗通道复用。把图像按行流水进来,每来一行像素,只缓存当前行和上下各一行(共三行),然后用一个3×3的窗口滑过,计算局部最小值。这样BRAM消耗只有三行line buffer,大约30块以内。虽然暗通道的窗口小了,但实时视频去雾对精度不敏感,视觉上够用。你的大赛题目要求的是实时性,不是PSNR指标,所以这种近似完全可行。流水线重排上,只需要两级:第一级读三行数据并做3×3最小值,第二级做透射率和恢复。注意三行line buffer要用双端口BRAM同时读三个地址,紫光同创的BRAM支持真双端口,一个读行N,一个读行N-1,第三个地址用LUT搭的寄存器阵列来实现。你试过这种三行缓存方案吗?如果试过还爆BRAM,那可能是你的透射率计算里用了大查找表,这部分可以改成CORDIC近似,不用查表。

  • 嵌入式小白

    分块和流水线重排这个思路没错,但紫光同创的BRAM有个坑:它的单块深度通常只有9Kb,而Xilinx常见的是18Kb或36Kb,所以同样的line buffer在国产芯片上会多占一倍块数。你提到的16×16块,保守估计光缓存16行就要吃掉50-70块BRAM,加上其他模块肯定爆。我建议放弃整块缓存,改用行流水的滑动窗口:只存当前处理行及其上下各一行(共三行),用3×3或5×5窗口算局部最小值,这样BRAM占用直接降到20块以内。代价是暗通道窗口变小,但实时视频去雾对精度容忍度很高,肉眼基本看不出差别。流水线重排上,你只需要做两级:第一级读三行数据并算出窗口最小值,第二级用这个最小值做透射率估计和去雾运算。注意紫光同创的BRAM读写时序比Xilinx慢半拍,要手动加一拍寄存器对齐。另外,你的大赛题目是2026年,可以关注一下紫光同创新出的PGL系列,部分型号的BRAM分布有改进。方便的话说说你用的是具体哪个型号和分辨率?1080p和720p的BRAM压力差很大。

  • FPGA学号3

    你遇到的BRAM瓶颈,本质是暗通道算法里滑动窗口的line buffer开销和分块处理的缓存开销在争资源。16×16分块是一种软件思维——把图像切成独立的小图块再逐个处理,但硬件上每个块都需要自己的行缓存,块数一多BRAM就炸了。更工程化的做法是放弃分块,改用全图流水的滑动窗口,配合行缓冲区的乒乓操作。具体步骤:第一步,用两个双口BRAM分别缓存当前行和上一行,每个BRAM只存一行数据,深度等于图像宽度(比如1920像素,8位灰度图就是约15Kb),紫光同创的9Kb BRAM两块拼一行正好够,两行消耗4块BRAM。第二步,再加一个单行缓存存第三行,总共6块BRAM搞定三行line buffer。第三步,构建一个3×3的滑动窗口,每个时钟周期从三行缓存里读出九个像素,用组合逻辑或三级流水线比较出最小值,这就是暗通道值。第四步,用这个最小值计算透射率和去雾结果。整条流水线只有四级:读像素、算最小值、算透射率、恢复图像,每级一拍,吞吐率就是像素时钟频率。分块处理在这里反而多余,因为行流水天然不需要整体缓存。你提的乒乓操作可以用在输入接口上——比如摄像头数据进来时,用两个FIFO做乒乓缓冲,把输入时钟域和内部处理时钟域隔开,这能省掉很多跨时钟域的处理。伪代码核心就两段:一段是行缓存写入逻辑,地址轮询写满一行就滚动;另一段是滑动窗口读取逻辑,每个时钟从三行缓存中取同一列的三个像素,再用寄存器打拍对齐成3×3矩阵。注意紫光同创的BRAM读延迟是1个时钟周期,所以取数时要晚一拍再锁存。你现在的设计乱,很可能是因为想把分块和滑动窗口混在一起,建议完全砍掉分块,只保留行流水。如果硬要保留分块,比如因为算法必须用16×16的块才能达到指标,那只能把图像尺寸从1080p降到720p,或者改用DDR3做行缓存,但那样延迟会变大,实时性可能打折扣。你的大赛评委会重点看资源利用率和帧率,而不是PSNR,所以用3×3窗口的近似方案得分反而可能更高。你目前是卡在BRAM不够还是流水线时序不收敛?说清楚我能给更具体的代码结构。

  • Web新手

    分块16×16太贪了,紫光同创的BRAM扛不住。换8×8,line buffer减半,再把暗通道计算拆成两拍:一拍读数据,一拍算最小值,中间用寄存器打平,省掉中间BRAM缓存。这样30块BRAM以内能搞定1080p,够你用了。你试过这个尺寸吗?

登录后可在本页底部提交回答

提问者

逻辑萌新实验室查看主页

描述场景与已尝试方案,更容易获得有效解答

浏览「其他」

相关问题

同分类问答

提问建议

  • 标题写清核心疑问,避免「求助」「请问」等空泛用语
  • 正文补充环境、版本、报错信息或截图
  • 先搜索本站是否已有相近问题,减少重复提问
  • 若与课程相关,请标明课时或章节便于讲师定位

技术问答

问完之后的闭环

  • 关联课程精学高频问题往往对应章节,建议回到课程补基础。
  • 产出与互助解决过程可写成笔记,帮助后续同学。

探索全站