查看: 2200|回复: 0

(六)中值滤波法算法实现

[复制链接]
  • TA的每日心情
    无聊
    2021-4-7 11:23
  • 签到天数: 27 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2020-1-27 10:55:34 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 雪孩爱雪 于 2020-1-27 22:48 编辑

    背景知识:
       中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内
    的所有像素点灰度值的中值.
       中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波
    的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让
    周围的像素值接近的真实值,从而消除孤立的噪声点。方法是用某种结构的二维滑动模板,
    将板内像素按照像素值的大小进行排序,生成单调上升(或下降)的为二维数据序列。二维
    中值滤波输出为 gx,y=med{f(x-k,y-l),(k,lW)} ,其中,f(x,y)g(x,y)分别为原始图像和
    处理后图像。W 为二维模板,通常为 3*35*5 区域,也可以是不同的的形状,如线状,圆
    形,十字形,圆环形等。
      中值滤波法对消除椒盐噪声非常有效,在光学测量条纹图象的相位分析处理方法中有特
    殊作用,但在条纹中心分析方法中作用不大。中值滤波在图像处理中,常用于保护边缘信息,
    是经典的平滑噪声的方法。
    要得到模板中数据的中间值,首先要将数据按大小排序,然后根据有序的数字序列来找
    中问值。中值滤波排序的过程有很多成熟的算法,如冒泡排序、二分排序等,大多是基于微
    机平台的软件算法,而适合硬件平台的排序算法则比较少。
    FPGA 中值滤波实现方法:

    360截图16570131265549.png
    如上所示,为一个 3x3 的图像模板,
    第一步:
    分别对三行像素进行排序:
    L11,L12,L13 得到 L1maxL1midL1min
    L21,L22,L23 得到 L2maxL2midL2min
    3)由 L31,L32,L33 得到 L3maxL3midL3min
    第二步:
    分别对三行像素中的 3 个最大,3 个中间和 3 个最小分别进行排序:
    L1maxL2maxL3max 得到 Lmax_maxLmax_midLmax_min
    2)由 L1midL2midL3mid 得到 Lmid_maxLmid_midLmid_min
    3)由 LminL2minL3min 得到 Lmin_maxLmin_midLmin_min

    第三步:对最大的最小(Lmax_min),中间的中间(Lmid_mid)以及最小的最大(Lmin_max)
    进行排序(例:由 Lmax_minLmid_midLmin_max 得到 midian)。
    FPGA 的算法实现步骤基本如此。

    FPGA 平台搭建:
    方法 1:
    通过 R/G/B 通道形成单色通道进入中值滤波器实现灰度图像的中值
    滤波的系统构建。

    方法 2
    首先将 RGB 图像转换成 Ycbcr 图像,Y 通道进入中值滤波器实现灰
    度图像的中值滤波。此外中值滤波是可以处理 RGB 图像格式的,失真不是很严重,相比较均值和高斯滤波
    就不能处理 RGB 图像,大家可以多试验。

    如图所示,我们要进行均值滤波首先要生成一个3x3矩阵。算法运算窗口一般采用奇数点的邻域来计算中值,最常用的窗口有3X3和5X5模型。下面介绍3X3窗口的Verilog实现方法。
    (1)       通过2个或者3个RAM的存储来实现3X3像素窗口;
    (2)       通过2个或者3个FIFO的存储来实现3X3像素窗口;
    (3)       通过2行或者3行Shift_RAM的存储来实现3X3像素窗口;
      要想用实现均值滤波和中值滤波,必须要先生成3x3阵列,在xilinx系列里,可以用调用IP核——shift_RAM,Xilinx也有自己的Shift RAM,Shift_RAM简直就是为3X3矩阵而生的,所以这我使用Xilinx shift_RAM来实现3X3矩阵,配置如下:
    添加IP核
    360截图18720123929789.png 搜索IP核
    360截图167708105959103.png
    IP核设置:
    360截图17590829423847.png
    shift register(RAM-based)ip 主要为了形成三行像素缓存。
    这里Xilinx的shift_ram一次只能生成一行数据,所以我采用两个IP Core和正在输入的一行来生成三行数据
    module line3(
        input clk,
        input [15:0] din,
        input hs_valid_in,
        output [15:0] dout,
        output [15:0] dout_r0,
        output [15:0] dout_r1,
        output [15:0] dout_r2
        );
    line_buff line_buff0(
      .D(din),
       .CLK(clk),
       .CE(hs_valid_in),
       .Q(dout_r0)
    );
    line_buff line_buff1(
      .D(dout_r0),
       .CLK(clk),
       .CE(hs_valid_in),
       .Q(dout_r1)
    );
    line_buff line_buff2(
        .D(dout_r1),
       .CLK(clk),
       .CE(hs_valid_in),
       .Q(dout_r2)
    );
    assign dout = dout_r2;
    endmodule
    中值滤波实现算法:

    `timescale 1ns/1ps
    module median_filter(
             input             clk,
                     input             rst_n,
                     
                     input [15:0]      data_in,
                     input             data_in_en,
                     input             hs_in,
                     input             vs_in,
                     
                     output[15:0]      data_out,
                     output            data_out_en,
                     
                     output            hs_out,
                     output            vs_out
                     );
                     
    wire [15:0] line0;
    wire [15:0] line1;
    wire [15:0] line2;


    //--------------------------------------
    //pipeline control signal
    //--------------------------------------
    reg         hs0;
    reg         hs1;
    reg         hs2;


    reg         vs0;
    reg         vs1;
    reg         vs2;


    reg         de0;
    reg         de1;
    reg         de2;
    //-------------------------------------
    //pipeline data
    //-------------------------------------
    reg [15:0] line0_data0;
    reg [15:0] line0_data1;
    reg [15:0] line0_data2;


    reg [15:0] line1_data0;
    reg [15:0] line1_data1;
    reg [15:0] line1_data2;


    reg [15:0] line2_data0;
    reg [15:0] line2_data1;
    reg [15:0] line2_data2;


    //--------------------------------------
    //define line max mid min
    //--------------------------------------
    reg [15:0] line0_max;
    reg [15:0] line0_mid;
    reg [15:0] line0_min;


    reg [15:0] line1_max;
    reg [15:0] line1_mid;
    reg [15:0] line1_min;


    reg [15:0] line2_max;
    reg [15:0] line2_mid;
    reg [15:0] line2_min;


    //----------------------------------------------
    // define //max of min //mid of mid// min of max
    //----------------------------------------------


    reg [15:0] max_max;
    reg [15:0] max_mid;
    reg [15:0] max_min;


    reg [15:0] mid_max;
    reg [15:0] mid_mid;
    reg [15:0] mid_min;


    reg [15:0] min_max;
    reg [15:0] min_mid;
    reg [15:0] min_min;


    //---------------------------------------------
    // define mid of mid
    //---------------------------------------------


    reg [15:0] mid;
       
    line3 line3x3_inst(
            .hs_valid_in(data_in_en),
                 .clk(clk),
                 .din(data_in),
                 .dout(),
                 .dout_r0(line0),
                 .dout_r1(line1),
                 .dout_r2(line2)
                      );


    //----------------------------------------------------
    //delay control signal
    //----------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
        hs0 <= 1'b0;
        hs1 <= 1'b0;
        hs2 <= 1'b0;


        vs0 <= 1'b0;
        vs1 <= 1'b0;
        vs2 <= 1'b0;


        de0 <= 1'b0;
        de1 <= 1'b0;
        de2 <= 1'b0;
      end
      else if(data_in_en) begin
        hs0 <= hs_in;
        hs1 <= hs0;
        hs2 <= hs1;


        vs0 <= vs_in;
        vs1 <= vs0;
        vs2 <= vs1;


        de0 <= data_in_en;
        de1 <= de0;
        de2 <= de1;  
      end
    end
    //----------------------------------------------------
    // Form an image matrix of three multiplied by three
    //----------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
        line0_data0 <= 16'b0;
             line0_data1 <= 16'b0;
             line0_data2 <= 16'b0;
             
             line1_data0 <= 16'b0;
             line1_data1 <= 16'b0;
             line1_data2 <= 16'b0;
             
             line2_data0 <= 16'b0;
             line2_data1 <= 16'b0;
             line2_data2 <= 16'b0;
      end
      else if(data_in_en) begin
        line0_data0 <= line0;
             line0_data1 <= line0_data0;
             line0_data2 <= line0_data1;
             
             line1_data0 <= line1;
             line1_data1 <= line1_data0;
             line1_data2 <= line1_data1;
             
             line2_data0 <= line2;
             line2_data1 <= line2_data0;
             line2_data2 <= line2_data1;         
      end
      else ;
    end
    //-----------------------------------------------------------------------------------
    //(line0 line1 line2) of (max mid min)
    //-----------------------------------------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
        line0_max <= 16'd0;
        line0_mid <= 16'd0;
        line0_min <= 16'd0;
      end
      else if(data_in_en) begin
        if((line0_data0 >= line0_data1) && (line0_data0 >= line0_data2)) begin
               line0_max <= line0_data0;
                    if(line0_data1 >= line0_data2) begin


                      line0_mid <= line0_data1;
                      line0_min <= line0_data2;
                    end
                    else begin
                      line0_mid <= line0_data2;
                      line0_min <= line0_data1;
                    end
             end
             else if((line0_data1 > line0_data0) && (line0_data1 >= line0_data2)) begin
               line0_max <= line0_data1;
                    if(line0_data0 >= line0_data2) begin
                      line0_mid <= line0_data0;
                      line0_min <= line0_data2;
                    end
                    else begin
                      line0_mid <= line0_data2;
                      line0_min <= line0_data0;
                    end
             end
             else if((line0_data2 > line0_data0) && (line0_data2 > line0_data1)) begin
               line0_max <= line0_data2;
                    if(line0_data0 >= line0_data1) begin
                      line0_mid <= line0_data0;
                      line0_min <= line0_data1;
                    end
                    else begin
                      line0_mid <= line0_data1;
                      line0_min <= line0_data0;
                    end
             end
      end
    end


    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
             line1_max <= 16'd0;
        line1_mid <= 16'd0;
        line1_min <= 16'd0;
      end
      else if(data_in_en) begin
        if((line1_data0 >= line1_data1) && (line1_data0 >= line1_data2)) begin
               line1_max <= line1_data0;
                    if(line1_data1 >= line1_data2) begin
                      line1_mid <= line1_data1;
                      line1_min <= line1_data2;
                    end
                    else begin
                      line1_mid <= line1_data2;
                      line1_min <= line1_data1;
                    end
             end
             else if((line1_data1 > line1_data0) && (line1_data1 >= line1_data2)) begin
               line1_max <= line1_data1;
                    if(line1_data0 >= line1_data2) begin
                      line1_mid <= line1_data0;
                      line1_min <= line1_data2;
                    end
                    else begin
                      line1_mid <= line1_data2;
                      line1_min <= line1_data0;
                    end         
             end
             else if((line1_data2 > line1_data0) && (line1_data2 > line1_data1)) begin
               line1_max <= line1_data2;
                    if(line1_data0 >= line1_data1) begin
                      line1_mid <= line1_data0;
                      line1_min <= line1_data1;
                    end
                    else begin
                      line1_mid <= line1_data1;
                      line1_min <= line1_data0;
                    end         
             end
      end
    end


    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
             line2_max <= 16'd0;
        line2_mid <= 16'd0;
        line2_min <= 16'd0;
      end
      else if(data_in_en) begin
        if((line2_data0 >= line2_data1) && (line2_data0 >= line2_data2)) begin
               line2_max <= line2_data0;
                    if(line2_data1 > line2_data2) begin
                      line2_mid <= line2_data1;
                      line2_min <= line2_data2;
                    end
                    else begin
                      line2_mid <= line2_data2;
                      line2_min <= line2_data1;
                    end
             end
             else if((line2_data1 > line2_data0) && (line2_data1 >= line2_data2)) begin
               line2_max <= line2_data1;
                    if(line2_data0 >= line2_data2) begin
                      line2_mid <= line2_data0;
                      line2_min <= line2_data2;
                    end
                    else begin
                      line2_mid <= line2_data2;
                      line2_min <= line2_data0;
                    end         
             end
             else if((line2_data2 > line2_data0) && (line2_data2 > line2_data1)) begin
               line2_max <= line2_data2;
                    if(line2_data0 >= line2_data1) begin
                      line2_mid <= line2_data0;
                      line2_min <= line2_data1;
                    end
                    else begin
                      line2_mid <= line2_data1;
                      line2_min <= line2_data0;
                    end         
             end
      end
    end
    //----------------------------------------------------------------------------------
    // (max_max max_mid max_min) of ((line0 line1 line2) of max)
    //----------------------------------------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
             max_max <= 16'd0;
        max_mid <= 16'd0;
        max_min <= 16'd0;
      end
      else if(data_in_en) begin
        if((line0_max >= line1_max) && (line0_max >= line2_max)) begin
               max_max <= line0_max;
                    if(line1_max >= line2_max) begin
                      max_mid <= line1_max;
                      max_min <= line2_max;
                    end
                    else begin
                      max_mid <= line2_max;
                      max_min <= line1_max;
                    end
             end
             else if((line1_max > line0_max) && (line1_max >= line2_max)) begin
               max_max <= line1_max;
                    if(line0_max >= line2_max) begin
                      max_mid <= line0_max;
                      max_min <= line2_max;
                    end
                    else begin
                      max_mid <= line2_max;
                      max_min <= line0_max;
                    end
             end
             else if((line2_max > line0_max) && (line2_max > line1_max)) begin
               max_max <= line2_max;
                    if(line0_max >= line1_max) begin
                      max_mid <= line0_max;
                      max_min <= line1_max;
                    end
                    else begin
                      max_mid <= line1_max;
                      max_min <= line0_max;
                    end
             end
      end
    end
    //------------------------------------------------------------------------------
    // (mid_max mid_mid mid_min) of ((line0 line1 line2)of mid)
    //------------------------------------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
             mid_max <= 16'd0;
        mid_mid <= 16'd0;
        mid_min <= 16'd0;
      end
      else if(data_in_en) begin
        if((line0_mid >= line1_mid) && (line0_mid >= line2_mid)) begin
               mid_max <= line0_mid;
                    if(line1_mid >= line2_mid) begin
                      mid_mid <= line1_mid;
                      mid_min <= line2_mid;
                    end
                    else begin
                      mid_mid <= line2_mid;
                      mid_min <= line1_mid;
                    end
             end
             else if((line1_mid > line0_mid) && (line1_mid >= line2_mid)) begin
               mid_mid <= line1_mid;
                    if(line0_mid >= line2_mid) begin
                      mid_mid <= line0_mid;
                      mid_min <= line2_mid;
                    end
                    else begin
                      mid_mid <= line2_mid;
                      mid_min <= line0_mid;
                    end
             end
             else if((line2_mid > line0_mid) && (line2_mid > line1_mid)) begin
               mid_max <= line2_mid;
                    if(line0_mid >= line1_mid) begin
                      mid_mid <= line0_mid;
                      mid_min <= line1_mid;
                    end
                    else begin
                      mid_mid <= line1_mid;
                      mid_min <= line0_mid;
                    end
             end
      end
    end
    //------------------------------------------------------------------------------
    // (min_max min_mid min_min) of ((line0 line1 line2)of min)
    //------------------------------------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
      if(!rst_n) begin
             min_max <= 16'd0;
        min_mid <= 16'd0;
        min_min <= 16'd0;
      end
      else if(data_in_en) begin
        if((line0_min >= line1_min) && (line0_min >= line2_min)) begin
               min_max <= line0_min;
                    if(line1_min >= line2_min) begin
                      min_mid <= line1_min;
                      min_min <= line2_min;
                    end
                    else begin
                      min_mid <= line2_min;
                      min_min <= line1_min;
                    end
             end
             else if((line1_min > line0_min) && (line1_min >= line2_min)) begin
               min_max <= line1_min;
                    if(line0_min >= line2_min) begin
                      min_mid <= line0_min;
                      min_min <= line2_min;
                    end
                    else begin
                      min_mid <= line2_min;
                      min_min <= line0_min;
                    end
             end
             else if((line2_min > line0_min) && (line2_min > line1_min)) begin
               min_max <= line2_min;
                    if(line0_min >= line1_min) begin
                      min_mid <= line0_min;
                      min_min <= line1_min;
                    end
                    else begin
                      min_mid <= line1_min;
                      min_min <= line0_min;
                    end
             end
      end
    end
    //------------------------------------------------------------------------------
    // middle
    //------------------------------------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
      if(!rst_n)
        mid <= 16'd0;
      else if(data_in_en) begin
        if(((max_mid >= mid_mid) && (max_mid < min_mid)) || ((max_mid >= min_mid) && (max_mid < mid_mid)))
               mid <= max_mid;
             else if(((mid_mid > max_mid) && (mid_mid < min_mid)) || ((min_mid >= min_mid) && (mid_mid < max_mid)))
               mid <= mid_mid;
             else if(((min_mid > max_mid) && (min_mid < mid_mid)) || ((min_mid > mid_mid) && (mid_min < max_mid)))
               mid <= min_mid;
      end
      else ;
    end
    //------------------------------------------------------------------------------------------------------
    //result
    //------------------------------------------------------------------------------------------------------
    assign data_out = mid;
    assign data_out_en = de2;
    assign hs_out = hs2;
    assign vs_out = vs2;
    endmodule

    360截图17100805587687.png


    我们将lena的照片加入椒盐噪声。
    lenna100 - 副本.jpg
    然后生成coe文件,导入工程,便可以看到滤波效果。








    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-12-28 02:53 , Processed in 0.137377 second(s), 16 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.