在圖像預處理中,最基礎也最重要的處理方法是圖像濾波與增強。圖像濾波可以很好地消除測量成像或者環境帶來的隨機噪聲、高斯噪聲和椒鹽噪聲等。圖像增強可以增強圖像細節,提高圖像對比度。
濾波器的種類有很多種。按照輸出和輸入之間是否有唯一且確定的傳遞函數,我們可以把濾波器分為線性濾波器和非線性濾波器兩種。
非線性濾波器在通常情況下沒有特定的轉移函數。一類比較重要的非線性濾波就是統計排序濾波器,如中值濾波、最大/最小值濾波等。
中值濾波對於某些類型的隨機噪聲具有非常理想的降噪能力,對於線性平滑濾波而言,在處理像素鄰域之內的噪聲點時,噪聲的存在總會或多或少影響該點的像素值的計算(高斯平滑影響的程度與噪聲點到中心點的距離成正比),但在中值濾波中噪聲點則常常直接被忽略掉的;而且與線性平滑濾波器相比,中值濾波在降噪同時引起的模糊效應較低,進行中值濾波不僅可以去除孤點噪聲,而且可以保持圖像的邊緣特性,不會使圖像產生顯著的模糊,比較適合於實驗中的人臉圖像。中值濾波的一種典型應用是消除椒鹽噪聲(即黑白噪聲)。
一、理論分析
中值濾波方法是:對待處理的當前像素,選擇一個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圖像處理教程
