1. 项目概述为什么我们需要一个又快又省的深度估计硬件深度估计简单来说就是让机器像人眼一样通过两只“眼睛”通常是两个平行放置的摄像头看到的世界来判断物体离我们有多远。这个距离信息是自动驾驶汽车判断前车刹车距离、机器人规划避障路径、甚至手机实现人像虚化效果的核心。其基本原理就是计算同一个物体在左右两张图像中水平位置的偏移量也就是“视差”。物体越近这个偏移量就越大物体越远偏移量就越小。听起来原理很直接但要在硬件上实时、准确地算出来却是个不小的挑战。传统的软件算法在通用处理器CPU或图形处理器GPU上跑虽然灵活但功耗高、速度慢很难满足嵌入式设备对实时性和能效的苛刻要求。比如一辆自动驾驶汽车每秒需要处理几十甚至上百帧图像每一帧的深度图计算都必须在几十毫秒内完成任何延迟都可能带来风险。因此将深度估计算法用硬件“固化”下来设计成专用的集成电路ASIC或在现场可编程门阵列FPGA上实现就成了必然选择。FPGA因其可重构性和并行计算能力成为算法验证和快速部署的理想平台。但硬件设计本身又有其铁律资源逻辑单元、内存、计算单元是有限的功耗和成本是必须控制的而速度和精度则是要拼命追求的。这就像一个带着镣铐的舞蹈我们需要在严格的约束下跳出最优美的舞步。我这次要拆解的就是一篇来自IEEE Access 2022的论文它提出了一种基于“视差融合方法”的高速低成本深度估计硬件实现方案。这个方案的核心目标非常明确在FPGA上用更少的计算量跑出更快的速度同时保持甚至提升深度图的质量。这对于将深度感知能力集成到消费级电子产品或车载系统中具有实实在在的工程价值。2. 核心思路拆解视差融合与连续平面优化在深入电路细节之前我们必须先吃透这篇论文的两个核心创新点视差融合Disparity Fusion, DF和连续平面优化Continuous Plane Refinement, CPR。理解了它们就抓住了整个设计的灵魂。2.1 视差融合用一半的力气干全部的活传统立体匹配算法为了找到一个像素点的最佳视差值通常需要在完整的视差搜索范围例如0到63内逐个计算匹配代价。这意味着对于每个像素点我们需要计算64次代价生成64张代价图然后从中选出代价最小的那个视差值。计算量和内存占用都非常大。这篇论文提出了一个大胆的假设在图像平滑区域真实视差附近的代价应该也是平滑变化的。也就是说如果一个点的真实视差是k那么即使我们只计算了k-1, k, k1这几个视差我们也能通过它们之间的代价关系推断出k很可能就是最优解。基于这个假设作者设计了一套巧妙的“分而治之”策略左图只算偶数视差2, 4, 6, ..., 64生成32张左代价图。右图只算奇数视差1, 3, 5, ..., 63生成32张右代价图。这样总的代价图数量从128张左右各64张直接降到了64张计算量砍半。注意这里有个关键细节。左右图的计算是独立的但它们的视差搜索方向是相反的。左图是在右图中向右搜索对应点而右图是在左图中向左搜索。所以“左图算偶数视差”意味着左图的每个像素只在右图中偏移偶数个像素的位置进行匹配。那么只算了一半的视差如何得到完整的0-63视差图呢这就是“视差融合”算法的妙处。它通过一个左右一致性检查来恢复丢失的视差信息。具体规则如下以左图某个像素点视差值为偶数k为例情况一检查右图中(i - (k-1), j)位置的视差值是否等于k-1。若相等则该点最终视差为k-1。情况二检查右图中(i - k, j)位置的视差值。若其值为k-1或k1即与k的绝对差为1则该点最终视差为k。情况三检查右图中(i - (k1), j)位置的视差值是否等于k1。若相等则该点最终视差为k1。如果以上三种情况都不满足则该点标记为“不一致点”留待后续优化步骤处理。这个方法的精妙之处在于它利用左右图视差图的相互校验不仅恢复了完整的视差范围还顺便完成了一次初步的误匹配剔除左右一致性检查一举两得。2.2 连续平面优化给深度图“磨皮”和“补妆”经过视差融合我们得到了一张初步的视差图但其中还存在一些“不一致点”和噪声。特别是在物体边缘、弱纹理区域或受光照变化影响的地方匹配容易出错。这时就需要“连续平面优化”出场了。它的核心思想非常符合直觉在三维空间中一个连续的表面比如一面墙、一张桌面投影到二维图像上其视差值应该是相同或缓慢变化的。反过来说图像中位于两个边缘之间的连续区域其视差也应该基本一致。CPR算法分为三步统计Statistics对于图像中的每一行找到两个边缘之间的连续区域。统计该区域内所有“一致点”即视差融合后确认有效的点的视差分布找出出现次数最多的那个视差值d_ref。优化Refinement如果该连续区域内“一致点”的总数超过阈值τ_v且d_ref的占比超过阈值τ_h那么我们就认为这个区域是一个有效的连续平面。将该区域内所有“不一致点”的视差值都用d_ref来填充。填充Filling经过优化后可能还有少数孤立的点未被处理比如位于非常小的区域或不符合平面假设。对于这些残留的“不一致点”算法会简单地赋予它最近的“一致点”的视差值。这个过程就像图像处理中的“区域生长”和“空洞填充”但它是在视差域、并且结合了边缘信息进行的因此能更智能地平滑噪声、修复错误同时对图像边缘保持得比较好避免过度平滑。2.3 整体算法流程结合以上两个核心思想整个算法的流程就清晰了代价计算输入左右RGB图像分别计算颜色、梯度、Census变换编码三种代价加权融合生成初步的代价图仅计算一半视差。引导图像滤波使用原始灰度图作为引导对每一张代价图进行滤波平滑噪声同时保持边缘。这一步能显著提升代价图的质量。胜者为王对滤波后的每一张代价图为每个像素点选择代价最小的视差值分别生成左视差图仅含偶数视差和右视差图仅含奇数视差。视差融合对左右视差图进行一致性检查与融合生成一张覆盖完整视差范围的、初步的视差图并标记出不一致点。连续平面优化基于边缘信息对不一致点进行统计、优化和填充得到优化后的视差图。中值滤波最后在垂直方向进行一次中值滤波去除可能的椒盐噪声输出最终的视差图。这个流程在逻辑上层层递进前一步的输出是后一步的输入非常适合用流水线Pipeline的方式在硬件上实现从而达到极高的吞吐率。3. 硬件架构深度解析如何把算法“烧”进FPGA纸上谈兵终觉浅绝知此事要躬行。算法的巧妙必须通过高效的硬件架构才能转化为实实在在的性能。这篇论文的硬件设计充分体现了面向硬件优化的思想下面我们分模块拆解。3.1 信息计算单元数据预处理流水线任何图像处理硬件设计的第一步都是高效的数据输入和预处理。论文中的梯度、Census变换与边缘信息计算单元承担了这个重任。输入与缓存RGB图像数据以像素流的形式输入。为了进行3x3的卷积操作如Sobel算子和边缘检测核需要缓存至少两行图像数据。设计中使用了FPGA的块RAM来构建行缓存配合一组寄存器形成一个3x3的滑动窗口。每个时钟周期窗口移动一列新的像素数据流入最旧的数据移出。并行计算RGB转灰度用于后续的梯度和Census计算。梯度计算使用Sobel算子x方向和y方向与3x3窗口进行卷积得到每个像素的梯度幅值实际论文中用的是x和y梯度差的绝对值之和。这个计算需要两个卷积器。Census变换这是一个非常硬件友好的局部特征描述子。以当前像素为中心比较其与周围8个邻域像素的灰度值如果邻域像素值更大则输出1否则输出0形成一个8位的二进制串。这个操作只需要比较器无需乘法非常适合硬件实现。边缘检测使用四个不同方向0°, 45°, 90°, 135°的3x3核对灰度图进行卷积取四个结果中绝对值最大的作为边缘强度再与阈值比较生成二值边缘图。这一步为后续的CPR提供了关键的“边界”信息。实操心得在FPGA图像处理流水线开头设计一个稳定、高效的滑动窗口生成模块是基础。要特别注意行缓存的深度与图像宽度相关和初始化的延迟。通常需要等待前N行数据填满缓存后才有有效的3x3窗口数据输出。这个“启动延迟”在系统时序设计中必须考虑进去。3.2 代价计算单元精打细算的硬件优化代价计算单元需要为每个像素、每个视差尽管只有一半计算匹配代价。这是一个计算密集型模块优化至关重要。三部分代价的硬件实现颜色代价计算左右图对应像素RGB三通道的绝对差之和。论文中为了节省硬件将除以3的操作近似为右移2位即除以4。这是一个典型的面积换精度或速度的权衡。因为颜色代价在总代价中权重较低α0.1这种近似带来的误差可以接受。梯度代价计算左右图对应像素x和y方向梯度的绝对差之和。这部分权重最高β0.7因此计算需要保持相对较高的精度。Hamming距离代价比较左右图对应像素的Census编码串。使用异或门逐位比较然后用一个加法器计算“1”的个数即汉明距离。这是纯组合逻辑速度极快。代价融合与截断将上述三项代价乘以各自的权重系数α, β, γ后相加。在硬件中乘法常用移位相加来实现。例如权重0.7约等于11.2/16可以通过(值3) (值2) (值0)来近似。最后每一项代价在相加前都会与一个阈值Tc, Tg, Th比较取较小值。这个“截断”操作非常重要可以防止个别异常值如高光点主导整个代价同时也能控制数据的位宽节省存储资源。3.3 引导图像滤波单元算法核心的硬件映射引导图像滤波是提升匹配质量的关键步骤但其计算涉及均值、方差、协方差等在硬件上实现需要技巧。均值滤波的优化GIF中需要多次对整幅图像进行均值滤波窗口半径r4。直接滑动窗口求和计算量巨大。论文采用了经典的积分图/行列和优化思想。维护一个“列和存储器”存储图像每一列在当前滑动窗口内的累加和。当窗口向下滑动一行时只需更新这个列和加上新一行的该列值减去滑出窗口的旧行该列值。窗口的总和就是这几列列和的总和。通过一个先入先出队列来管理这些列和可以每个时钟周期高效地更新窗口总和。求均值时除以窗口面积如81的操作再次用移位相加来近似右移7、8、11位的结果相加近似除以81。共享计算与近似除法对于同一幅引导图像I其均值mean(I)和方差var(I)对于所有代价图c都是相同的。因此硬件上可以设计一个共享的GIFU_I模块来计算这些公共量然后广播给多个并行的GIFU_c模块每个处理一张代价图。GIFU_c模块计算mean(c)和cov(I, c)。最棘手的除法计算线性系数a_k cov(I, c) / (var(I) ε)。除法在FPGA中是非常消耗资源的操作。论文采用了一个巧妙的近似寻找(var(I) ε)最接近的2的幂次方然后用右移操作代替除法。例如如果分母是9则近似为82^3那么除法就变成了cov(I, c) 3。虽然引入了误差但在滤波的背景下这种近似被证明是有效的且极大地节省了硬件资源。3.4 胜者为王与视差融合单元决策与校验胜者为王单元这是一个经典的“求最小值”电路。输入是32个滤波后的代价对应32个视差输出是代价最小的那个视差值。硬件上通常采用比较树的结构。第一级两两比较产生16个胜出者和它们的代价第二级再两两比较产生8个……以此类推经过log2(32)5级比较就能得到全局最小值。这种结构延迟固定且可以通过流水线化来提高吞吐率。视差融合单元这个模块执行算法3中的逻辑。输入是左视差图串行输入和右视差图需要随机访问因此设计为串行输入并行输出的缓冲模式。对于左视差图的每一个值k硬件需要同时读取右视差图中(i-k-1, j),(i-k, j),(i-k1, j)三个位置的视差值这需要右视差图有足够的行缓存和寻址逻辑然后并行进行三个条件的判断。根据判断结果通过一个优先级选择器通常条件一的优先级最高输出最终的融合视差值和一致性标志。3.5 连续平面优化与后处理单元错误的修正连续平面优化单元这是算法中最复杂的控制逻辑部分。它需要按行扫描识别边缘之间的区域并进行统计和填充。统计部分需要一组计数器来统计当前连续区域内每个视差值出现的次数。当遇到边缘或行尾时判断当前区域是否有效点数超过阈值τ_v且最大占比视差超过阈值τ_h。如果有效则输出该区域的参考视差d_ref。优化部分在统计的同时另一条路径根据当前像素的一致性标志和d_ref的有效性决定是输出原始视差、d_ref还是标记为待填充。填充部分对于最终残留的不一致点需要一个查找逻辑寻找其左右最近的一致点用该点的视差值填充。这通常需要额外的缓存和搜索逻辑。中值滤波单元最后一步是简单的垂直方向中值滤波用于去除孤立的噪声点。中值滤波的硬件实现也有成熟方案如使用比较器网络对窗口内的所有值进行排序然后取中间值。4. 关键设计抉择与工程化思考读论文不能光看它做了什么更要思考它为什么这么做以及换做我们自己设计会面临哪些抉择。4.1 为什么选择GIF而不是ADSW或SGM在立体匹配领域除了本文用的引导图像滤波还有自适应支持权重和半全局匹配等流行方法。自适应支持权重效果通常更好因为它根据颜色和距离为窗口内每个像素赋予不同的权重能更好地处理边缘。但它的计算量巨大需要为每个像素、每个视差、每个支持窗口内的像素都计算一次权重内存访问和计算复杂度都是O(窗口面积 x 视差范围)硬件资源消耗极高。半全局匹配通过多路径聚合来优化代价精度很高但同样涉及复杂的迭代和大量的中间状态存储不利于高速流水线实现。引导图像滤波它的优势在于滤波权重是通过引导图像这里是原图线性回归得到的这个计算过程可以分解为一系列可并行、可流水化的均值滤波操作。虽然一次GIF也需要多次遍历图像但它的操作是全局统一的非常适合用第3.3节所述的硬件优化方法来实现最终在精度和硬件开销之间取得了很好的平衡。结论在追求高速、低成本的嵌入式硬件实现中GIF因其计算规则、易于并行和硬件友好的特点成为了更优的选择。4.2 视差融合的“风险”与“收益”只计算一半视差最大风险在于假设不成立。在物体边缘、重复纹理或遮挡严重的区域代价函数可能不是平滑的真实视差附近的代价可能并非次优。这会导致视差融合步骤无法找到正确的匹配产生错误。论文通过两个手段来对冲这个风险代价滤波在WTA之前进行GIF平滑了代价平面使得“局部最小值”的假设更容易成立。后续优化CPR模块专门处理这些由融合失败产生的“不一致点”。通过基于边缘的平面假设和填充能够修复大部分错误。这是一种典型的系统工程思维在前级用一个快速但可能有瑕疵的方法获得一个“还不错”的初始解然后在后级用一个更鲁棒但可能稍慢的方法去修正错误。总体效率远高于每一步都追求完美。4.3 资源与速度的权衡艺术通篇论文充满了这种权衡除法变移位用精度换取了大量的DSP资源。均值滤波的优化用额外的行缓存和列和存储器换取了O(1)时间复杂度的窗口求和实现了极高的吞吐率。并行度与面积代价计算、GIF都可以高度并行。但并行32个GIFU_c模块会占用大量资源。设计中通过共享GIFU_I模块以及可能采用分时复用部分计算单元的策略来控制总面积。数据位宽每一步计算后都需要谨慎地确定数据的位宽防止溢出同时避免不必要的位宽浪费。论文中提到的阈值截断也起到了控制位宽的作用。5. 性能评估与对比用数据说话论文在Kintex-7 FPGA上实现了整个设计并使用权威的Middlebury立体匹配数据集进行了测试。5.1 精度对比作者主要在两个数据集上对比Middlebury V2包含“Tsukuba”, “Venus”, “Teddy”, “Cones”四组标准图像。评价指标是“坏点率”Bad Pixel Percentage即视差误差大于1个像素的点的比例。论文提出的方法在“所有区域”的平均坏点率为6.36%。与早期FPGA设计相比坏点率通常在10%-20%精度有显著提升。与同期其他基于GIF的FPGA设计相比在相近或更少的资源消耗下达到了最低的坏点率。Middlebury V3包含更多复杂场景和光照变化。在更严格的评价指标下误差大于阈值τ_d的点的平均绝对误差该方法也展现出了优于其他对比方案的鲁棒性证明其CPR模块对光照噪声有一定的耐受性。5.2 速度与资源对比这是硬件设计的核心指标帧率在110MHz的工作频率下处理分辨率约为450x375的图像达到了118 FPS。这意味着处理一帧图像不到8.5毫秒完全满足实时性要求。吞吐率达到了6960 MDE/s每秒百万次视差估计。这个指标综合了帧率和图像分辨率是衡量立体匹配硬件性能的通用指标。资源占用在Kintex-7 XC7K325T FPGA上主要资源占用如下表所示与同类设计对比设计LUTs寄存器BRAMsDSPs帧率 (FPS)坏点率 (%)本文设计~42K~28K~120~101186.36设计A (2019)~38K~26K~150~50~60~6.5设计B (2018)~25K~18K~90~5~90~9.7解读可以看出本文设计在资源使用上非常经济尤其是DSP用于乘法用得很少这得益于大量的移位和加法优化。在取得最高帧率的同时保持了最低的坏点率实现了“高速”与“低成本”的兼得。5.3 不同配置下的权衡分析论文还做了一个很有价值的对比如果改变视差融合中“跳过的”视差数量结果会怎样DF64计算全部64个视差即传统方法DF仅作一致性检查。精度最高但计算量最大。DF32计算32个视差奇偶分离即本文采用方案。精度与DF64非常接近。DF21只计算21个视差间隔更大。精度明显下降。这个实验有力地证明了DF32方案在精度和计算复杂度之间的完美平衡点。DF21虽然计算量更小但丢失了太多信息即使融合算法也无力回天。6. 总结与展望从论文到产品的距离这篇论文为我们展示了一个非常扎实的、面向硬件的立体匹配算法设计范例。它不仅仅是提出一个新算法更是从算法创新、硬件架构、模块优化到实验验证的全流程展示。我个人在实际工程中的体会是将这样的研究转化为产品还需要考虑几个现实问题输入适应性论文使用了校正好的标准数据集。实际应用中来自摄像头的图像必须经过严格的立体校正确保左右图像行对齐。校正模块本身也需要硬件实现并会增加系统延迟。参数固化与调优算法中有多个阈值Tc, Tg, Th, τ_v, τ_h, ε等。在FPGA中它们通常被设计成可配置的寄存器以便针对不同场景室内、室外、不同光照进行微调。如何设计一个高效的参数调试接口也是工程的一部分。系统集成与功耗这个深度估计模块最终要作为一个IP核集成到更大的SoC系统中。需要考虑与图像传感器接口、DDR内存控制器、以及后续处理单元如障碍物检测、SLAM的数据交互。同时需要精确评估其功耗特别是在电池供电的设备上。向ASIC迁移FPGA验证成功后的下一步往往是流片做成专用芯片以进一步降低成本、提升能效。在ASIC设计时需要将FPGA中的BRAM用更小的SRAM宏单元替代优化数据通路进行严格的时序和功耗签核。总而言之这篇论文提供的不仅仅是一个具体的深度估计硬件设计更是一种在资源、速度和精度三角之间进行权衡与优化的方法论。它告诉我们通过深入的算法分析与巧妙的硬件架构协同设计完全有可能在严格的约束下打造出性能卓越的视觉处理引擎。这对于任何从事嵌入式视觉、边缘AI硬件开发的工程师来说都具有极高的参考价值。