基於FPGA的圖像中值濾波原理與實現

項目簡述

中值濾波器在去除尖端噪聲中非常重要,是信號處理中最長用到的濾波器。圖像中的一些椒鹽噪聲或者其它突變比較大的噪聲可以使用中值濾波器去除,所以這篇文章我們來講解FPGA實現圖像的中值濾波。本次項目的簡述如下:PC機通過千兆以太網發送到FPGA開發板中,然後經過中值濾波緩存進DDR3中,最後經過DDR3發送到上位機中顯示。

本次實驗所用到的軟硬件環境如下:
1、VIVADO2019.1軟件環境
2、Modelsim10.7c仿真環境
3.米聯客MA7035FA(100T)開發板
4、米聯客USB3.0上位機軟件

中值濾波器原理

圖像信號在形成、傳輸和記錄的過程中,由於成像系統、 傳輸介質、 工作環境和記錄設備等的固有缺陷,不可避免地產生各種類型的噪聲,降低了圖像的質量,進而影響後續處理(如邊緣檢測、圖像分割、特徵提取、模式識別等)的效果或準確性。因此,對噪聲圖像進行濾波是必要預處理過程。

這裏需要注意中值濾波基於排序統計理論,是抑制噪聲的***非線性信號處理技術***。其核心運算是以模板中的數據進行排序,使得某個亮點(暗點)的噪聲在排序過程中被排在數據序列的兩側。因爲數據序列中間位置上的值一般不是噪聲點的值,從而達到抑制噪聲的目的。

假設有圖像 A, 對其進行中值濾波, 即求出該 3x3 矩陣中的排序在中間位置的那個值。
在這裏插入圖片描述
當然前面的文章中我們已經詳細講解了3*3矩陣的構建方法,那麼這篇文章,我們主要集中在找上面圖像矩陣中的中值,然後代替圖像的數據。方法一,是對上面的矩陣進行硬件排序,硬件排序的效率非常高,但是理解與實現起來較困難,我會在後面的專門的文章中進行相應的講解。第二種方法就是兩兩找最大值的方法,對齊介紹如下:

第一步: 分別求出 3 行中同一行的最大值、 最小值、 中間值
設 max_h1 爲第一行的最大值, min_h1 爲第一行的最小值, mid_h1 爲第一
行的中間值。
同理有 max_h2, mid_h2, min_h2, max_h3, mid_h3, min_h3。
第二步: 3 行的最大值、 最小值、 中間值進行比較
max_h1, m2ax_h2, max_h3 這 3 個值比較, 得到這 3 個值的最小值 min_max。
mid_h1, mid_h2, mid_h3 這 3 個值比較, 得到這 3 個值的中間值 mid_mid。
min_h1, min_h2, min_h3 這 3 個值比較, 得到這 3 個值的最大值 max_min。
第三步: 得到 3x3 矩陣的中間值
將第二步得到的 min_max, mid_mid, max_min 進行比較, 得到的中間值,
即該 3x3 矩陣的中間值。

至於爲什麼上面找到的值就是圖像矩陣的中值,同學們可以試着分別對上面 max_h1 ,mid_h1 ,max_h1 ,max_h2, mid_h2, min_h2, max_h3, mid_h3, min_h3進行排序的大體範圍判斷。然後,就可以發現排序第5位的數據就在min_max, mid_mid, max_min的中間值。

中值濾波器的實現

這裏因爲簡單的數學關係,我們同樣不再給出時序圖,而是直接會給出相應的代碼:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : sobel.v
// Create Time  : 2020-04-08 08:32:02
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module sobel(
    //System Interfaces
    input                   sclk            ,
    input                   rst_n           ,
    //Communication Interfaces
    input           [ 7:0]  rx_data         ,
    input                   pi_flag         ,
    output  reg     [ 7:0]  tx_data         ,
    output  reg             po_flag         
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter           COL_NUM     =   1024    ;
parameter           ROW_NUM     =   768     ;
parameter           VALUE       =   80      ;

wire                [ 7:0]  mat_row1        ;
wire                [ 7:0]  mat_row2        ;
wire                [ 7:0]  mat_row3        ;
wire                        mat_flag        ; 
reg                 [ 7:0]  mat_row1_1      ;
reg                 [ 7:0]  mat_row2_1      ;
reg                 [ 7:0]  mat_row3_1      ;
reg                 [ 7:0]  mat_row1_2      ;
reg                 [ 7:0]  mat_row2_2      ;
reg                 [ 7:0]  mat_row3_2      ;
reg                         mat_flag_1      ; 
reg                         mat_flag_2      ; 
reg                         mat_flag_3      ; 
reg                         mat_flag_4      ; 
reg                         mat_flag_5      ; 
reg                         mat_flag_6      ; 
reg                         mat_flag_7      ;

reg                 [ 7:0]  max_h1          ;
reg                 [ 7:0]  mid_h1          ;  
reg                 [ 7:0]  min_h1          ; 
reg                 [ 7:0]  max_h2          ;
reg                 [ 7:0]  mid_h2          ;  
reg                 [ 7:0]  min_h2          ;  
reg                 [ 7:0]  max_h3          ;
reg                 [ 7:0]  mid_h3          ;  
reg                 [ 7:0]  min_h3          ; 
reg                 [ 7:0]  min_max         ;
reg                 [ 7:0]  mid_mid         ;
reg                 [ 7:0]  max_min         ;       
  

 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
always @(posedge sclk)
    begin
        mat_row1_1          <=          mat_row1;
        mat_row2_1          <=          mat_row2;
        mat_row3_1          <=          mat_row3;
        mat_row1_2          <=          mat_row1_1;
        mat_row2_2          <=          mat_row2_1;
        mat_row3_2          <=          mat_row3_1;
    end
    
always @(posedge sclk)
    begin
        mat_flag_1          <=          mat_flag;      
        mat_flag_2          <=          mat_flag_1;      
        mat_flag_3          <=          mat_flag_2;      
        mat_flag_4          <=          mat_flag_3;      
        mat_flag_5          <=          mat_flag_4;      
        mat_flag_6          <=          mat_flag_5;      
        mat_flag_7          <=          mat_flag_6;      
    end
    
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        max_h1              <=          8'd0;        
    else if(mat_row1 >= mat_row1_1 && mat_row1 >= mat_row1_2)
        max_h1              <=          mat_row1;
    else if(mat_row1_1 >= mat_row1 && mat_row1_1 >= mat_row1_2) 
        max_h1              <=          mat_row1_1;
    else
        max_h1              <=          mat_row1_2;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        mid_h1              <=          8'd0;        
    else if((mat_row1 >= mat_row1_1 && mat_row1_1 >= mat_row1_2) || (mat_row1_2 >= mat_row1_1 && mat_row1_1 >= mat_row1))
        mid_h1              <=          mat_row1_1;
    else if((mat_row1_1 >= mat_row1 && mat_row1 >= mat_row1_2) || (mat_row1_2 >= mat_row1 && mat_row1 >= mat_row1_1))
        mid_h1              <=          mat_row1;
    else
        mid_h1              <=          mat_row1_2;
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        min_h1              <=          8'd0;        
    else if(mat_row1 <= mat_row1_1 && mat_row1 <= mat_row1_2)
        min_h1              <=          mat_row1;
    else if(mat_row1_1 <= mat_row1 && mat_row1_1 <= mat_row1_2) 
        min_h1              <=          mat_row1_1;
    else
        min_h1              <=          mat_row1_2;  

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        max_h2              <=          8'd0;        
    else if(mat_row2 >= mat_row2_1 && mat_row2 >= mat_row2_2)
        max_h2              <=          mat_row2;
    else if(mat_row2_1 >= mat_row2 && mat_row2_1 >= mat_row2_2) 
        max_h2              <=          mat_row2_1;
    else
        max_h2              <=          mat_row2_2;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        mid_h2              <=          8'd0;        
    else if((mat_row2 >= mat_row2_1 && mat_row2_1 >= mat_row2_2) || (mat_row2_2 >= mat_row2_1 && mat_row2_1 >= mat_row2))
        mid_h2              <=          mat_row2_1;
    else if((mat_row2_1 >= mat_row2 && mat_row2 >= mat_row2_2) || (mat_row2_2 >= mat_row2 && mat_row2 >= mat_row2_1))
        mid_h2              <=          mat_row2;
    else
        mid_h2              <=          mat_row2_2;
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        min_h2              <=          8'd0;        
    else if(mat_row2 <= mat_row2_1 && mat_row2 <= mat_row2_2)
        min_h2              <=          mat_row2;
    else if(mat_row2_1 <= mat_row2 && mat_row2_1 <= mat_row2_2) 
        min_h2              <=          mat_row2_1;
    else
        min_h2              <=          mat_row2_2;  

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        max_h3              <=          8'd0;        
    else if(mat_row3 >= mat_row3_1 && mat_row3 >= mat_row3_2)
        max_h3              <=          mat_row3;
    else if(mat_row3_1 >= mat_row3 && mat_row3_1 >= mat_row3_2) 
        max_h3              <=          mat_row3_1;
    else
        max_h3              <=          mat_row3_2;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        mid_h3              <=          8'd0;        
    else if((mat_row3 >= mat_row3_1 && mat_row3_1 >= mat_row3_2) || (mat_row3_2 >= mat_row3_1 && mat_row3_1 >= mat_row3))
        mid_h3              <=          mat_row3_1;
    else if((mat_row3_1 >= mat_row3 && mat_row3 >= mat_row3_2) || (mat_row3_2 >= mat_row3 && mat_row3 >= mat_row3_1)) 
        mid_h3              <=          mat_row3;
    else
        mid_h3              <=          mat_row3_2;
 
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        min_h3              <=          8'd0;        
    else if(mat_row3 <= mat_row3_1 && mat_row3 <= mat_row3_2)
        min_h3              <=          mat_row3;
    else if(mat_row3_1 <= mat_row3 && mat_row3_1 <= mat_row3_2) 
        min_h3              <=          mat_row3_1;
    else
        min_h3              <=          mat_row3_2;


always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        min_max             <=          8'd0;
    else if(max_h1 <= max_h2 && max_h1 <= max_h3)
        min_max             <=          max_h1;
    else if(max_h2 <= max_h1 && max_h2 <= max_h3)
        min_max             <=          max_h2;
    else
        min_max             <=          max_h3;
          
   
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        mid_mid             <=          8'd0;
    else if((mid_h1 >= mid_h2 && mid_h2 >= mid_h3) || (mid_h3 >= mid_h2 && mid_h2 >= mid_h1))
        mid_mid             <=          mid_h2;
    else if((mid_h2 >= mid_h1 && mid_h1 >= mid_h3) || (mid_h3 >= mid_h1 && mid_h1 >= mid_h2))
        mid_mid             <=          mid_h1;
    else
        mid_mid             <=          mid_h3;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        max_min             <=          8'd0;
    else if(min_h1 <= min_h2 && min_h1 <= min_h3) 
        max_min             <=          min_h1;
    else if(min_h2 <= min_h1 && min_h2 <= min_h3)
        max_min             <=          min_h2;
    else
        max_min             <=          min_h3;
           
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        tx_data             <=          8'd0; 
    else if((mid_mid >= min_max && min_max >= max_min) || (max_min >= min_max && min_max >= mid_mid))
        tx_data             <=          min_max;
    else if((min_max >= mid_mid && mid_mid >= max_min) || (max_min >= mid_mid && mid_mid >= min_max))
        tx_data             <=          mid_mid;
    else
        tx_data             <=          max_min;
          
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        po_flag             <=          1'b0;
    else if(mat_flag_2 == 1'b1 && mat_flag_4 == 1'b1) 
        po_flag             <=          1'b1;
    else
        po_flag             <=          1'b0;      
        

mat_3x3 mat_3x3_inst(
    //System Interfaces
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    //Communication Interfaces
    .rx_data                (rx_data                ),
    .pi_flag                (pi_flag                ),
    .mat_row1               (mat_row1               ),
    .mat_row2               (mat_row2               ),
    .mat_row3               (mat_row3               ),
    .mat_flag               (mat_flag               )

);
 

endmodule

這裏說明一下爲了文章的簡潔性,我們這裏不再給出整個工程的代碼,知識給出了中值濾波部分的程序。具體的項目工程代碼查看前面的文章***基於FPGA的圖像邊緣檢測***,至於要把這篇論文種的sobel模塊換成上面的sobel便可以完成圖像的中值濾波,至於這裏取名字sobel也只是因爲偷懶沒改模塊名。

測試模塊的代碼

測試模塊的代碼如下:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : tb_sobel.v
// Create Time  : 2020-04-08 09:19:44
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module tb_sobel();

//System Interfaces
reg                        sclk            ;
reg                        rst_n           ;
//Communication Interfaces
reg                [ 7:0]  rx_data         ;
reg                        pi_flag         ;
wire               [31:0]  tx_data         ;
wire                       po_flag         ; 
reg                [ 1:0]  cnt              ; 

initial begin
    sclk                =           1'b0;
    rst_n               <=          1'b0;
    pi_flag             <=          1'b0;
    rx_data             <=          8'd0;
    #(1000);
    rst_n               <=          1'b1;
    #(10000);
    gendata();
    #(10000);
    gendata();
end
always      #5          sclk            =       ~sclk;

task    gendata();
    integer         i           ;
    integer         j           ;
    begin
        for(j = 0;j < 768;j = j+1)
        begin
            for(i = 0;i < 1024;i = i+1)
            begin
                pi_flag = 1'b1;
                #10; 
                pi_flag = 1'b0;
                #20;    
            end
            pi_flag = 1'b0;
            #1000;
        end
    end
endtask

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt             <=      2'd0;
    else if(pi_flag == 1'b1 && cnt == 2'd2)
        cnt             <=      2'd0;
    else if(pi_flag == 1'b1)
        cnt             <=      cnt + 1'b1;
    else 
        cnt             <=      cnt;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rx_data             <=          8'd0;
    else if(cnt == 2'd2 && pi_flag == 1'b1 && rx_data == 1024-1) 
        rx_data             <=          8'd0;
    else if(cnt == 2'd2 && pi_flag == 1'b1)
        rx_data             <=          rx_data + 1'b1;
    else
        rx_data             <=          rx_data;

//sobel sobel_inst(
//    //System Interfaces
//    .sclk                       (sclk                       ),
//    .rst_n                      (rst_n                      ),
//    //Communication Interfaces
//    .rx_data                    (rx_data                    ),
//    .pi_flag                    (pi_flag                    ),
//    .tx_data                    (tx_data                    ),
//    .po_flag                    (po_flag                    )     
//);

conver_bit conver_bit_inst(
    //System Interfaces
    .sclk                       (sclk                       ),
    .rst_n                      (rst_n                      ),
    //Gigbit Interfaces
    .image_data                 (rx_data                    ),
    .image_data_en              (pi_flag                    ),
    //Communication Interfaces
    .rgb_data                   (tx_data                    ),
    .rgb_data_en                (po_flag                    )
);

endmodule

仿真結果

我們進行相應的仿真測試,結果如下:
在這裏插入圖片描述
從上圖中的關鍵數據可以發現我們完成了圖像的中值濾波。

下板結果

原圖像如下:
在這裏插入圖片描述
FPGA中值濾波處理之後的圖像如下:
在這裏插入圖片描述
從上面的圖像中,我們可以發現圖像中的突變噪聲被消除,但是圖像的邊緣也被取消一部分,從而證明了我們實驗的正確性。

總結

創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。(txt文件、圖片文件在羣中)對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章