基于FPGA的中值滤波设计————(3)矩阵模板生成模块设计

这篇具有很好参考价值的文章主要介绍了基于FPGA的中值滤波设计————(3)矩阵模板生成模块设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、功能描述 

        mid3x3模块的功能首先是根据当前中心像素点坐标生成地址,获取RAM_picture模块中的数据,接着生成我们需要的3X3矩阵模板,然后输出给后面的模块去处理,当后面的模块处理完后,再通过模块生成下一个3x3矩阵,直到把所有的像素点都遍历完。

二、端口描述和设计

        上图,先看一下我们需要哪些I/O端口?

中值滤波3×3模板,FPGA开发,中值滤波,图像处理,fpga开发

         结合图具体解析一下,

        输入信号:模块的输入信号有4个,时钟clk和复位rst_n都是全局信号,接着是flag信号,前面都有讲到代表的是一个3x3模板处理完之后的标志信号,由midfilter模块产生,输入到当前模块,然后是输入的data_in[23:0]是来自于RAM_picture的数据也就是提前存储好的图片数据;

        输出信号:address_out[31:0]控制RAM读出的数据地址,以便我们能够取到想要坐标的地址,具体的地址选取方式我们下面再讲。mid3x3_done也是标志信号,代表着一个3x3模板生成了,后面模块可以拿去用了。而c1~c9就是我们生成的3x3矩阵模板,排列方式如下。

中值滤波3×3模板,FPGA开发,中值滤波,图像处理,fpga开发

        这个排序是需要记住的,这关乎到我们后面地址的选取,还有就是我们数据是从图层的左上角为第一个点,从左往右,从上往下开始存储在RAM当中,右下角是最后一个像素点

         通过Verilog设计的端口常量如下:

module mid3x3#(

    parameter picture_size =71200,
               picture_row=200,
               picture_col=356,
               data_width   =24
)(
    input clk,rst_n,
    input flag,
    input [data_width-1:0]data_in,
    
    output reg [data_width-1:0] c1,c2,c3,c4,c5,c6,c7,c8,c9,模板矩阵
    output[31:0] address_out,
    output reg mid3x3_done
    );

三、逻辑功能设计

       逻辑功能部分的设计又可以分为两部分:坐标计数,矩阵像素点获取。

1)坐标计数

        要遍历所有的像素点,生成以当前像素点为中心的3x3矩阵模板,我们首先得知道当前像素点的坐标,怎么求这个坐标呢,很简单就是计数!这里需要产生三个寄存器:像素点计数寄存器、行计数寄存器、列计数寄存器。

    reg  [31:0] address_out_n;
    reg  [31:0] pixel_cnt;//像素点计数  
    reg         row_last;///一行结束信号
    reg  [31:0] row_cnt;//行像素点计数
    reg  [31:0] col_cnt;//列像素点计数 

        其中的address_out_n代表的是像素地址,row_last标识一行的最后一个像素点(其实可用可不用),就是在最后一个像素点的时候拉高,其他的时候全为低电平0。

        像素点计数寄存器pixel_cnt:为了知道像素点处理的进程,就是明确当前是第几个像素点了,所以需要对像素点计数,且当前像素点的计数就是当前像素点的地址address_out。解释一下,比如我们要生成的第一个3x3矩阵模板,它的中心点像素地址我们是可以直接知道的就是0(为什么是0呢?因为我们存在RAM中的地址是从0开始的),第二个我们要生成的3x3矩阵模板,它的中心点像素地址是1,以此类推,第N的矩阵模板的地址就是N-1。

        可以看到中心点还是比较好找的,地址都是跟我们的矩阵模板处理的进度或者说数量是一致的,但是除开中心点,其他点的寻找就需要坐标了。

        列计数寄存器row_cnt:代表当前模板中心像素点的横坐标,也就是在一行中处理到哪一列像素了。

        行计数寄存器col_cnt:代表当前模板中心像素点的纵坐标,也就是处理到哪一行像素了。

例如下面这图:

中值滤波3×3模板,FPGA开发,中值滤波,图像处理,fpga开发

         以黑色这个点为中心点像素,那它的坐标就是row_cnt=6、col_cnt=3。对应这里还可以简单的推一下它的地址为pixel_cnt=row_cnt+row_cnt*picture_col=6+3*10=36。其中picture_col代表的一行有多少个像素点

        对于坐标计数部分的具体Verilog设计如下:

///判断像素点处理进度/    
always@(posedge clk)
    if(!rst_n)
       pixel_cnt<=0;
     else if(flag&(pixel_cnt<=picture_size-1))       
            pixel_cnt<=pixel_cnt+1;
      else
        pixel_cnt<=pixel_cnt;
///判断在一行中处理进度/          
always@(posedge clk)        
    if(!rst_n)
    begin
     row_cnt<=0;
     row_last<=0;
    end
     else if(flag&(row_cnt<picture_col-1))    
            begin		
              row_cnt<=row_cnt+1;
			  row_last<=0;
			end
      else if(flag&(row_cnt==picture_col-1))
            begin
            row_cnt<=0;
            row_last<=1;
            end
      else
        begin
        row_cnt<=row_cnt;
        row_last<=0;
        end
///判断行处理进度/  
always@(posedge clk)        
    if(!rst_n)
     col_cnt<=0;
     else if((col_cnt<=picture_row)&(row_cnt==picture_col-1)&flag)    
              col_cnt<=col_cnt+1;
      else
        col_cnt<=col_cnt;

        这里涉及到了三个always功能描述块的使用,我们挨着挨着看:

第一个always块:主要是对pixel_cnt计数器寄存器进行累加计数,+1的条件就是当flag信号拉高且计数的值pixel_cnt小于总的像素值71200时,条件不满足时就不变。实现的逻辑是一个矩阵模板滤波处理完成之后就对计数+1,开始下一个像素处理。

第二个always块:主要是对横坐标row_cnt进行计数累加,要稍微复杂一点。实现的逻辑是当flag信号拉高且计数的值row_cnt小于一行总的像素值picture_col-1(我这里是常数356-1)时,row_cnt+1;当等于picture_col-1时就清零。简单来说就是一行的计数从零开始累加到一行的总数过后又从零开始循环。这里还对row_last进行了赋值,就是当row_cnt计数到一行的最后一个数的时候拉高,其他的时候都拉低为0。

第三个always块:主要是对纵坐标col_cnt进行计数累加,实现的逻辑是当flag信号拉高且计数的值col_cnt小于总的行数picture_row(200)时并且row_cnt等于一行总的像素值picture_col-1时,col_cnt可以+1,其他的时候都为不变。

2)矩阵像素点获取        

        要获取到矩阵模板9个点的数据我们得先获取到每个数据的地址,在前面部分基础上,我们成功的获得了模板中心点的地址pixel_cnt和横纵坐标row_cnt、col_cnt,有了中心点这两个计数器坐标,我们就可以推导出以它为中心点的3x3矩阵模板中,每一个像素点的坐标以及对应的存储地址:

c1坐标为(row_cnt-1,col_cnt-1),对应地址:c1_address=row_cnt-1+(col_cnt-1)*picture_col;

c2坐标为(row_cnt,col_cnt-1),对应地址:c2_address=row_cnt+(col_cnt-1)*picture_col;

c3坐标为(row_cnt+1,col_cnt-1),对应地址:c3_address=row_cnt+1+(col_cnt-1)*picture_col;

c4坐标为(row_cnt-1,col_cnt),对应地址:c4_address=row_cnt-1+col_cnt*picture_col;

c5坐标为(row_cnt,col_cnt),对应地址:c5_address=pixel_cnt;or=row_cnt+col_cnt*picture_col;

c6坐标为(row_cnt+1,col_cnt),对应地址:c6_address=row_cnt+1+col_cnt*picture_col;

c7坐标为(row_cnt-1,col_cnt+1),对应地址:c7_address=row_cnt-1+(col_cnt+1)*picture_col;

c8坐标为(row_cnt,col_cnt+1),对应地址:c8_address=row_cnt+(col_cnt+1)*picture_col;

c9坐标为(row_cnt+1,col_cnt+1),对应地址:c9_address=row_cnt+(col_cnt+1)*picture_col;

        大家可以一一推导一下加深印象,对应地址就是对应在RAM_picture中的存储地址,其中picture_col代表的一行有多少个像素点。

        对于矩阵模板像素点获取的设计代码如下:

reg [3:0]state;
reg [1:0] data_cnt;/等待地址稳定然后取数
always@(posedge clk)        
 begin
    if(!rst_n)
    begin
     state<=0;
     pixel_cnt<=0;
     row_cnt<=0;
     col_cnt<=0;
     mid3x3_done<=0;
     address_out_n<=0;
     data_cnt<=0;
    end 
     else case(state)
            0:begin state<=1;
                     pixel_cnt<=0;
                     row_cnt<=0;
                     col_cnt<=0;
                     address_out_n<=0;
                     mid3x3_done<=0; 
                     data_cnt<=0;
              end 
            1:begin
                mid3x3_done<=0;
                if(data_cnt==2)begin state<=2;data_cnt<=0;end else
                begin state<=1;data_cnt<=data_cnt+1;end                
                if((col_cnt==0)||(row_cnt==0))
                    c1<=24'b0;   
                else
                    begin
                    address_out_n<=row_cnt-1+(col_cnt-1)*picture_col;//取第1个点
                    c1<=data_in;
                    end            
              end
             2:begin
             if(data_cnt==2)begin state<=3;data_cnt<=0;end else
                begin state<=2;data_cnt<=data_cnt+1;end 
             if(col_cnt==0)
               c2<=24'b0;
               else
                    begin
                    address_out_n<=row_cnt+(col_cnt-1)*picture_col;//取第2个点
                    c2<=data_in;
                    end            
              end 
              3:begin
              if(data_cnt==2)begin state<=4;data_cnt<=0;end else
                begin state<=3;data_cnt<=data_cnt+1;end 
               if((col_cnt==0)||(row_cnt==picture_col-1))
               c3<=24'b0; 
               else
                    begin
                    address_out_n<=row_cnt+1+(col_cnt-1)*picture_col;//取第3个点
                    c3<=data_in;
                    end              
              end 
              4:begin
              if(data_cnt==2)begin state<=5;data_cnt<=0;end else
                begin state<=4;data_cnt<=data_cnt+1;end 
                if(row_cnt==0)
               c4<=24'b0; 
               else
                    begin
                    address_out_n<=row_cnt-1+col_cnt*picture_col;//取第4个点
                    c4<=data_in;
                    end               
              end 
              5:begin
              if(data_cnt==2)begin state<=6;data_cnt<=0;end else
                begin state<=5;data_cnt<=data_cnt+1;end 
               address_out_n<=pixel_cnt;//取第5个点中心点
               c5<=data_in;               
              end 
              6:begin
              if(data_cnt==2)begin state<=7;data_cnt<=0;end else
                begin state<=6;data_cnt<=data_cnt+1;end 
               if(row_cnt==picture_col-1)
               c6<=24'b0; 
               else
                    begin
                    address_out_n<=row_cnt+1+col_cnt*picture_col;//取第6个点
                    c6<=data_in;
                    end                
              end
              7:begin
              if(data_cnt==2)begin state<=8;data_cnt<=0;end else
                begin state<=7;data_cnt<=data_cnt+1;end 
               if((col_cnt==picture_row-1)||(row_cnt==0))
                    c7<=24'b0;   
                else
                    begin
                    address_out_n<=row_cnt-1+(col_cnt+1)*picture_col;//取第7个点
                    c7<=data_in;
                    end              
              end 
              8:begin
              if(data_cnt==2)begin state<=9;data_cnt<=0;end else
                begin state<=8;data_cnt<=data_cnt+1;end 
               if((col_cnt==picture_row-1))
                    c8<=24'b0;   
                else
                    begin
                    address_out_n<=row_cnt+(col_cnt+1)*picture_col;//取第8个点
                    c8<=data_in;
                    end                 
              end 
              9:begin
              if(data_cnt==2)begin state<=10;data_cnt<=0;end else
                begin state<=9;data_cnt<=data_cnt+1;end 
               if((col_cnt==picture_row-1)||(row_cnt==picture_col-1))
               c9<=24'b0; 
               else
                    begin
                    address_out_n<=row_cnt+1+(col_cnt+1)*picture_col;//取第9个点
                    c9<=data_in;
                    end              
              end 
              10:begin
                    mid3x3_done<=1;
                    if(flag)
                        begin
                        state<=1;
                        mid3x3_done<=0; 
                      end                     
                    else
                       state<=state;  
              end           default:state<=0;
            endcase
end

        这部分的代码十分的冗长,但逻辑其实也十分的简单,整体的结构是通过状态机的形式完成的,我详细的介绍一个状态大家就能看明白其他的状态了,因为我们取9个像素点数据的逻辑手段是一样的具有可重复性。

直接来看取第一个数的状态,当state=1

1:begin
   mid3x3_done<=0;
   if(data_cnt==2)
    begin state<=2;data_cnt<=0;end 
   else
    begin state<=1;data_cnt<=data_cnt+1;end                
   if((col_cnt==0)||(row_cnt==0))
    c1<=24'b0;   
   else
     begin
       address_out_n<=row_cnt-1+(col_cnt-1)*picture_col;//取第1个点
       c1<=data_in;
     end            
   end

        进入这个状态首先需要把标志信号mid3x3_done清零,代表矩阵还在生成当中。

        接着我们先看第二个if-else,注意有个初始条件就是当col_cntrow_cnt等于0的时候,直接将我们的c1等于0,这里怎么理解呢,其实就是实现对我们的图像边缘进行零值填充。大家想一下,当我们生成图像第一个矩阵模板时,是不是要以图层左上角第一个点为中心点,所以取出来的矩阵如下,c1=0、c2=0、c3=0、c4=0、c7=0。

中值滤波3×3模板,FPGA开发,中值滤波,图像处理,fpga开发

        同样以此类推,每当我们生成的矩阵在以图像边缘像素点为中心的时候,都需要利用这种方式进行零值填充 ,当不是以边缘点为中心时,可以利用我们前面的推导得出每个矩阵点c1~c9的地址然后取对应的像素值,比如这里的地址address_out_n<=row_cnt-1+(col_cnt-1)*picture_col。

        然后是第一个if-else,这个if-else主要的作用是利用计数寄存器data_cnt生成延时,同时进行state状态的跳转,为什么要这么设置呢?主要的原因还是在取像素点时,我们的地址需要先产生,然后过一个周期才能将像数数据读出,最后再利用c1进行锁存,换句话说就是地址address_out_n的产生到c1数据的锁存有一个时钟的间隔,保证取到了我们想要的数之后,再进行状态的跳转。

        从state=1到state=9,每个状态的设计都是按照这样的思路进行的。

        state=0状态代表着初始化和复位的效果是一样的。当进入state=10这个状态,主要的功能就是拉高标志信号mid3x3_done表示3x3的矩阵模板生成好了,接着就是等待flag信号等待后面模块滤波完成就将状态跳转到state=0,进行新的一轮的矩阵模板生成。

        还有最后一段就是将地址寄存器赋值给地址端口输出:

assign address_out=address_out_n;

四、总结

        这一章设计的内容比较的多,难度比上一章明显的提高,同时还增加了很多的细节设计。设计的点包括了,判断计数、零值填充以及状态机的使用(很简单的状态机)。希望大家能够完完全全的吃透这里面的设计,还有想说的一点逻辑思维很重要,本文大部分的语言都是在描述设计的逻辑思维,而Verilog就相当于是实现我们逻辑思维的一种工具,语法不算高深,高深的往往是逻辑思维,这是对我自己说的也是对大家说的!

        顺便补充一下完整的工程代码比较多,我会在最后一章给出,所以这里就不贴出。

        作为一名优秀的FPGA开发工程师应该知其然,亦知其所以然!文章来源地址https://www.toymoban.com/news/detail-662203.html

到了这里,关于基于FPGA的中值滤波设计————(3)矩阵模板生成模块设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于FPGA的FFT图像滤波设计

            FFT滤波就是通过傅里叶运算将图像转换到频域空间,然后在频域中对图像进行处理,最后将处理后的图像通过傅里叶逆运算将图像转会到时域空间。   在频域空间中,我们能够更好的对图像的噪声进行分析,然后找出相关规律将噪声信息去除。    本文重点讲解

    2024年04月17日
    浏览(45)
  • 基于MATLAB对彩色图像去噪的代码,均值滤波,中值滤波,空域低通滤波。

    本文主要为代码展示,未对所用算法进行较为详细的文字介绍,请读者见谅。如有建议,欢迎私信。   MATLAB调用格式为: J=imnoise(I,type)或者J=imnoise(I,type,parameters)。将类型噪声添加到灰度图像。 其中,I为原始图像,J为有噪图像,参数type和parameters用于确定噪声类型和相应的参

    2024年02月06日
    浏览(46)
  • 基于FPGA的RC滤波器设计实现

    目录 简介: 传递函数 FPGA代码实现 总结 RC滤波器的特性基本情况介绍 RC一阶低通滤波介绍;RC滤波器电路简单,抗干扰性强,有较好的低频性能,并且选用标准的阻容元件易得,所以在工程测试的领域中最经常用到的滤波器是RC滤波器。 这里我们主要认识和介绍低通滤波器。

    2024年02月16日
    浏览(35)
  • 【OpenCV-Python】:基于均值、中值、方框、双边和高斯滤波的图像去噪

    ✨博客主页:王乐予🎈 ✨年轻人要:Living for the moment(活在当下)!💪 🏆推荐专栏:【图像处理】【千锤百炼Python】【深度学习】【排序算法】 本节将对经过噪声污染的图像进行去噪,去噪方法包含 均值滤波、中值滤波、方框滤波、双边滤波和高斯滤波 。 实验所用的图

    2024年02月05日
    浏览(58)
  • m基于FPGA的积分梳状CIC滤波器verilog设计

    目录 1.算法描述 2.仿真效果预览 3.verilog核心程序 4.完整FPGA 积分梳状滤波器,是指该滤波器的冲激响应具有如下形式: 其物理框图如图所示: 可见,CIC滤波器是由两部分组成:累积器H1和H2梳状滤波器的级联。        现若假设用N级CIC滤波器来代替,每一级的滤波器系数长度

    2024年02月14日
    浏览(29)
  • 基于FPGA的FIR数字滤波器设计(quartus和vivado程序都有)。

    基于FPGA的FIR数字滤波器设计(quartus和vivado程序都有)。 附: 1.配套quartus从MATLAB系数生成直到仿真成功说明文档。 2.配套仿真出波形(图1)的视频。      

    2024年02月10日
    浏览(46)
  • m基于FPGA的半带滤波器verilog设计,对比普通结构以及乘法器复用结构

    目录 1.算法描述 2.仿真效果预览 3.verilog核心程序 4.完整FPGA         HBF模块由半带滤波器(HBF)和抽取模块组成。该模块的任务是实现2倍抽取进一步降低信号采样速率。由于HBF的冲激响应h(k)除零点外其余偶数点均为零,所以用HBF实现2倍抽取可以节省一半的运算量,对增强软

    2023年04月08日
    浏览(76)
  • 基于fpga的图像处理之3x3_5x5算子模板设计

    微信公众号上线,搜索公众号 小灰灰的FPGA ,关注可获取相关源码,定期更新有关FPGA的项目以及开源项目源码,包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 源码工程链接 https://download.csdn.net/download/m0_50111463/88529239 本

    2024年02月05日
    浏览(44)
  • 基于FPGA的UDP协议栈设计第七章_RGMII模块设计

    该部分内容主要需要掌握各种IO和时钟相关的原语使用 以太网的通信离不开PHY芯片,PHY芯片实现实现了RGMII接口到网口(RJ45)的转换, RGMII接口就是PHY芯片和FPGA之间的接口。 GMII :GMII(Gigabit Media Independant Interface),千兆MII接口。GMII采用8位接口数据,工作时钟125MHz,因此传

    2024年04月15日
    浏览(79)
  • 中值滤波,均值滤波,高斯滤波,双边滤波,联合双边滤波介绍

    看GAMES202相关课程发现闫老师讲的太好了,所以记录一下。当然文中涉及的PPT也来自闫老师的课程PPT,欢迎交流。 首先这几种都是空域的滤波方式,用于抑制图像中的噪声。它们采用的原理基本都是通过滤波核 K K K 处理含噪图像 C ~ widetilde{C} C ,得到干净的输出图 C ‾ ove

    2024年02月09日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包