FPGA實現圖像的非線性濾波:中值濾波


  在圖像預處理中,最基礎也最重要的處理方法是圖像濾波與增強。圖像濾波可以很好地消除測量成像或者環境帶來的隨機噪聲、高斯噪聲和椒鹽噪聲等。圖像增強可以增強圖像細節,提高圖像對比度。
  濾波器的種類有很多種。按照輸出和輸入之間是否有唯一且確定的傳遞函數,我們可以把濾波器分為線性濾波器和非線性濾波器兩種。

  非線性濾波器在通常情況下沒有特定的轉移函數。一類比較重要的非線性濾波就是統計排序濾波器,如中值濾波、最大/最小值濾波等。

  中值濾波對於某些類型的隨機噪聲具有非常理想的降噪能力,對於線性平滑濾波而言,在處理像素鄰域之內的噪聲點時,噪聲的存在總會或多或少影響該點的像素值的計算(高斯平滑影響的程度與噪聲點到中心點的距離成正比),但在中值濾波中噪聲點則常常直接被忽略掉的;而且與線性平滑濾波器相比,中值濾波在降噪同時引起的模糊效應較低,進行中值濾波不僅可以去除孤點噪聲,而且可以保持圖像的邊緣特性,不會使圖像產生顯著的模糊,比較適合於實驗中的人臉圖像。中值濾波的一種典型應用是消除椒鹽噪聲(即黑白噪聲)。

 

一、理論分析

  中值濾波方法是:對待處理的當前像素,選擇一個3x3、5x5 或其他模板,該模板為其鄰近的若千個像素組成,對模板的像素由小到大進行排序,再用模板的中值來替代原像素的值。3x3 模板下的排序算法如圖所示:

二、MATLAB實現

clc;
clear all;
close all;

RGB = imread('flower.bmp');               %讀取圖片
imgn = imnoise(RGB,'salt & pepper',0.05); %椒鹽密度0.05
gray = im2double(rgb2gray(imgn));         %灰度圖

[ROW,COL, DIM] = size(gray);              %得到圖像行列數
%--------------------------------------------------------------------------
%                        Mean Filter 均值濾波
%--------------------------------------------------------------------------
Mean_Img = zeros(ROW,COL);
for r = 2:1:ROW-1
    for c = 2:1:COL-1
        Mean_Img(r,c) = (gray(r-1, c-1) + gray(r-1, c) + gray(r-1, c+1) + gray(r, c-1) + gray(r, c) + gray(r, c+1) + gray(r+1, c-1) + gray(r+1, c) + gray(r+1, c+1)) / 9;
    end
end
%--------------------------------------------------------------------------
%                        Median Filter 中值濾波
%--------------------------------------------------------------------------
Median_Img = zeros(ROW,COL);
for r = 2:ROW-1
    for c = 2:COL-1
        median3x3 =[gray(r-1,c-1)    gray(r-1,c) gray(r-1,c+1)
                    gray(r,c-1)      gray(r,c)      gray(r,c+1)
                    gray(r+1,c-1)      gray(r+1,c) gray(r+1,c+1)];
        sort1 = sort(median3x3, 2, 'descend');
        sort2 = sort([sort1(1), sort1(4), sort1(7)], 'descend');
        sort3 = sort([sort1(2), sort1(5), sort1(8)], 'descend');
        sort4 = sort([sort1(3), sort1(6), sort1(9)], 'descend');
        mid_num = sort([sort2(3), sort3(2), sort4(1)], 'descend');
        Median_Img(r,c) = mid_num(2);
    end
end
%--------------------------------------------------------------------------
%                           Show Image
%--------------------------------------------------------------------------
subplot(2,2,1); imshow(imgn);       title('椒鹽噪聲');
subplot(2,2,2); imshow(gray);       title('灰度圖');
subplot(2,2,3); imshow(Mean_Img);   title('均值濾波');
subplot(2,2,4); imshow(Median_Img); title('中值濾波');

% 由實驗可知:
% 1、椒鹽噪聲就是黑白噪聲,均值濾波對椒鹽噪聲基本無作用。
% 2、中值濾波對椒鹽噪聲的處理非常好。

  當我們使用3x3窗口后獲取領域中的9個像素,就需要對9個像素值進行排序,為了提高排序效率,排序算法思想如下所示。

  (1)對窗內的每行像素按降序排序,得到最大值、中間值和最小值。
  (2)把三行的最小值即第三列相比較,取其中的最大值。
  (3)把三行的最大值即第- -列相比較,取其中的最小值。
  (4)把三行的中間值即第二列相比較,再取一次中間值。
  (5)把前面的到的三個值再做一次排序,獲得的中值即該窗口的中值。

   MATLAB代碼中采用了 sort 排序函數,該函數使用方法如下所示:

sort(A)若A可以使矩陣或行列向量,默認都是對A進行升序排列。
sort (A)是默認的升序,而sort (A,' descend' )是降序排序。
sort(A)若A是矩陣,默認對A的各列進行升序排列
sort (A, dim)
dim=1時相當於sort (A)
dim=2時表示對矩陣A中的各行元素升序排列
sort(A,dim, ’descend' )則對矩陣的每行進行降序排列

  點擊運行,得到如下結果:

   結果可以看出:均值濾波對椒鹽噪聲無效,中值濾波則過濾了絕大部分椒鹽噪聲,如果還不夠可以再用一次中值濾波,達到滿意效果。

 

三、FPGA實現

 1、形成3x3矩陣

  這個在前面的博客花了3篇來解釋,就不多說了,我把3x3矩陣的代碼用一個專門的 .v 文件寫好,這里直接調用即可。輸入是灰度數據,即 YCbCr格式中的 8bit Y分量,輸出是矩陣數據。

//==========================================================================
//==    matrix_3x3_8bit,生成3x3矩陣,輸入和使能需對齊,耗費1clk
//==========================================================================
//--------------------------------------------------- 矩陣順序
//        {matrix_11, matrix_12, matrix_13}
//        {matrix_21, matrix_22, matrix_23}
//        {matrix_31, matrix_32, matrix_33}
//--------------------------------------------------- 模塊例化
matrix_3x3_8bit
#(
    .COL                    (480                    ),
    .ROW                    (272                    )
)
u_matrix_3x3_8bit
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .din_vld                (Y_de                   ),
    .din                    (Y_data                 ),
    .matrix_11              (matrix_11              ),
    .matrix_12              (matrix_12              ),
    .matrix_13              (matrix_13              ),
    .matrix_21              (matrix_21              ),
    .matrix_22              (matrix_22              ),
    .matrix_23              (matrix_23              ),
    .matrix_31              (matrix_31              ),
    .matrix_32              (matrix_32              ),
    .matrix_33              (matrix_33              )
);

2、sort排序

  MATLAB有sort函數,FPGA里可沒有,我們得自己寫一個,由於要用到多次,因此用一個.v文件來寫,用的時候調用即可。sort代碼如下所示:

 1 module sort
 2 //========================< 端口 >==========================================
 3 (
 4 //system --------------------------------------------
 5 input   wire                clk                     ,
 6 input   wire                rst_n                   ,
 7 //input ---------------------------------------------
 8 input   wire    [7:0]       data1                   ,
 9 input   wire    [7:0]       data2                   ,
10 input   wire    [7:0]       data3                   ,
11 //output --------------------------------------------
12 output  reg     [7:0]       max_data                , //最大值
13 output  reg     [7:0]       mid_data                , //中間值
14 output  reg     [7:0]       min_data                  //最小值
15 );
16 //==========================================================================
17 //==    最大值
18 //==========================================================================
19 always @(posedge clk or negedge rst_n) begin
20     if(!rst_n)
21         max_data <= 8'd0;
22     else if(data1 >= data2 && data1 >= data3) 
23         max_data <= data1;
24     else if(data2 >= data1 && data2 >= data3)
25         max_data <= data2;
26     else if(data3 >= data1 && data3 >= data2)
27         max_data <= data3;
28 end
29 //==========================================================================
30 //==    中間值
31 //==========================================================================
32 always @(posedge clk or negedge rst_n) begin
33     if(!rst_n)
34         mid_data <= 8'd0;
35     else if((data2 >= data1 && data1 >= data3) || (data3 >= data1 && data1 >= data2))
36         mid_data <= data1;
37     else if((data1 >= data2 && data2 >= data3) || (data3 >= data2 && data2 >= data1))
38         mid_data <= data2;
39     else if((data1 >= data3 && data3 >= data2) || (data1 >= data3 && data3 >= data2))
40         mid_data <= data3;
41 end
42 //==========================================================================
43 //==    最小值
44 //==========================================================================
45 always @(posedge clk or negedge rst_n) begin
46     if(!rst_n)
47         min_data <= 8'd0;
48     else if(data3 >= data2 && data2 >= data1)
49         min_data <= data1;
50     else if(data3 >= data1 && data1 >= data2)
51         min_data <= data2;
52     else if(data1 >= data2 && data2 >= data3)
53         min_data <= data3;
54 end
55 
56 
57 
58 endmodule 

3、調用sort,完成中值濾波

  調用上面寫好的 sort 就行了,注意一下整個的邏輯,消耗了3個時鍾周期。

  (1)對窗內的每行像素按降序排序,得到最大值、中間值和最小值。
  (2)把三行的最小值即第三列相比較,取其中的最大值。
  (3)把三行的最大值即第- -列相比較,取其中的最小值。
  (4)把三行的中間值即第二列相比較,再取一次中間值。
  (5)把前面的到的三個值再做一次排序,獲得的中值即該窗口的中值。

  第1個周期實現(1),第2個周期實現(2)(3)(4),第3個周期實現(5)。

//==========================================================================
//==    中值濾波,耗費3clk
//==========================================================================
//每行像素降序排列,clk1
//---------------------------------------------------
//第1行
sort u1
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (matrix_11              ), 
    .data2                  (matrix_12              ), 
    .data3                  (matrix_13              ),
    .max_data               (max_data1              ),
    .mid_data               (mid_data1              ),
    .min_data               (min_data1              )
);

//第2行
sort u2
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (matrix_21              ),
    .data2                  (matrix_22              ),
    .data3                  (matrix_23              ),
    .max_data               (max_data2              ),
    .mid_data               (mid_data2              ),
    .min_data               (min_data2              )
);

//第3行
sort u3
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (matrix_31              ),
    .data2                  (matrix_32              ),
    .data3                  (matrix_33              ),
    .max_data               (max_data3              ),
    .mid_data               (mid_data3              ),
    .min_data               (min_data3              )
);

//三行的最小值取最大值
//三行的中間值取中間值
//三行的最大值取最小值,clk2
//---------------------------------------------------
//min-max
sort u4
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (min_data1              ),
    .data2                  (min_data2              ),
    .data3                  (min_data3              ),
    .max_data               (min_max_data           ),
    .mid_data               (                       ),
    .min_data               (                       )
);

//mid-mid
sort u5
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (mid_data1              ),
    .data2                  (mid_data2              ),
    .data3                  (mid_data3              ),
    .max_data               (                       ),
    .mid_data               (mid_mid_data           ),
    .min_data               (                       )
);

//max-min
sort u6
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (max_data1              ), 
    .data2                  (max_data2              ), 
    .data3                  (max_data3              ),
    .max_data               (                       ),
    .mid_data               (                       ),
    .min_data               (max_min_data           )
);

//前面的三個值再取中間值,clk3
//---------------------------------------------------
sort u7
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (max_min_data           ),
    .data2                  (mid_mid_data           ), 
    .data3                  (min_max_data           ),
    .max_data               (                       ),
    .mid_data               (median_data            ),
    .min_data               (                       )
);

4、信號同步

  形成3x3矩陣耗費1clk,中值濾波耗費3clk,因此行場和使能信號都需要延遲4拍。

//==========================================================================
//==    信號同步
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        Y_de_r    <= 4'b0;
        Y_hsync_r <= 4'b0;
        Y_vsync_r <= 4'b0;
    end
    else begin  
        Y_de_r    <= {Y_de_r[2:0],    Y_de};
        Y_hsync_r <= {Y_hsync_r[2:0], Y_hsync};
        Y_vsync_r <= {Y_vsync_r[2:0], Y_vsync};
    end
end

assign median_de    = Y_de_r[3];
assign median_hsync = Y_hsync_r[3];
assign median_vsync = Y_vsync_r[3];

 

四、上板驗證

  同樣取一張含有椒鹽噪聲的圖片來看現象。

  原圖:

  中值濾波后:

  從實驗結果看出,椒鹽噪聲都被過濾了,實驗成功。

  我的板子壞了,出現一些不該有的橫條,如果是好的板子則沒有這些鬼東西。

 

參考資料:

[1] OpenS Lee:FPGA開源工作室(公眾號)

[2] CrazyBingo:基於VIP_Board Mini的FPGA視頻圖像算法(HDL-VIP)開發教程-V1.6 

[3] NingHechuan:FPGA圖像處理教程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM