在对图像进行处理时经常用到矩阵操作,本篇博客介绍一下用两个FIFO生成 3x3 矩阵的方法,并对其进行验证。
要求:模拟一张分辨率为 10x5 的图片,图片的数据为 1~50,对其生成 3x3 矩阵,以便后面的图像处理。
testbench:数据的使能和数据对齐,每隔 10 个数据就空闲小段时间,每隔 50 个数据又空闲一段时间,模仿图像帧的样子,如下所示:
一、计数器行列规划
数据是 1-50,分为 10 列 5 行,而数据本身是没有行列概念的,因此要用两个计数器对数据行列规划。
第一个计数器为 col_cnt,计10下。第二个计数器为 row_cnt,计5下。这样数据就人为的划分成了10x5,如下图所示:
二、调用两个FIFO形成3行数据
1、生成一个同步 FIFO IP核,深度只要是超过 2 行的数据个数就行,例如这里一行数据个数是10个,FIFO的深度就选为32。模式选为 normal(standard)模式,其他信号都不勾选。
2、设计3x3模块,调用两次 FIFO IP 核,两个FIFO写数据相同,都是本模块进来的数据 din,两个FIFO的各种信号按后缀 1 和 2 来区分。两个FIFO的读写信号示意图如下所示:
这样设置的话,从第 3 行 din 来开始,q_1、q_2 和新进来的数据din就能形成 3 行平行数据,代码书写如下:
assign wr_en_1 = (cnt_row < 4) ? din_vld : 1'b0; //不写最后1行 assign rd_en_1 = (cnt_row > 0) ? din_vld : 1'b0; //从第1行开始读 assign wr_en_2 = (cnt_row < 3) ? din_vld : 1'b0; //不写最后2行 assign rd_en_2 = (cnt_row > 1) ? din_vld : 1'b0; //从第2行开始读
3、这样操作后生成的仿真波形如下所示:
由波形看到 din_r(din打了一拍)和 q_1、q_2 信号在第三行数据时变成了平行的三行数据。 din 信号需要打一拍是因为此次使用的FIFO模式为normal(standard)模式,给出其读使能后过 1clk 后才出数据 q,因此 din 打了一拍后就能和 q_1、q_2 对齐了。如果 FIFO 使用的是 show-ahead(first word fall through)模式则不需要对 din 信号进行打拍就能对齐。
从波形中还可以得出一些信息:
(1)来前两行数据时,din_r 和 q_1、q_2 形成的三行数据不完整,从第3行数据时才完整。
(2)din_r、q_1、q_2的顺序和我们的数据排列相比是倒的,符合人的正常思维的顺序是:q_2、q_1、din_r。
(3)形成3行数据后,由于FIFO选用的是 normal(standard)模式,din数据打了一拍,所以整个过程消耗了 1clk。
三、打 3 拍形成 3x3 矩阵
获得了上述的波形后,我们采用打拍即可完成矩阵的生成,上面说了数据是倒的,因此选择矩阵数据时把编号给正过来。
//矩阵数据选取,1clk //--------------------------------------------------- assign row_1 = q_2; assign row_2 = q_1; always @(posedge clk or negedge rst_n) begin if(!rst_n) row_3 <= 'd0; else row_3 <= din; end
这里 row_3 就是原本的 din_r,命名将顺序正过来,后面打拍也就更能理解了。
//打拍形成矩阵,矩阵顺序归正,1clk //--------------------------------------------------- always @(posedge clk or negedge rst_n) begin if(!rst_n) begin {matrix_11, matrix_12, matrix_13} <= {8'd0, 8'd0, 8'd0}; {matrix_21, matrix_22, matrix_23} <= {8'd0, 8'd0, 8'd0}; {matrix_31, matrix_32, matrix_33} <= {8'd0, 8'd0, 8'd0}; end else begin {matrix_11, matrix_12, matrix_13} <= {matrix_12, matrix_13, row_1}; {matrix_21, matrix_22, matrix_23} <= {matrix_22, matrix_23, row_2}; {matrix_31, matrix_32, matrix_33} <= {matrix_32, matrix_33, row_3}; end end
最后形成的矩阵波形如下所示:
由波形见得,最后生成的矩阵是成功的,该矩阵的观看顺序是从上到下,一列一列的看,例如第一个矩阵是:{000,000,001},第二个矩阵是:{000,000,012}。此外由于矩阵是打拍形成的,也耗费了 1clk 。至此,我们的 3x3 矩阵就生成了,总共耗费 2clk,即两个时钟周期。
四、问题引出
如果只是做到这样,其实已经能做图像处理了,但是细细品味这些波形会发现很多小问题。我们会产生一些疑问:
(1)换行时的数据很怪,如第 4 行数据的第一个矩阵是{10,10,11,20,20,21,30,30,31},这是什么鬼?
(2)换帧时的数据更怪,虽然第一帧图片前面的矩阵很多都是0,但第二帧图片前面的矩阵很多都是上一帧图片遗留的数据,怎么办?
(3)这个矩阵进行图像处理的实际效果怎么样?
(4)show-ahead(first word fall through)模式的话又会是什么情况?
(5)对于上面的问题,有改进的办法吗?
这篇博客已经有些长度了,对这些问题我们下篇博客继续分析!
参考资料:
[1]V3学院FPGA教程