zoukankan      html  css  js  c++  java
  • 基于FPGA的均值滤波算法的实现

      前面实现了基于FPGA的彩色图像转灰度处理,减小了图像的体积,但是其中还是存在许多噪声,会影响图像的边缘检测,所以这一篇就要消除这些噪声,基于灰度图像进行图像的滤波处理,为图像的边缘检测做好夯实基础。

      椒盐噪声(salt & pepper noise)是数字图像的一个常见噪声,所谓椒盐,椒就是黑,盐就是白,椒盐噪声就是在图像上随机出现黑色白色的像素。椒盐噪声是一种因为信号脉冲强度引起的噪声,产生该噪声的算法也比较简单。

      均值滤波的方法将数据存储成3x3的矩阵,然后求这个矩阵。在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标象素为中心的周围 8 个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。

     

      如图所示,我们要进行均值滤波首先要生成一个3x3矩阵。算法运算窗口一般采用奇数点的邻域来计算中值,最常用的窗口有3X3和5X5模型。下面介绍3X3窗口的Verilog实现方法。

      (1)通过2个或者3个RAM的存储来实现3X3像素窗口;

      (2)通过2个或者3个FIFO的存储来实现3X3像素窗口;

      (3)通过2行或者3行Shift_RAM的存储来实现3X3像素窗口;

      要想用实现均值滤波和中值滤波,必须要先生成3x3阵列,在Altera系列里,可以用QuatusII调用IP核——shift_RAM,具体设置参数如图所示。

     

      如上图所示,其中shiftin是实时输入的数据,taps1x,taps2x输入数据的第二三行,当数据输入成一行三个时,自动跳到下一行,最终形成每行是三列的一个矩阵,用均值滤波和中值滤波的处理方法即可,这样基本是每一个目标都可以找到自己对应的一个3x3矩阵,最后进行处理。先进入IP核里面的是最开始的的数据,所以在读出的时候也是要放在第一行。

      关于shift_ram的更详细的解释可以查看我的另一篇博文:http://www.cnblogs.com/ninghechuan/p/6789399.html

      这学期做比赛用的是国产FPGA,开发软件是PDS,这个软件说实话比较简洁,快,里面也有shift_ram IP core,但是不能设置多行(一个IP只能存储一行),不过只要你理解了shift_ram的工作的原理,完全可以用几个来实现多行处理,我通过PDS开发套件调用两个shift_register IP核来生成3X3矩阵实现3X3像素窗口。shift_register IP核可定义数据宽度、移位的行数、每行的深度。这里我们需要8bit。640个数据每行,同事移位寄存2行即可。同时选择时钟使能端口clken。

     1 shift_ram_end u_shift_ram_end1
     2      (
     3       .din       (row3_data),
     4       .clk       (shift_clk_en),
     5       .rst       (~rst_n),
     6       .dout      (row2_data)
     7      );
     8 
     9 shift_ram_end u_shift_ram_end2
    10      (
    11       .din       (row2_data),
    12       .clk       (shift_clk_en),
    13       .rst       (~rst_n),
    14       .dout      (row1_data)
    15      );

      如图所示,我们这里将行设置为8,场设置为4,所以可以明显的看到,当数据缓存到一行时,就会移位寄存到下一行,缓存两行后便会生成3X3矩阵。

      如图所示,比较缓存的第一行的数据在3x3矩阵中,占第一行,结果相同,显然是正确的。

      如图所示,第二行、第三行和最终生成的3x3矩阵作比较,结果显然是正确的。

     1 //wire     [32:0]     matrix_row1 = {matrix_p11, matrix_p12,matrix_p13};//just for test
     2 //wire     [32:0]    matrix_row2 = {matrix_p21, matrix_p22,matrix_p23};
     3 //wire     [32:0]    matrix_row3 = {matrix_p31, matrix_p32,matrix_p33};
     4 always @(posedge clk or negedge rst_n)
     5 begin
     6     if(!rst_n)begin
     7            {matrix_p11, matrix_p12, matrix_p13}  <= 33'h0;
     8          {matrix_p21, matrix_p22, matrix_p23} <= 33'h0;
     9          {matrix_p31, matrix_p32, matrix_p33} <= 33'h0;
    10     end
    11     else if(read_frame_href)begin
    12         if(read_frame_clken)begin//shift_RAM data read clock enbale 
    13             {matrix_p11, matrix_p12, matrix_p13} <= {matrix_p12, matrix_p13, row1_data};//1th shift input
    14             {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p22, matrix_p23, row2_data};//2th shift input 
    15             {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p32, matrix_p33, row3_data};//3th shift input 
    16         end
    17         else begin
    18             {matrix_p11, matrix_p12, matrix_p13} <= {matrix_p11, matrix_p12, matrix_p13};
    19             {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p21, matrix_p22, matrix_p23};
    20             {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p31, matrix_p32, matrix_p33};
    21             end
    22     end
    23     else begin
    24            {matrix_p11, matrix_p12, matrix_p13}  <= 33'h0;
    25          {matrix_p21, matrix_p22, matrix_p23} <= 33'h0;
    26          {matrix_p31, matrix_p32, matrix_p33} <= 33'h0;
    27         end
    28 end
    3x3矩阵生成

     

    1 assign post_img_Y = mean_value4[10:3];//求平均值除以8,向右移位3位

      如图所示,将3x3矩阵的中心像素的周围八个点求和,我们上面还是采取了流水线的设计方法,来增加吞吐量,然后再求平均值代替目标像素的值,从波形图上观察,计算的结果显然是正确的。这样便完成了均值滤波的仿真。

     1 //--------------------------------------------
     2 //Generate 8bit 3x3 matrix for video image processor
     3 //Image data has been processd
     4 wire             matrix_frame_vsync;    //Prepared Image data vsync valid signal
     5 wire             matrix_frame_href;    //Prepared Image data href vaild  signal
     6 wire             matrix_frame_clken;    //Prepared Image data output/capture enable clock
     7 wire     [7:0]     matrix_p11, matrix_p12, matrix_p13;//3x3 materix output 
     8 wire     [7:0]    matrix_p21, matrix_p22, matrix_p23;
     9 wire     [7:0]    matrix_p31, matrix_p32, matrix_p33;
    10 
    11 shift_RAM_3x3 u_shift_RAM_3x3
    12 (
    13     //global signals
    14     .clk                                (clk),
    15     .rst_n                                (rst_n),
    16     //Image data prepred to be processd
    17     .per_frame_vsync                    (per_frame_vsync),    //Prepared Image data vsync valid signal
    18     .per_frame_href                        (per_frame_href),        //Prepared Image data href vaild  signal
    19     .per_frame_clken                    (per_frame_clken),    //Prepared Image data output/capture enable clock
    20     .per_img_Y                            (per_img_Y),            //Prepared Image brightness input
    21 
    22     //Image data has been processd
    23     .matrix_frame_vsync                    (matrix_frame_vsync),    //Prepared Image data vsync valid signal
    24     .matrix_frame_href                    (matrix_frame_href),    //Prepared Image data href vaild  signal
    25     .matrix_frame_clken                    (matrix_frame_clken),    //Prepared Image data output/capture enable clock    
    26     .matrix_p11                            (matrix_p11),
    27     .matrix_p12                            (matrix_p12),
    28     .matrix_p13                            (matrix_p13),    //3X3 Matrix output
    29     .matrix_p21                            (matrix_p21),
    30     .matrix_p22                            (matrix_p22),
    31     .matrix_p23                            (matrix_p23),
    32     .matrix_p31                            (matrix_p31),
    33     .matrix_p32                            (matrix_p32),
    34     .matrix_p33                            (matrix_p33)
    35 
    36 );
    37 
    38 //-----------------------------------------------------------------------
    39 //step1
    40 reg     [10:0]     mean_value1, mean_value2, mean_value3;
    41 always @(posedge clk or negedge rst_n)
    42 begin
    43     if(!rst_n)begin
    44         mean_value1 <= 11'd0;
    45         mean_value2 <= 11'd0; 
    46         mean_value3 <= 11'd0;
    47     end
    48     else begin
    49         mean_value1 <= matrix_p11 + matrix_p12 + matrix_p13;
    50         mean_value2 <= matrix_p21 + 11'd0 + matrix_p23;
    51         mean_value3 <= matrix_p31 + matrix_p32 + matrix_p33;
    52     end
    53 end
    54 
    55 //step2
    56 reg     [10:0]    mean_value4;
    57 always @(posedge clk or negedge rst_n)
    58 begin
    59     if(!rst_n)
    60         mean_value4 <= 11'd0;
    61     else
    62         mean_value4 <= mean_value1 + mean_value2 + mean_value3;
    63 end
    对3x3矩阵求均值

      当然,最后为了保持时钟的同步性,将消耗的时钟延时输出。

     1 //------------------------------------------------------------
     2 //delay 2 clk
     3 reg     [1:0]     per_frame_clken_r;
     4 reg     [1:0]     per_frame_href_r;
     5 reg     [1:0]     per_frame_vsync_r;
     6 
     7 always @(posedge clk or negedge rst_n)
     8 begin
     9     if(!rst_n)begin
    10         per_frame_clken_r <= 2'b0;
    11         per_frame_href_r <= 2'b0;
    12         per_frame_vsync_r <= 2'b0;
    13     end    
    14     else begin
    15         per_frame_clken_r <= {per_frame_clken_r[0], matrix_frame_clken};
    16         per_frame_href_r <= {per_frame_href_r[0], matrix_frame_href};
    17         per_frame_vsync_r <= {per_frame_vsync_r[0], matrix_frame_vsync};
    18     end
    19 end
    20 
    21 assign post_frame_vsync = per_frame_vsync_r[1];    
    22 assign post_frame_href  = per_frame_href_r[1]; 
    23 assign post_frame_clken = per_frame_clken_r[1];
    保持时钟的同步性

      图上为灰度图像,图下为均值滤波后的图像,可以看出滤波后的图像有一些模糊,这是因为均值滤波就是将图像做平滑处理,像素值高的像素会被拉低,像素值低像素会被拉高,趋向于一个平均值,所以图像会变模糊一些。这样基于FPGA的均值滤波就完成了,下一篇我会发布基于FPGA的中值滤波处理,并且比较这两种滤波方式的优劣,最终选取较好的一种滤波方式进行图像边缘检测处理。

     

    转载请注明出处:NingHeChuan(宁河川)

    个人微信订阅号:NingHeChuan

    如果你想及时收到个人撰写的博文推送,可以扫描左边二维码(或者长按识别二维码)关注个人微信订阅号

    知乎ID:NingHeChuan

    微博ID:NingHeChuan

    原文地址:http://www.cnblogs.com/ninghechuan/p/6984705.html 

  • 相关阅读:
    设计模式-转载
    Java-类和对象基础练习
    Java-单例模式(singleton)-转载
    java-面向对象练习2
    Java-面向对象基础练习
    Java-字符串练习
    Java-数组练习5
    Java-数组练习4
    JAVA-初步认识-常用对象API(String类-常见功能-获取-1)
    JAVA-初步认识-常用对象API(String类-构造函数)
  • 原文地址:https://www.cnblogs.com/ninghechuan/p/6984705.html
Copyright © 2011-2022 走看看