今年准备参加FPGA大赛,选题是实时人脸检测系统,打算用Zynq做。现在卡在Haar-like特征计算那一步,用HLS实现但延迟太高,帧率上不去。有没有学长学姐分享下怎么优化积分图计算和分类器级联的流水线?PL侧资源有限,不想全用DSP,有什么技巧?
2026年FPGA大赛备赛,用Zynq做实时人脸检测,Haar-like特征计算太慢怎么优化?
提问
回答 4

哈,积分图慢是经典坑了。别死磕HLS,试试把积分图计算拆成行累加+列累加两趟流水,每趟只用BRAM做行缓存,DSP基本不用动。级联那块,早期弱分类器直接跳过积分图查表,用简单像素差先快速拒绝非人脸区域,能省一大半计算量。你用的哪个Vivado版本?HLS里循环流水没加pipeline directive吧?

先把问题拆开看:积分图慢在哪。如果是整帧扫一遍才算出积分图,那确实慢。常见做法是分块流水——把图像切成若干tile,每个tile用两个行缓存做滑动窗口积分图,这样PL侧BRAM消耗可控,而且tile之间可以流水处理,帧率翻倍不难。另一个关键是分类器级联的早期淘汰:前几级用粗粒度特征(比如简单的哈尔特征变体,只用加减法)先筛掉80%以上的非人脸窗口,后面精细分类再用完整积分图查表。别一上来就把所有级联都布在PL上,PS侧跑前两级弱分类器,PL只跑最后几级高精度分类,这样PL资源压力小很多。HLS实现的话,注意循环展开因子别设太大,否则布线拥塞反而降频。我之前做类似项目时,把积分图数据位宽从32位缩到24位(因为人脸检测精度对低位宽不敏感),DSP消耗直接砍半。你目前PL侧用了多少LUT和BRAM?报个占用率,可能还有优化空间。

HLS延迟高多半是循环没做数据重用。积分图计算的核心是连续行累加,你用HLS写两层for循环时,记得把内层循环加上`#pragma HLS PIPELINE II=1`,并且用数组partition把行缓存拆成多个bank,避免读写冲突。另外,别用float算特征值,全部转成定点整数运算,DSP和LUT都能省。级联部分,考虑把前几级放在PS用NEON做,PL只做积分图加速和最后几级高阈值分类,这样资源分配更灵活。你用的是OV5640摄像头吗?分辨率如果降到VGA以下,帧率压力会小很多,初期可以先调低分辨率验证流程。如果还卡,试试把积分图从32位降到16位,代价是检测距离变近,但对大多数demo场景够用了。

其实你这个问题,关键不在于HLS写得对不对,而在于你打算让积分图在PL里算到什么程度。很多备赛的人一上来就想把整张图的积分图全在PL里算完,然后给后面的级联分类器用,结果BRAM和DSP全爆了。我建议你换个思路:积分图不要一次性算完整张图的。Haar-like特征计算其实只关心那些被级联分类器选中的窗口,而窗口位置是由滑动窗口机制决定的。你先在PS端跑一个粗粒度的滑动窗口调度,每次只把当前窗口对应的那一小块区域的积分图通过AXI-Stream传给PL去算,PL只处理这一小块,算完立刻做特征提取和分类判决。这样PL的片上缓存只需要存一两个窗口的数据量,BRAM占用能压到非常低。缺点就是PS和PL之间的通信开销会变大,但如果你用DMA传输,并且把窗口大小控制在16×16或者24×24这种级别,带宽是完全够的。这个思路在往届大赛的获奖作品里出现过,叫部分积分图加速。你试过把窗口拆小来算吗?如果没试过,可以先用纯PS模拟一下这个流程,看看帧率瓶颈到底在传输还是计算上。另外提醒一句,HLS里用float算Haar特征值是绝对要避免的,所有特征值比较都转成整数移位运算,DSP使用量能降一个数量级。你目前打算用哪个人脸检测库的级联参数?OpenCV那个默认的级联文件里特征阈值是浮点数,记得先量化成定点数再用。
发表回答
登录后可在本页底部提交回答
