面试官问到了我项目里的一个细节,让我手撕Verilog实现基于AXI4-Stream的实时视频去雾加速器,然后追问了暗通道先验算法里导向滤波的窗口大小怎么选。我项目里用的11×11,但他说太大,BRAM和DSP都扛不住,让我解释为什么不是7×7或15×15,还问边界怎么处理。有没有大佬指点一下,窗口大小选择的核心权衡是什么?边界像素的导向滤波怎么用流水线实现?
2026年FPGA校招,面试官问如何用Verilog实现一个基于AXI4-Stream的实时视频去雾加速器,暗通道先验算法中导向滤波的窗口大小怎么选?
提问
回答 14

面试官问窗口大小其实是在考察你对面积和效果的平衡感。11×11是很多论文里的默认值,但FPGA上BRAM和DSP都是硬资源,11×11意味着你需要缓存至少11行数据,每个像素的滤波运算还要做大量乘加。如果视频是1080p,一行1920像素,11行就是21120个像素的BRAM消耗,加上导向滤波本身需要计算均值和协方差,DSP数量直接跟窗口内像素数成正比。7×7能省将近60%的行缓存和DSP,但去雾后边缘可能会有点伪影;15×15效果更平滑,但资源可能翻倍都不止。我的建议是:先看你的目标分辨率,如果是720p以下且BRAM吃紧,7×7完全够用;如果是1080p且你还有余量,9×9是个不错的折中。边界处理一般用镜像填充,因为复制填充会在边界产生明显的块效应,而且镜像填充在硬件上只需要额外加一组地址反转逻辑,不增加行缓存深度。流水线上,导向滤波的关键是让均值滤波和协方差滤波并行,用一个双端口BRAM同时读写当前窗口和下一行数据,这样每个时钟都能出一个像素结果。你项目里用11×11被说太大,很可能是没做资源估算,面试时能当场画出资源占用公式会加分。你用的FPGA具体是哪家的?不同厂家的BRAM块大小差异会影响行缓存的实现方式。

窗口大小选7×7或9×9就够,11×11是论文党不爱考虑资源才用的。边界镜像填充,流水线注意行缓存深度跟窗口高度成线性关系,别超BRAM上限就行。

面试官追问窗口大小,本质是让你现场做一次资源与效果的trade-off。你先明确分辨率:假设1080p,11×11的行缓存需要111920每个像素的位宽,再考虑导向滤波里每个像素需要存均值和方差两个值,BRAM占用一下就上去了。换成7×7,行缓存降为7行,DSP用量从121个降到49个,效果损失在大部分场景下肉眼不可见。边界处理我推荐镜像填充,因为复制填充会让边界像素的滤波结果偏向当前值,导致去雾后边界出现光晕。流水线实现时,可以设计一个三级流水:第一级计算窗口内像素和与平方和,第二级计算均值和协方差,第三级输出滤波结果。注意每级之间用寄存器打拍,避免组合逻辑过长。你项目里用的视频源是8bit还是10bit?这个会影响你BRAM的位宽配置。

面试官问窗口大小,其实是想看你在资源约束下有没有工程直觉。11×11在论文里常见,因为暗通道先验的导向滤波效果确实跟窗口半径成正比,但FPGA上每增加一行窗口高度,行缓存就要多占一整行像素的BRAM。1080p下1920×11个像素,每个像素如果是8bit灰度图就是16896字节,如果是RGB24那直接翻三倍。7×7能省差不多一半的BRAM,而且对去雾效果来说,大部分室外场景的透射率图在7×7窗口下已经足够平滑,边缘伪影靠后续的soft matting或者guide filter本身的保边特性就能压住。边界处理我推荐镜像填充,复制填充会让边界像素的滤波结果偏向最近的有效值,导致去雾后天空区域和物体交界处出现一圈亮边。流水线实现时,行缓存可以用双口BRAM做乒乓操作,导向滤波的均值计算拆成两级累加:第一级做窗口内像素和与平方和,第二级做除法。注意除法器如果直接用IP核会占很多LUT,可以改成移位近似或者查表法。你项目里视频源是YUV还是RGB?这个会影响你行缓存的位宽设计。

窗口大小这件事,我当年校招也被问过,后来在项目里踩过坑才想明白。面试官说11×11太大,不是因为他觉得11×11效果不好,而是因为在AXI4-Stream的实时架构里,窗口大小直接决定了你的行缓冲深度,而行缓冲深度又决定了你能支持的视频分辨率上限。比如你做一个1080p@60fps的去雾加速器,每帧时间大约是16.67ms,一行数据只有不到30us的传输时间,如果你的导向滤波窗口是11×11,那你就需要至少11个行缓冲,每个行缓冲用BRAM实现,一个1080p的RGB行缓冲大概需要1920×24=46080bit,11个就是506880bit,这还没算你导向滤波里计算均值和方差需要的额外存储。而7×7只需要7个行缓冲,资源直接省36%。但为什么不用更小的比如5×5?因为暗通道先验的导向滤波本质上是在做一个局部均值滤波,窗口太小会导致透射率估计的噪声很大,去雾后的图像会有大量斑块。所以7×7到9×9是个比较常见的折中区间。边界处理的话,镜像填充在硬件上实现最简单:你只需要在行缓冲的读写地址上做一点反向映射,比如第一列像素的左边邻居用第二列,第二列左边用第三列,这样不用额外存边界数据。流水线实现建议把导向滤波分成三步:第一步做行缓冲写入和窗口数据对齐,第二步做窗口内累加运算,第三步做除法与输出。每步之间用valid-ready握手信号做流控,这样不会丢帧。你面试的时候如果能主动说出这些资源计算和时序约束的细节,面试官会觉得你是有过真实工程经验的。另外想问一下,你项目里用的AXI4-Stream时钟频率大概多少?这个会影响你行缓冲的读写带宽设计。

窗口大小选7×7或9×9就行,11×11是论文党用的,面试官嫌费BRAM。边界镜像填充,流水线注意行缓冲别爆了。你视频是1080p还是720p?这个会影响BRAM够不够用。

面试官嫌11×11大,其实不是嫌效果不好,是嫌你行缓存堆太狠。1080p下一行1920像素,RGB888就是1920x24bit,11行就是11倍,BRAM直接吃掉小半块芯片。7×7的话行缓存降到7行,DSP也从121降到49,大部分室外场景去雾效果差异肉眼几乎看不出来。边界我推荐镜像填充,复制填充在天空和物体交界处容易出现一圈亮边。你项目里用的视频源是8bit还是10bit?这个会影响BRAM位宽配置,10bit的话11×11基本就别想了。

窗口大小这块,面试官不是真要你背一个数字,而是看你能不能当场做资源与效果的trade-off。你先明确分辨率,假设是1080p,11×11的行缓存需要11行,每行1920个像素,每个像素如果是灰度图就是8bit,如果是RGB24就是24bit,BRAM占用一下就上去了。换成7×7,行缓存降为7行,DSP用量从121降到49,效果损失在大部分室外场景下肉眼不可见,因为暗通道先验的透射率图本身在平滑区域变化很慢,边缘靠导向滤波的保边性就能压住。边界处理我推荐镜像填充,复制填充会让边界像素的滤波结果偏向最近的有效值,导致去雾后边界出现光晕。流水线实现时,可以设计一个三级流水:第一级用行缓存和窗口滑动寄存器阵列收集窗口数据,第二级计算窗口内像素和与平方和,第三级算均值和协方差然后输出。注意每级之间用寄存器打拍,避免组合逻辑过长。你项目里用的视频源是8bit还是10bit?这个会影响你BRAM的位宽配置和DSP的位宽对齐。

面试官问导向滤波窗口大小,本质上是在考察你对面积、时序和效果三者的平衡能力,不是让你背一个值。11×11在论文里常见,因为暗通道先验的导向滤波效果确实跟窗口半径成正比,半径越大,透射率图越平滑,去雾后天空区域越均匀,但代价是BRAM和DSP直线上升。FPGA上每增加一行窗口高度,行缓存就要多占一整行像素的BRAM。1080p下1920×11个像素,每个像素如果是8bit灰度图就是16896字节,如果是RGB24那直接翻三倍。7×7能省差不多一半的BRAM,而且对大部分室外场景,透射率图在7×7窗口下已经足够平滑,边缘伪影靠导向滤波本身的保边特性就能压住。那为什么不用15×15?因为15×15的行缓存是15行,BRAM消耗是7×7的两倍多,而且DSP数量从49变成225,很多中低端芯片根本塞不下。边界处理我推荐镜像填充,因为复制填充会让边界像素的滤波结果偏向最近的有效值,导致去雾后天空区域和物体交界处出现一圈亮边。镜像填充在硬件上只需要额外加一组地址反转逻辑,不增加行缓存深度。流水线实现时,行缓存可以用双口BRAM做乒乓操作,写端口接收AXI4-Stream的像素流,读端口同时读出窗口所需的N行数据。导向滤波的均值计算拆成两级累加:第一级做窗口内行累加,用一个加法树把当前窗口内所有像素求和;第二级做列累加,把上一级的行和再累加得到窗口总和。这样做的好处是每个时钟周期只更新一个像素的累加值,不用每次重新算整个窗口,流水线深度大概在10到15拍之间。你项目里目标分辨率是1080p还是4K?如果是4K,7×7可能都勉强,得考虑用DDR做行缓冲或者降分辨率处理。

面试官说11×11太大,核心不是效果不行,是行缓存太吃BRAM。你想想1080p分辨率的11行RGB888,BRAM直接吃掉小半块芯片。7×7行缓存少4行,DSP从121降到49,去雾效果肉眼几乎看不出区别。边界用镜像填充,复制填充容易在天空边缘搞出一圈亮边。你视频源是8bit还是10bit?这个会影响BRAM位宽配置。
发表回答
登录后可在本页底部提交回答
