第二章 视网膜模型与实现:从生物视觉到FPGA流水线

大家好,欢迎来到第二章。

上一章我们聊了视觉仿生的整体框架。这一章,咱们直接切入一个非常经典、也非常实用的模型——视网膜神经节细胞模型,以及它的数学简化版:DoG(Difference of Gaussians)算法。

说实话,我在做视觉处理项目时,最早接触的就是这个模型。为什么?因为它简单、有效,而且特别适合在FPGA上跑。你想想看,一个生物视觉系统,从视网膜到大脑皮层,信息处理的第一步就是「边缘检测」和「对比度增强」。而DoG,恰恰就是模拟了视网膜神经节细胞(Retinal Ganglion Cell, RGC)的感受野机制。

2.1 视网膜神经节细胞在干什么?

我们先简单回顾一下生物机制。

视网膜神经节细胞是视网膜的「输出神经元」。它接收来自双极细胞和水平细胞的信号,然后通过视神经传给大脑。它的核心特点是:具有中心-周边拮抗的感受野

什么意思呢?

就是说,一个神经节细胞,它的感受野分两部分:

  • 中心区域:对光刺激有兴奋(ON型)或抑制(OFF型)反应
  • 周边区域:对光刺激有相反的效应

这种结构,说白了就是做了一个「局部对比度增强」。它让细胞只对亮度变化敏感,而对均匀亮度的区域不敏感。这就是为什么我们能轻松看到物体的边缘,而不是一片模糊的灰度。

核心要点:视网膜神经节细胞 = 空间带通滤波器。它滤掉了低频(均匀区域)和高频(噪声),只保留了中频(边缘和纹理)。

2.2 Difference of Gaussians (DoG) 算法

好,生物机制讲完了。那怎么用数学模拟它?

答案就是DoG。

DoG用两个高斯函数的差来近似模拟中心-周边拮抗:

DoG(x, y) = G_σ1(x, y) - G_σ2(x, y)

其中:

  • G_σ1 是中心高斯(小标准差,对应中心兴奋区域)
  • G_σ2 是周边高斯(大标准差,对应周边抑制区域)

通常 σ1 < σ2,且两者的权重可以调整。

我习惯用这个公式来理解:DoG = 中心兴奋 - 周边抑制。说白了,就是用一个「小高斯」减去一个「大高斯」,得到一个类似墨西哥草帽的形状。

在实际图像处理中,我们怎么做?

  1. 对原图做一次高斯模糊(σ1),得到中心响应
  2. 对原图再做一次高斯模糊(σ2),得到周边响应
  3. 两者相减,得到DoG响应

就这么简单。但注意,这里有个坑——高斯核的大小和σ的选择。我刚开始做的时候,σ1和σ2选得太接近,结果啥也没检测出来。后来我总结了一个经验:σ2一般是σ1的1.5到2倍,效果比较好。

我的小技巧:如果你做的是边缘检测,σ1取1.0左右,σ2取1.6~2.0。如果你做的是纹理分析,可以适当放大σ值。具体多少,建议你跑一下仿真看看效果。

2.3 FPGA上的流水线架构设计

好了,算法讲完了。接下来是重头戏——怎么在FPGA上把它跑起来?

你想想看,DoG算法涉及两次高斯滤波和一次减法。如果按顺序做,先做第一个高斯,再做第二个高斯,最后减法,那延迟会很大。而且,中间要存一帧图像,资源消耗也大。

所以,我们需要流水线架构

我设计的架构是这样的:

输入像素流 → 行缓存 → 第一个高斯滤波器(σ1) → 第二个高斯滤波器(σ2) → 减法器 → 输出像素流

但这里有个问题:两个高斯滤波器是串行的,第二个要等第一个算完才能开始。怎么办?

我的做法是:并行化两个高斯滤波器的计算

具体来说:

  • 输入像素流同时送入两个高斯滤波器模块
  • 每个模块内部有自己的行缓存和乘加树
  • 两个模块的输出在减法器处对齐(通过延迟匹配)

这样,整个处理就是全流水线的。每个时钟周期,输入一个像素,输出一个像素。延迟只取决于滤波器的行缓存深度。

注意:两个高斯滤波器的延迟不同(因为σ不同,核大小不同)。你需要在减法器前插入适当的延迟线,确保两个数据在时间上对齐。我曾经在这里吃过亏,输出图像出现了「鬼影」,后来发现是时序没对齐。

2.4 核心逻辑:用SVG画一张架构图

光说可能不够直观。我画了一张架构图,你看看就明白了。

输入像素流 高斯滤波器 (σ1) 核大小: 5x5 高斯滤波器 (σ2) 核大小: 9x9 延迟线 (对齐时序) 减法器 DoG输出 输出 图2.1 DoG算法的FPGA流水线架构

这张图展示了核心的流水线结构。注意看,两个高斯滤波器是并行工作的,中间通过延迟线对齐时序。这样,整个系统可以做到每个时钟周期处理一个像素,吞吐量非常高。

2.5 实现细节与避坑指南

好了,架构有了。但真正写代码时,还有几个细节要注意。

2.5.1 行缓存的设计

高斯滤波需要二维卷积,所以需要行缓存。对于5x5的核,需要4行缓存;对于9x9的核,需要8行缓存。

我建议用Block RAM (BRAM)来实现行缓存。FPGA的BRAM资源很丰富,而且读写速度快。

// 伪代码示例:行缓存实现
module line_buffer #(
    parameter LINE_WIDTH = 640,
    parameter LINE_NUM = 4
) (
    input clk,
    input rst,
    input [7:0] data_in,
    input valid_in,
    output [7:0] data_out[LINE_NUM-1:0]
);
    // 用BRAM实现环形缓冲区
    // 每个时钟周期,写入新像素,同时输出当前行的数据
endmodule

2.5.2 乘加树的优化

高斯滤波的核心是乘加运算。对于5x5的核,需要25次乘法和24次加法。如果直接用DSP48,资源消耗不小。

我的做法是:利用高斯核的对称性。高斯核是中心对称的,所以可以先把对称位置的像素相加,再乘以对应的系数。这样,乘法次数可以减少到原来的1/4左右。

优化技巧:对于5x5高斯核,利用对称性后,只需要6次乘法和12次加法。资源节省了将近一半。

2.5.3 数据位宽的选择

输入图像通常是8位灰度。经过高斯滤波后,数据位宽会增大。我一般保留到16位,然后做减法。减法后的结果可能为负,所以要用有符号数。

最后,输出时再截断或做绝对值处理。具体怎么处理,取决于你的应用场景。

注意:减法后的负值不要直接截断!我见过有人直接取绝对值,结果把暗边缘变成了亮边缘,方向信息全丢了。如果你需要保留边缘方向,建议用有符号数输出,或者做线性映射到0~255。

2.6 性能评估

最后,我们看看这个架构的性能如何。

参数 数值
输入分辨率 640x480
时钟频率 150 MHz
处理帧率 480 fps (全流水线)
延迟 约12行 (取决于σ2的核大小)
资源消耗 (LUT) 约3500
资源消耗 (DSP48) 12
资源消耗 (BRAM) 8块 (每块18Kb)

你看,这个架构在150MHz下,处理640x480的图像,帧率能达到480fps。延迟只有12行左右,非常适合实时应用。

嗯,这一章的内容就到这里。DoG算法虽然简单,但它是很多高级视觉算法的基石。比如SIFT特征检测、边缘检测、甚至一些深度学习的前处理,都用到了DoG的思想。

下一章,我们会继续深入,聊聊如何在这个架构上做进一步的优化和扩展。但今天先到这里,你先把DoG的流水线吃透,后面就好办了。


专注资料整理