加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 設(shè)計(jì)背景
    • 設(shè)計(jì)原理
    • 設(shè)計(jì)架構(gòu)圖
    • 設(shè)計(jì)代碼
    • 仿真測(cè)試
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

源碼系列:基于FPGA的中值濾波器設(shè)計(jì)(附源碼)

12小時(shí)前
288
閱讀需 46 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

大俠好,歡迎來(lái)到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。

今天給大俠帶來(lái)基于FPGA的中值濾波器設(shè)計(jì),附源碼,獲取源碼,請(qǐng)?jiān)凇癋PGA技術(shù)江湖”公眾號(hào)內(nèi)回復(fù)“中值濾波器設(shè)計(jì)源碼”,可獲取源碼文件。話不多說,上貨。

設(shè)計(jì)背景

在圖像采集、轉(zhuǎn)換和傳輸?shù)倪^程中,由于成像系統(tǒng)、傳輸介質(zhì)和工作環(huán)境等固有的缺陷,不可避免地產(chǎn)生各種類型的噪聲,導(dǎo)致獲取的圖像往往與實(shí)際圖像有差異。圖像質(zhì)量的下降使得圖像后續(xù)處理(如邊緣檢測(cè)、圖像分割、特征提取、模式識(shí)別等)產(chǎn)生困難,因此對(duì)噪聲圖像進(jìn)行濾波是必要預(yù)處理過程,這可以使處理后的圖像更適合觀察或提取有用信息。但濾波算法在去除噪聲的同時(shí)難免對(duì)圖像造成一定程度的模糊,造成細(xì)節(jié)信息的丟失。中值濾波是對(duì)圖像的低通濾波,可有效濾除高頻噪聲,增強(qiáng)圖像清晰度。

設(shè)計(jì)原理

中值濾波是對(duì)一個(gè)滑動(dòng)窗口內(nèi)的諸像素灰度值排序,用其中值代替窗口中心象素的原來(lái)灰度值,它是一種非線性的圖像平滑法,它對(duì)脈沖干擾級(jí)椒鹽噪聲(脈沖噪聲)的抑制效果好,在抑制隨機(jī)噪聲的同時(shí)能有效保護(hù)邊緣少受模糊。

本設(shè)計(jì)采用3*3的滑動(dòng)窗口,先將3*3窗口中每一列數(shù)據(jù)進(jìn)行從大到小的排序,列排序后,再對(duì)窗口中每一行的數(shù)據(jù)從大到小進(jìn)行排序,之后再對(duì)窗口中對(duì)角線上的數(shù)據(jù)進(jìn)行排序,得到中間值,即為9個(gè)數(shù)的中值。其示意圖如下:

這種濾波算法,極大減少了比較的次數(shù),提高了圖像處理的速度,在FPGA上,不僅易于實(shí)現(xiàn),而且占用了更少的片上資源。

這種濾波算法,極大減少了比較的次數(shù),提高了圖像處理的速度,在FPGA上,不僅易于實(shí)現(xiàn),而且占用了更少的片上資源。

設(shè)計(jì)架構(gòu)圖

本設(shè)計(jì)可分為四個(gè)模塊,分別是:ROM模塊,用于存儲(chǔ)處理圖像的信息;3*3窗口生成模塊,用于生成濾波的滑動(dòng)窗口,得到窗口內(nèi)的所有元素?cái)?shù)據(jù);計(jì)數(shù)器控制模塊,主要用于獲得中心像素點(diǎn)的地址信息;3*3中值濾波模塊,主要用于得到某一中心像素點(diǎn)的3*3滑動(dòng)窗口區(qū)域的灰度值的中值,作為中心像素點(diǎn)的值。

設(shè)計(jì)代碼

medfilter頂層模塊代碼:

module medfilter  (  CLK,   RSTn,  Start_sig,  Done_sig,  Data_out);       input CLK;  input RSTn;  input Start_sig;  output Done_sig;  output [7:0] Data_out;    /********************************************************************/    wire [17:0] rom_addr; //  wire [7:0] rom_data;  // 
//  rom_512by512 rom_512by512_inst//  (//    .clka(CLK),          //input clka;//    .addra(rom_addr),   //input-from; //    .douta(rom_data)     //output-to ; //  );    rom_512by512 rom_512by512_inst(    .address(rom_addr),    //input clka;    .clock(CLK),          //input-from;     .q(rom_data)           //output-to ;  );
  /******************************************************************************/    //wire [7:0] win_data[8:0];  wire [7:0] data_out0;           //output-to ;  wire [7:0] data_out1;  wire [7:0] data_out2;  wire [7:0] data_out3;  wire [7:0] data_out4;  wire [7:0] data_out5;  wire [7:0] data_out6;  wire [7:0] data_out7;  wire [7:0] data_out8;  wire win_done_sig;   wire [9:0] column_addr_sig; wire [9:0] row_addr_sig;   win3by3_gen win3by3_gen_inst (  .CLK(CLK),   .RSTn(RSTn),  .center_pix_sig(win_start_sig), //input-from ;   .cols(10'd512),   // the column numbers of the input image  .rows(10'd512),   // the row numbers of the input image  .rom_data_win(rom_data),    //input-from ;   .column_addr_sig(column_addr_sig),    //input-from ; //output [9 : 0] addra;   .row_addr_sig(row_addr_sig),         //input-from ; //output [9 : 0] addra;  .rom_addr_sig(rom_addr),   //output-to ;   .data_out0(data_out0),           //output-to ;  .data_out1(data_out1),  .data_out2(data_out2),  .data_out3(data_out3),  .data_out4(data_out4),  .data_out5(data_out5),  .data_out6(data_out6),  .data_out7(data_out7),  .data_out8(data_out8),  .win_data_done_sig(win_done_sig)  //output-to U4/U3;     );    /******************************************************************************/      counter_ctrl counter_ctrl_inst(  .CLK(CLK),  .RSTn(RSTn),  .start_sig(Start_sig),  //input-from top   .nxt_pix_sig(win_done_sig),  //input-from   .cols(10'd512),   .column_addr_sig(column_addr_sig),  //output-to   .row_addr_sig(row_addr_sig),     //output-to   .pix_done_sig(win_start_sig)   //output-to      );  /*****************************************************************************/  wire medfilt_done_sig; wire [7:0] medfilt_data_wire;  medfilter3by3 medfilter3by3_inst(  .CLK(CLK),  .RSTn(RSTn),   .win_data_sig(win_done_sig),  //input-from;   .medfilt_done_sig(medfilt_done_sig), //output-to;  .data_in0(data_out0),        //input-from ;  .data_in1(data_out1),  .data_in2(data_out2),  .data_in3(data_out3),  .data_in4(data_out4),  .data_in5(data_out5),  .data_in6(data_out6),  .data_in7(data_out7),  .data_in8(data_out8),  .medfilt_data_out(medfilt_data_wire)     //output-to top; ); 
/*********************************************************************/ wire Done_sig; wire [7:0] Data_out; assign Done_sig = medfilt_done_sig; assign Data_out = medfilt_data_wire; /**********************************************************************/endmodule

rom_512by512設(shè)計(jì)模塊代碼:

// synopsys translate_off`timescale 1 ps / 1 ps// synopsys translate_onmodule rom_512by512 (  address,  clock,  q);
  input  [17:0]  address;  input    clock;  output  [7:0]  q;`ifndef ALTERA_RESERVED_QIS// synopsys translate_off`endif  tri1    clock;`ifndef ALTERA_RESERVED_QIS// synopsys translate_on`endif
  wire [7:0] sub_wire0;  wire [7:0] q = sub_wire0[7:0];
  altsyncram  altsyncram_component (        .address_a (address),        .clock0 (clock),        .q_a (sub_wire0),        .aclr0 (1'b0),        .aclr1 (1'b0),        .address_b (1'b1),        .addressstall_a (1'b0),        .addressstall_b (1'b0),        .byteena_a (1'b1),        .byteena_b (1'b1),        .clock1 (1'b1),        .clocken0 (1'b1),        .clocken1 (1'b1),        .clocken2 (1'b1),        .clocken3 (1'b1),        .data_a ({8{1'b1}}),        .data_b (1'b1),        .eccstatus (),        .q_b (),        .rden_a (1'b1),        .rden_b (1'b1),        .wren_a (1'b0),        .wren_b (1'b0));  defparam    altsyncram_component.address_aclr_a = "NONE",    altsyncram_component.clock_enable_input_a = "BYPASS",    altsyncram_component.clock_enable_output_a = "BYPASS",    altsyncram_component.init_file = "medfilter2_re.mif",    altsyncram_component.intended_device_family = "Cyclone IV E",    altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",    altsyncram_component.lpm_type = "altsyncram",    altsyncram_component.numwords_a = 262144,    altsyncram_component.operation_mode = "ROM",    altsyncram_component.outdata_aclr_a = "NONE",    altsyncram_component.outdata_reg_a = "UNREGISTERED",    altsyncram_component.widthad_a = 18,    altsyncram_component.width_a = 8,    altsyncram_component.width_byteena_a = 1;

endmodule

counter_ctrl模塊代碼:

module counter_ctrl(  CLK,  RSTn,  start_sig,  //input-from top  nxt_pix_sig,     //input-from --start next center point pixel  cols,                            column_addr_sig,  //output  row_addr_sig,     //output-to   pix_done_sig   //output-to    );       input CLK;  input RSTn;  input start_sig;  input nxt_pix_sig;  input [9:0] cols;    output pix_done_sig;    output [9:0] column_addr_sig;      output [9:0] row_addr_sig;      /***********************************************************************************************/    reg isCtrlDone;  //reg isWinStart;  reg [17:0] imk;   //The k-th pixel of the image  reg [9:0] row_addr;  // The row of the centeral pixel  reg [9:0] column_addr;   // The column of the centeral pixel    reg start_sig_d;    wire start_sig_rising_vld;     always @ (posedge CLK or negedge RSTn)   //Asynchronous reset      if (!RSTn)        start_sig_d <= 0;     else         start_sig_d <= start_sig;    assign start_sig_rising_vld = start_sig & (~start_sig_d);    always @ (posedge CLK or negedge RSTn)   //Asynchronous reset    if (!RSTn)       begin          imk <= 18'b0;         column_addr <= 10'b0;         row_addr <= 10'b0;        isCtrlDone <= 1'b0;            end     else if (start_sig_rising_vld)       begin          imk <= 18'b1;         column_addr <= 10'b1;         row_addr <= 10'b1;        isCtrlDone <= 1'b1;            end         else if ( nxt_pix_sig )       begin            imk <= imk + 1'b1;          row_addr <= imk / cols + 1;             column_addr <= imk % cols + 1;           isCtrlDone <= 1'b1;         end     else isCtrlDone <= 1'b0;              /*****************************************************************************************/    assign row_addr_sig = row_addr;  assign column_addr_sig = column_addr;  assign pix_done_sig = isCtrlDone;  /*****************************************************************************************/endmodule

win3by3_gen模塊代碼:

 module win3by3_gen(   CLK,    RSTn,   center_pix_sig,   cols,   // the column numbers of the input image   rows,   rom_data_win,   //input-from U1;    column_addr_sig,    //input-from U3; //output [9 : 0] addra;    row_addr_sig,         //input-from U3; //output [9 : 0] addra;   rom_addr_sig,            //output-to U1;    data_out0,           //output-to U4;   data_out1,   data_out2,   data_out3,   data_out4,   data_out5,   data_out6,   data_out7,   data_out8,   win_data_done_sig            //output-to U4/U3;complete the win data;     );    input CLK;    input RSTn;   input [7:0] rom_data_win;   input [9:0] cols;   input [9:0] rows;   input center_pix_sig;  //    input [9:0] column_addr_sig;   input [9:0] row_addr_sig;      output [7:0] data_out0;           //output-to U4;   output [7:0] data_out1;   output [7:0] data_out2;   output [7:0] data_out3;   output [7:0] data_out4;   output [7:0] data_out5;   output [7:0] data_out6;   output [7:0] data_out7;   output [7:0] data_out8;   output [17:0] rom_addr_sig;   output win_data_done_sig;    /******************************************************************************************************************************/       reg [9:0] m;      always @ ( posedge CLK or negedge RSTn )     if ( !RSTn )        m <= 10'd1;      else if (  center_pix_sig )        m <= row_addr_sig[9:0];             /******************************************************************************************************************************/       reg [9:0] n;      always @ ( posedge CLK or negedge RSTn )     if ( !RSTn )        n <= 10'd1;      else if (  center_pix_sig )        n <= column_addr_sig[9:0];                /*****************************************************************************************************************************/       reg [3:0] i;    reg isWinDone;   reg [17:0] rom_addr;   reg [7:0] a11;   reg [7:0] a12;   reg [7:0] a13;   reg [7:0] a21;   reg [7:0] a22;   reg [7:0] a23;   reg [7:0] a31;   reg [7:0] a32;   reg [7:0] a33;       /*****************************************************************************************************************************/   reg get_9point_vld;  always @ ( posedge CLK or negedge RSTn )     if (!RSTn)            get_9point_vld <= 1'b0;      else if ( center_pix_sig )               get_9point_vld <= 1'b1;      else if ( i==4'd10 )              get_9point_vld <= 1'b0;   always @ ( posedge CLK or negedge RSTn )     if ( !RSTn )            isWinDone <= 1'b0;      else if ( i==4'd10 )               isWinDone <= 1'b1;      else              isWinDone <= 1'b0;    always @ ( posedge CLK or negedge RSTn )     if ( !RSTn )            i <= 4'd0;      else if (i == 4'd10)               i <= 4'd0;      else if ( get_9point_vld )              i <= i + 1'b1;             always @ ( posedge CLK or negedge RSTn )     if (!RSTn)              rom_addr <= 0;      else if ( get_9point_vld)        case (i)           4'd0:             if(!(m==1 || n==1)) rom_addr <= (m-2)*cols + (n-1) -1;                         4'd1:           if(!(m==1 )) rom_addr <= (m-2)*cols + n -1;                        4'd2:             if(!(m==1 || n==cols)) rom_addr <= (m-2)*cols + (n+1) -1;                       4'd3:             if(!(n==1)) rom_addr <= (m-1)*cols + (n-1) -1;                       4'd4:             rom_addr <= (m-1)*cols + n -1;                       4'd5:             if(!(n==cols)) rom_addr <= (m-1)*cols + (n+1) -1;                       4'd6:             if(!(m==cols || n==1)) rom_addr <= m*cols + (n-1) -1;                       4'd7:             if(!(m==cols)) rom_addr <= m*cols + n -1;                       4'd8:             if(!(m==cols || n==cols)) rom_addr <= m*cols + (n+1) -1;                          default:;          endcase          always @ ( posedge CLK or negedge RSTn )     if (!RSTn)        begin           a11 <= 0;            a12 <= 0;            a13 <= 0;            a21 <= 0;            a22 <= 0;            a23 <= 0;            a31 <= 0;            a32 <= 0;           a33 <= 0;         end      else if ( get_9point_vld )              case (i)              4'd2:           if ( m==1 || n==1 )                  a11 <= 0;                else                  a11 <= rom_data_win;                            4'd3:           if ( m==1 )  a12 <= 0;            else a12 <= rom_data_win;                             4'd4:           if ( m==1 || n==cols ) a13 <= 0;            else a13 <= rom_data_win;                       4'd5:           if ( n==1 ) a21 <= 0;            else  a21 <= rom_data_win;                       4'd6:           a22 <= rom_data_win;                                 4'd7:           if ( n==cols ) a23 <= 0;            else a23 <= rom_data_win;                      4'd8:           if ( m==cols || n==1 ) a31 <= 0;           else a31 <= rom_data_win;                        4'd9:           if ( m==cols ) a32 <= 0;           else a32 <= rom_data_win;                      4'd10:           if ( m==cols || n==cols ) a33 <= 0;            else a33 <= rom_data_win;                        default:;                  endcase    /**********************************************************************************************/      assign win_data_done_sig = isWinDone;   assign rom_addr_sig = rom_addr;      assign data_out0 = a11;   assign data_out1 = a12;   assign data_out2 = a13;   assign data_out3 = a21;   assign data_out4 = a22;   assign data_out5 = a23;   assign data_out6 = a31;   assign data_out7 = a32;   assign data_out8 = a33;    /**********************************************************************************************/    endmodule

medfilter3by3模塊代碼:

module medfilter3by3(  CLK,  RSTn,  win_data_sig,  //input-from module of win3by3_gen;   medfilt_done_sig,   //output-to top;  data_in0,        //input-from module of win3by3_gen;  data_in1,  data_in2,  data_in3,  data_in4,  data_in5,  data_in6,  data_in7,  data_in8,  medfilt_data_out    //output-to top;     );
  input CLK;  input RSTn;  input win_data_sig;  input [7:0] data_in0;           //output-to ;  input [7:0] data_in1;  input [7:0] data_in2;  input [7:0] data_in3;  input [7:0] data_in4;  input [7:0] data_in5;  input [7:0] data_in6;  input [7:0] data_in7;  input [7:0] data_in8;
  output medfilt_done_sig;  output [7:0] medfilt_data_out;
/******************************************************************************/   reg [7:0] a11;  reg [7:0] a12;  reg [7:0] a13;  reg [7:0] a21;  reg [7:0] a22;  reg [7:0] a23;  reg [7:0] a31;  reg [7:0] a32;  reg [7:0] a33;    reg [7:0] b11;  reg [7:0] b12;  reg [7:0] b13;  reg [7:0] b21;  reg [7:0] b22;  reg [7:0] b23;  reg [7:0] b31;  reg [7:0] b32;  reg [7:0] b33;    reg [7:0] c11;  reg [7:0] c12;  reg [7:0] c13;  reg [7:0] c21;  reg [7:0] c22;  reg [7:0] c23;  reg [7:0] c31;  reg [7:0] c32;  reg [7:0] c33;    reg [2:0] i;  reg [7:0] medfilt_data;  reg filt_done;    reg cal_vld;
 always @ ( posedge CLK or negedge RSTn )    if (!RSTn)      begin            a11 <= 0;            a12 <= 0;            a13 <= 0;            a21 <= 0;            a22 <= 0;            a23 <= 0;            a31 <= 0;            a32 <= 0;            a33 <= 0;        end     else if (win_data_sig)       begin            a11 <= data_in0;            a12 <= data_in1;            a13 <= data_in2;            a21 <= data_in3;            a22 <= data_in4;            a23 <= data_in5;            a31 <= data_in6;            a32 <= data_in7;            a33 <= data_in8;        end    always @ ( posedge CLK or negedge RSTn )    if (!RSTn)            i <= 3'd0;     else if( cal_vld & ( i!=3 ) )            i <= i + 1;     else             i <= 0;              always @ ( posedge CLK or negedge RSTn )    if (!RSTn)            cal_vld <= 1'b0;     else if( win_data_sig )            cal_vld <= 1'b1;     else if( i==3'd3 )            cal_vld <= 0;            

  always @ ( posedge CLK or negedge RSTn )    if (!RSTn)       begin        filt_done <= 1'b0;        b11 <= 0;        b12 <= 0;        b13 <= 0;        b21 <= 0;        b22 <= 0;        b23 <= 0;        b31 <= 0;        b32 <= 0;        b33 <= 0;        c11 <= 0;        c12 <= 0;        c13 <= 0;        c21 <= 0;        c22 <= 0;        c23 <= 0;        c31 <= 0;        c32 <= 0;        c33 <= 0;        medfilt_data <= 0;        end     else if( cal_vld )       case(i)          3'd0:            begin             b11 <= max(a11, a21, a31);              b12 <= max(a12, a22, a32);              b13 <= max(a13, a23, a33);             b21 <= med(a11, a21, a31);              b22 <= med(a12, a22, a32);              b23 <= med(a13, a23, a33);             b31 <= min(a11, a21, a31);              b32 <= min(a12, a22, a32);              b33 <= min(a13, a23, a33);            end                       3'd1:            begin             c31 <= max(b31, b32, b33);             c22 <= med(b21, b22, b23);             c13 <= min(b11, b12, b13);              end                    3'd2:             begin             medfilt_data <= med(c13, c22, c31);             filt_done<=1'b1;             end           3'd3:             filt_done <= 1'b0; 
            default:;
        endcase        /************************************************************************************/ 
function [7:0] max;//if the data is signed number, please add the char signed behind key function;   input [7:0] a, b, c;  begin    max = (((a >= b) ? a : b) >= c ) ?  ((a >= b) ? a : b) : c;  endendfunction
function [7:0] med;  input [7:0] a, b, c;  begin     med = a < b ? (b < c ? b : a < c ? c : a) : (b > c ? b : a > c ? c : a);  endendfunction
function [7:0] min;  input [7:0] a, b, c;  begin     min= (((a <= b) ? a : b) <= c ) ?  ((a <= b) ? a : b) : c;  endendfunction          /************************************************************************************/    assign medfilt_data_out = medfilt_data;  assign medfilt_done_sig = filt_done;
/**********************************************************************************/  endmodule

仿真測(cè)試

仿真測(cè)試medfilter_tb模塊代碼:

module medfilter_tb;
    // Inputs    reg CLK;    reg RSTn;    reg Start_sig;    reg [18:0] pix_cnt;   //512*512=262144=100,0000,0000,0000,0000    
    // Outputs    wire Done_sig;    wire [7:0] Data_out;    integer fouti;        
    // Instantiate the Unit Under Test (UUT)    medfilter uut (        .CLK(CLK),         .RSTn(RSTn),         .Start_sig(Start_sig),         .Done_sig(Done_sig),         .Data_out(Data_out)    );        //assign Data_out = 0;   //assign Done_sig = 0;
    initial begin        // Initialize Inputs        CLK = 0;        RSTn = 1;        Start_sig = 0;                fouti = $fopen("medfilter2_re.txt");
        // Wait 100 ns for global reset to finish        #100;   // To reset the system        // Add stimulus here        RSTn = 0;        Start_sig = 1;        pix_cnt = 0;                #100;   // To start the system        // Add stimulus here        RSTn = 1;        pix_cnt = 1;        end        always #10 CLK = ~CLK;        always@(posedge CLK)    begin        if(Done_sig)           pix_cnt <= pix_cnt + 1;    end        always@(posedge CLK)    begin        if(pix_cnt == 19'd262145)           begin               Start_sig <= 0;               $display("Image Medfilter Completed!n");              $display("The all time is %d n",$time);              $stop;            end    end
    
    always@(posedge CLK)    begin        if(Done_sig)            begin              $fwrite(fouti, "%d", Data_out, "n");              $display("%d",pix_cnt);            end    end     endmodule 

仿真圖如下:

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

任何技術(shù)的學(xué)習(xí)就好比一個(gè)江湖,對(duì)于每一位俠客都需要不斷的歷練,從初入江湖的小白到歸隱山林的隱世高人,需要不斷的自我感悟自己修煉,讓我們一起仗劍闖FPGA乃至更大的江湖。