我们电赛队伍选了高云GW2A系列做视频边缘检测,现在代码写完综合出来LUT占用超过120%,DSP倒是还有富余。高斯滤波用3×3窗口,Sobel用两个方向核,都是最常规的写法。想请教有实战经验的大佬,在不换更大FPGA的前提下,有哪些工程上能落地的资源优化手段?比如能不能把高斯和Sobel合并成一个算子?还是改用行列分离的线性滤波结构?另外行缓存用BRAM还是分布式RAM更省?求具体方案,急!
FPGA大赛备赛只剩两周,用高云FPGA做实时视频边缘检测,Sobel算子加高斯滤波的LUT资源爆了,怎么在不换芯片的前提下硬优化?
4 个回答

两周时间确实紧,先别急着重构整个算法,按性价比排序来。你LUT爆到120%,最可疑的是3×3窗口的移位寄存器写法——很多人用二维数组,综合器会展开成9个独立的寄存器组,每个像素要搬9次,LUT自然爆炸。正确做法是行缓存加一维移位寄存器:两行BRAM(高云GW2A的BRAM够用),第三行用LUTRAM,每来一个像素只移一次,这样窗口逻辑从9份缩到1份。高斯和Sobel合并成单一5×5核是可行的,但注意高斯可分解为行和列两个一维核,和Sobel合并后其实是个4×4或5×5的二维核,直接做乘法器会吃掉DSP——你DSP有富余,那就用DSP做,LUT只留加法树。另外检查综合报告里有没有冗余逻辑被保留,比如Sobel的Gx和Gy都算出来但只用了模值,可以把平方根近似成绝对值加和,省掉一个乘法器。最后,行缓存用BRAM,窗口用LUT移位寄存器,这是标准做法,别用分布式RAM做行缓存,地址控制逻辑更费LUT。先按这个改,如果还超,把高斯核的系数量化成移位加,别用乘法器。你们用的是什么型号的GW2A?不同后缀的BRAM数量差挺多。

说下我的看法,你这个场景最该动刀的地方不是算子本身,而是数据流结构。你现在LUT爆,说明组合逻辑太多,大概率是每个像素同时做了高斯和Sobel的乘法,然后结果又各自累加。高斯3×3加Sobel两个方向核,如果分开写,等效于做了9次乘加再加9次乘加,总共18次,每次都是独立的LUT乘法器(因为你没用DSP)。但高斯和Sobel本质都是线性卷积,卷积核可以合并——高斯核先和Sobel核做二维卷积,得到一个4×4或5×5的等效核,这样每个像素只做一次卷积,乘法次数从18降到16或25,看起来没省多少,但关键是合并后可以拆成行列分离:先做行方向的一维卷积,再做列方向的一维卷积,每个方向只需要3到5个乘法器,中间结果存到行缓存里。这样LUT用量会从O(N^2)降到O(N),N是核大小。具体来说,你先把高斯核分解成行向量和列向量,比如[1,2,1]和[1,2,1]的转置,Sobel的Gx核是[-1,0,1;-2,0,2;-1,0,1],这个本身就可以拆成行向量[-1,0,1]和列向量[1,2,1]的乘积,你把它和高斯核合并,最终等效核就是两个一维核的乘积,先做行方向,结果存BRAM,再做列方向。这样DSP只用来做乘法,加法用LUT,LUT占用会大幅下降。另外,你检查下综合选项,高云的云源软件里有个retiming选项,打开它可以让综合器自动平衡流水线,有时候能省10%到15%的LUT。还有,你的Sobel如果输出是绝对值,直接用|Gx|+|Gy|,别用平方根,省DSP也省LUT。最后,行缓存用BRAM,窗口移位寄存器用LUT,这是标准方案,别反过来。你确认下你的高斯核系数是不是对称的?对称的话可以进一步用加法共享,比如[1,2,1]中间那个2可以做成左移一位,不用乘。整体上,合并算子加行列分离,LUT能降一半以上,两周时间够改。

高斯和Sobel合并成单核,行列分离,行缓存BRAM,窗口LUT移位寄存器,DSP做乘法,加法树用LUT。检查综合报告有没有冗余逻辑被保留,比如只算幅值就别平方根,用|Gx|+|Gy|。两周够改了,别拖。

先别急着改代码,把综合报告里LUT占用最高的几个模块列出来看,我赌大概率不是Sobel或高斯本身,而是你那个3×3窗口的生成方式。很多人写窗口直接用二维数组加移位,综合器会给你展开成9个独立寄存器组,每个像素进来要搬9次数据,LUT被这种搬运逻辑吃掉的量非常可观。正确做法是行缓存加一维移位寄存器:两行用BRAM(GW2A的BRAM资源够),第三行用LUTRAM,每来一个像素只在第三行里移一次,窗口逻辑从9份缩到1份,这一步通常能直接砍掉三成以上的LUT。
做完这步再考虑合并算子。高斯和Sobel都是线性卷积,可以先在高斯核和Sobel核之间做二维卷积,得到一个等效的4×4或5×5核,这样每个像素只做一次卷积。但注意别直接拿这个二维核去搭乘法器阵列,那会把DSP吃光。更好的做法是利用高斯核可分解为行向量和列向量的性质,把合并后的核也拆成行列分离的结构:先做行方向的一维卷积,中间结果存到行缓存,再做列方向的一维卷积。这样每个方向只需要3到5个乘法器,LUT用量从O(N^2)降到O(N)。你DSP有富余,就把乘法都放到DSP上,LUT只保留加法树和移位寄存器。
另外检查一下综合报告里有没有冗余逻辑被保留。比如你Sobel算出了Gx和Gy,但后面只用了模值,那平方根运算就是纯浪费——用|Gx|+|Gy|近似,能省掉一个开方模块。还有如果边缘检测只需要幅值不需要方向,Gy或Gx其中一个核可以简化。最后提醒一句,高云的IP核配置里,BRAM的行缓存深度要记得设成图像宽度+2或+3,别多留余量,BRAM位宽也按8位来,别用32位。两周时间,优先级就是:窗口结构改一改,算子合并加行列分离,最后查冗余。
你们现在窗口是用寄存器组搬的还是已经用了行缓存?这点定了才好判断下一步往哪使劲。
发表回答
登录后可在本页底部提交回答