在图像预处理中,最基础也最重要的处理方法是图像滤波与增强。图像滤波可以很好地消除测量成像或者环境带来的随机噪声、高斯噪声和椒盐噪声等。图像增强可以增强图像细节,提高图像对比度。
滤波器的种类有很多种。按照输出和输入之间是否有唯一且确定的传递函数,我们可以把滤波器分为线性滤波器和非线性滤波器两种。
非线性滤波器在通常情况下没有特定的转移函数。一类比较重要的非线性滤波就是统计排序滤波器,如中值滤波、最大/最小值滤波等。
中值滤波对于某些类型的随机噪声具有非常理想的降噪能力,对于线性平滑滤波而言,在处理像素邻域之内的噪声点时,噪声的存在总会或多或少影响该点的像素值的计算(高斯平滑影响的程度与噪声点到中心点的距离成正比),但在中值滤波中噪声点则常常直接被忽略掉的;而且与线性平滑滤波器相比,中值滤波在降噪同时引起的模糊效应较低,进行中值滤波不仅可以去除孤点噪声,而且可以保持图像的边缘特性,不会使图像产生显著的模糊,比较适合于实验中的人脸图像。中值滤波的一种典型应用是消除椒盐噪声(即黑白噪声)。
一、理论分析
中值滤波方法是:对待处理的当前像素,选择一个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图像处理教程