生成3x3矩阵(3):shift ip核

  前两篇博客整理了双 FIFO 生成 3x3 矩阵的方法,本篇博客整理一下 Quartus II 软件下的 shift ip 核及如何生成 3x3 矩阵。

  要求:模拟一张分辨率为 10x5 的图片,图片的数据为 1~50,用 Verilog 对其生成 3x3 矩阵,以便后面的图像处理。

     testbench:数据的使能和数据对齐,每隔 10 个数据就空闲小段时间,每隔 50 个数据又空闲一段时间,模仿图像帧的样子,如下所示:

 

 

一、Shift IP 核原理解析

  还是直接拿官方例程来说明吧。在官方手册上,展示了一个案例,首先是配置说明:

  这段配置在 Shift ip 核中的具体设置如下图所示:

  由此进行仿真可得到如下波形:

  官方解释:“ 这个例子展示的效果为:当全部 12 个数据都移到移位寄存器中时,如何同时使用第 1 - 4 - 7 - 10 个数据(其次是第 2-5-8-11 个和第 3-6-9-12个数据)。”

  看到这肯定是一脸懵逼的,完全不知道他表达的什么意思,因此我们还是自己再梳理一下图中的信息:

  1、有 12 个数据作为 shift ip 核的输入即 shiftin信号。

  2、和 shiftin一起的还有使能信号 clken,clken 和 shiftin是对齐的。

  3、出来了 4 串数据。shiftout、taps0x,taps1x,taps2x,taps3x,其中 shiftout 信号和 taps3x信号完全一致。

  4、有一个异步清 0 信号aclr,当其拉高有效时,出来的 4 串数据立马为 0。

  得到这些信号后稍微清楚了一点,但还是不太理解,那就继续看数据手册:

  这个示意图解释了 shift ip 核的内部原理。shiftout 信号和 taps3x信号相同。进去 1 串数据就出来平行的 4 串数据,f8 、13、b5、54在时序上是同一时刻出来的,同样的 b8,84,3b,0e是同一时刻出来的,d0,67,6e,44也是同一时刻出来的。由此我们可以看出 shift ip 核很像是一个 RAM,但是这个 RAM 里面有好几道沟槽,当一个沟槽填满后就转移到下一个沟槽,同时每个沟槽都有一个接口引出来,利用这些沟槽的接口就能做很多事情了,例如轻松的实现 3x3、5x5等矩阵。

  这个图理解了,但实际运用时还是会迷糊,因为看起来 shiftin 在最上面,而最下面的数据反而是最开始进去的。如果是图片数据,那完全就是倒过来了,此外shiftin的位置也比较模糊,因此我制作一张倒过来的图,方便后面生成 3x3 矩阵时的理解。

  由于 shiftout 和 taps3x 信号是完全相同的,因此没有画出,实际使用时也不需要使用 shiftout 信号。而 shiftin 信号在官方原版图中容易让人误解,正确的位置如图所示。倒过来后就清楚的知道,最先开始的数据在左上角,就像一张图片的第一个像素一样,后面的像素顺序排列,排满一行换下一行,而最下面的信号则是shiftin,即端口中的输入信号。

 

二、Shift IP 核生成 3x3 矩阵

1、IP核生成

(1)打开 Quartus II 的 IP核生成向导,输入 shift,点击如图所示的 IP核并命名。

 (2)本次设计是仿真 10x5 像素的图片,数据为 8bit,因此位宽选择为8,taps 选择为 2,即 2 个 taps 和 din 就已经满足 3 条平行数据了。默认是未勾选 “taps分组” 选项,这样出来的是一个大 taps,而我们需要的是多个 taps 数据,所以必须勾选上 “taps分组” 选项。taps之间的距离为一行的数据个数 10。再勾选时钟使能接口,这个实际上就是写使能。异步清 0 信号不用勾选,这里用不到。顺便说一下,是没有读使能的,ip核内数据存储到一定数量就会自动吐出。

 

2、IP核调用

shift_ip u_shift_ip
(
    .clken                  (din_vld                ),
    .clock                  (clk                    ),
    .shiftin                (din                    ),
    .shiftout               (                       ),
    .taps0x                 (taps0x                 ),
    .taps1x                 (taps1x                 ) 
);

  到这一步实际上相当于完成了之前双 FIFO 法生成 3x3 矩阵的 “IP核调用 + 行列计数规划 + FIFO读写信号设置”,只能说 shift ip 核太适合用来生成矩阵了。

3、生成3x3矩阵

  和双 FIFO 的 show-ahead 模式完全一样,就是要注意一下矩阵的数据选取,脑子得转个 180 度的弯来,一旦转过来了就非常简单,没转过来的话就难理解了。

//矩阵数据选取
//---------------------------------------------------
assign row_1 = taps1x;
assign row_2 = taps0x;
assign row_3 = din;

//打拍形成矩阵,矩阵顺序归正
//---------------------------------------------------
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

 

三、仿真分析

  此次仿真脚本和之前的双 FIFO 是完全一样的,即模拟一张 5x10 分辨率的图片,最终波形如下所示:

   波形是对齐了的,还是和双 FIFO 一样再来分析一下换行和换帧的情况吧。

1、换行数据的问题

  取第4行数据的第一个矩阵来看,其数据为{11,11,11,21,21,21,30,30,31},数据主要是复制了本矩阵的最后一列,即图像数据的第一列。此外还借用了 2 次上一行最后一个矩阵的 1 个数据。和 show-ahead 模式的双FIFO法是一模一样的情况。

  实验推理:图像最左边出现一个不怎么违和的竖条,隐隐约约像是第一列的复制。

2、换帧数据的问题

  换帧后一开始的矩阵为{31,31,31,41,41,41,50,50,1},借用了上一帧图片末尾的数据。 整个第一排矩阵的数据都是借用了上一帧图片末尾的最后两行数据。

  实验推理:最上边出现一个违和的横条,隐隐约约像是图片最下边的图形。

 

四、实际上板

  这次选择一张最下边有一些白点的图片,以均值滤波的实现来测试这次的 3x3 矩阵效果。关于均值滤波后面会单独拿出来讲解。原图如下:

  经过处理后得到如下图片:

  隐约看到最左边有一条模糊的线,但不怎么违和。而最上边出现了一些白色线段,刚好对应了最下方的那些白点。实验最终和我们的推理一致。

 

五、后记

  shift ip 核生成 3x3 矩阵比双 FIFO 简单太多了,代码量极少。但是它也有局限性,如果要改进为边界补 0 或边界复制的话还不如就用 双FIFO 来实现。但 shift ip 核胜就胜在简洁,而且我们做图像处理时不会在乎边界的那一丁点问题,重点还是关注图像处理算法本身以及最后实现的图像整体效果。

  在 ISE 和 Vivado 中其实也有 shift ip 核,和本篇博客略有差异。关于生成 3x3 矩阵的方法就整理到这,足够用了。

 

 

参考资料:

    [1]CrazyBingo 图像处理教程

    [2]NingHechuan 图像处理教程

posted @ 2020-03-03 19:06  咸鱼IC  阅读(5730)  评论(3编辑  收藏  举报