4. 高斯滤波硬件架构:从系数生成到乘法器优化
高斯滤波,说白了就是加权平均。离中心像素越近,权重越大。这个思想很简单,但落地到硬件,坑不少。我最早做这个模块时,以为不就是几个乘法器嘛,结果综合出来面积超标,时序还崩了。嗯,今天咱们就把这块掰开揉碎了讲。
4.1 高斯核生成:别手算,用公式
高斯核的数学表达式大家都熟:
G(x, y) = (1 / (2πσ²)) * exp(-(x² + y²) / (2σ²))
但硬件里我们不用浮点。我的做法是:先算出理论值,再定点化。举个例子,3×3核,σ=1:
| 位置 | 理论值 | 定点(Q8) |
|---|---|---|
| (0,0) | 0.075 | 19 |
| (0,1) | 0.124 | 32 |
| (1,1) | 0.204 | 52 |
个人习惯:我一般用Q8格式(8位小数位),精度够用,乘法器位宽也不至于爆炸。σ值越大,核越平缓,定点误差影响越小。
4.2 系数量化:精度与面积的博弈
量化这一步,我吃过亏。曾经为了省面积,把系数截到4bit,结果去噪后图像出现块状伪影。后来学乖了——
- 5×5核:建议8bit量化,归一化因子用256或512
- 7×7核:可以降到6bit,但要注意边界效应
- 归一化:用移位代替除法,比如除以256就是右移8位
避坑:我曾经在7×7核上用了5bit量化,结果PSNR掉了2dB。后来发现是系数截断导致核的对称性被破坏。记住——量化后一定要检查核的对称性是否还在。
4.3 乘法器优化:CSD编码
高斯滤波最耗资源的就是乘法器。一个3×3核需要9个乘法器,5×5就是25个。怎么办?用CSD(Canonic Signed Digit)编码。
CSD的核心思想:把乘法变成移位加/减法。比如系数52,二进制是110100,CSD编码后是+1 0 -1 0 0 +1 0 0(即64 - 16 + 4)。
// 传统乘法:Y = X * 52
// CSD实现:Y = (X << 6) - (X << 4) + (X << 2)
// 只需要3个移位器和2个加法器,没有乘法器!
效果对比:用CSD后,乘法器面积减少约60%。代价是加法器多了几个,但综合下来还是赚的。
4.4 对称性利用:砍掉一半乘法器
高斯核是中心对称的。3×3核只有3个独立系数(中心、边、角),5×5核只有6个独立系数。你想想看,如果每个系数都配一个乘法器,那得多浪费?
我的做法:
- 先找出所有对称位置
- 把同一系数的像素先相加
- 最后只乘一次系数
举个例子,3×3核的角系数相同:
// 传统:4个角各乘一次
// 优化:4个角先相加,再乘一次
sum_corner = p00 + p02 + p20 + p22;
result_corner = sum_corner * coeff_corner;
这样乘法器从9个降到3个。5×5核从25个降到6个。面积省了不是一星半点。
4.5 整体架构:流水线设计
下面这张图是我常用的高斯滤波流水线架构:
流水线分5级:行缓存 → 窗口生成 → 对称求和 → CSD乘法 → 累加归一化。每级之间插寄存器,保证时序收敛。
我建议:行缓存用双端口RAM实现,窗口生成用移位寄存器。这样面积和时序都能兼顾。5×5核需要4行缓存,每行存图像宽度个像素。
4.6 关键代码片段
下面是一个5×5高斯滤波的Verilog核心代码,只展示对称求和和CSD乘法部分:
// 对称求和:5×5核有6个独立系数
wire [15:0] sum_c0, sum_c1, sum_c2, sum_c3, sum_c4, sum_c5;
assign sum_c0 = p22; // 中心
assign sum_c1 = p12 + p21 + p23 + p32; // 边
assign sum_c2 = p02 + p20 + p24 + p42; // 角
assign sum_c3 = p11 + p13 + p31 + p33; // 内边
assign sum_c4 = p01 + p10 + p14 + p41; // 内角
assign sum_c5 = p00 + p04 + p40 + p44; // 外角
// CSD乘法:系数52 = 64 - 16 + 4
wire [23:0] mul_c1;
assign mul_c1 = (sum_c1 << 6) - (sum_c1 << 4) + (sum_c1 << 2);
注意:移位后位宽会增长。比如8bit输入左移6位变成14bit,累加后需要24bit。别把位宽算小了,否则数据溢出你会查很久。
4.7 性能与资源权衡
| 优化策略 | 乘法器节省 | 加法器增加 | 时序影响 |
|---|---|---|---|
| 对称性利用 | 60%~75% | 少量 | 无 |
| CSD编码 | 100%(无乘法器) | 中等 | 路径变长 |
| 两者结合 | 接近100% | 较多 | 需插流水线 |
我个人推荐两者都用。对称性利用是白送的收益,CSD编码虽然增加加法器,但综合下来面积还是比乘法器小。如果频率要求高,就在CSD乘法器内部再插一级流水线。