中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。方法是用某种结构的二维滑动模板,将板内像素按照像素值的大小进行排序,生成单调上升(或下降)的为二维数据序列。
简单来说:通常使用二维滑动模板,通过滑动,对模板内的数据进行排序,将排序后的中值提取出来,替换对应位置的数据,如图1所示,使用3*3模板,需替换第一个数据‘5’,则模板为[000,057,045]T,对其取中值替换‘5’;如替换第二行第5列数据‘4’,模板则为[268,349,10 6 10]T,对其取中值替换‘4’;
关于数据的获取,在此处,我们使用的是VGA/TFT显示屏来显示图像,因此,图像的获取是通过TFT控制器将数据逐行输出,数据从左到右依次输出,一行输出完毕,跳到下一行,继续从左到右依次输出;关于如何提取到需要的数据,且构成一个矩阵,在FPGA内,可以采用移位寄存的方法实现,实现方法如下:假如现在需要输入18个数据,如图2所示
假如我们现在有一个3行*6列的缓存器,可以将数据暂时缓存起来,数据从左到右,逐行输入这个缓存器,每个时钟输入一个数据,经12个时钟后,缓存器内数据应为如图3所示
我们可以看到,如果我们可以把圈内数据提取出来,对其进行中值处理,替换第一个数据,如何提取出来,我们可以用9个寄存器,通过不断移位,分别实现对3行数据的提取,相当于是一个3 * 3窗口,程序如下所示
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
line0_data0 <= 16'b0;
line0_data1 <= 16'b0;
line0_data2 <= 16'b0;
line1_data0 <= 16'b0;
line1_data1 <= 16'b0;
line1_data2 <= 16'b0;
line2_data0 <= 16'b0;
line2_data1 <= 16'b0;
line2_data2 <= 16'b0;
end
else if(data_in_en) begin
line0_data0 <= line0;
line0_data1 <= line0_data0;
line0_data2 <= line0_data1;
line1_data0 <= line1;
line1_data1 <= line1_data0;
line1_data2 <= line1_data1;
line2_data0 <= line2;
line2_data1 <= line2_data0;
line2_data2 <= line2_data1;
end
else ;
end
line0为图3第一行最后一个数据,line1为第二行最后一个数据,line2为第三行最后一个数据,
即在第12个时钟,line0 = 6,line1 = 0(寄存器在下一个时钟上升沿接收到数据)即line0_data0 = 6,line0_data1 = 5,line0_data2 = 4,line1_data0 = 0;
在第13个时钟,line0 = 7,line1 = 1,即line0_data0 = 7,line0_data1 = 6,line0_data2 = 5,line1_data0 = 1;
第14个时钟,line0 = 8,line1 = 2,line2 = 0,即line0_data0 = 8,line0_data1 = 7,line0_data2 = 6,line1_data0 = 2,line1_data1 = 1,line1_data2 = 0,line2_data0 = 0,line2_data1 = 0,line2_data2 = 0;可以看出,这9个数据构成了[8 7 6,2 1 0,0 0 0]T,是我们所需要的数据,对其进行中值运算后,替换第一个数据;
在第15个时钟,line0 = 9,line1 = 3,line2 = 0,即line0_data0 = 9,line0_data1 = 8,line0_data2 = 7,line1_data0 = 3,line1_data1 = 2,line1_data2 = 1,line2_data0 = 0,line2_data1 = 0,line2_data2 = 0;可以看出,这9个数据构成了[9 8 7 ,3 2 1 ,0 0 0]T,对其进行中值运算后,替换第二个数据,这就实现了3*3窗口滑动。
为了实现上述既可以缓存数据,又可以移位,又可以分别输出3个数据,在这里首先介绍一下Quartus Ⅱ软件内的IP核’shift_ram ’,此IP全称为:RAM-Based Shift Register ,即基于RAM的移位寄存器,其功能图如图5所示:此处设置的taps_distance为3,number_of_tap为4,即输出的taps的间隔为3,输出的taps为4,有4个输出(摘自shift_ram用户手册)(在创建IP核时可以对此进行设置),由此功能图可知,此IP核可以完美实现我们上述所需的功能。
如图6所示,第一步分别对三行像素进行排序:
由 L11,L12,L13 得到 L1max, L1mid, L1min;
由 L21,L22,L23 得到 L2max, L2mid, L2min;
由 L31,L32,L33 得到 L3max, L3mid, L3min。
第二步:
分别对三行像素中的 3 个最大,3 个中间和3个最小分别进行排序:
由 L1max, L2max, L3max 得到 Lmax_max, Lmax_mid, Lmax_min;
2)由 L1mid, L2mid, L3mid 得到 Lmid_max, Lmid_mid, Lmid_min;
3)由 Lmin, L2min, L3min 得到 Lmin_max, Lmin_mid, Lmin_min;
第三步:对最大的最小(Lmax_min),中间的中间(Lmid_mid)以及最小的最大
(Lmin_max)进行排序(例:由 Lmax_min,Lmid_mid,Lmin_max 得到midian)。
FPGA 的算法实现步骤基本如此。(注:此部分摘自“小梅哥基于 FPGA 的中值滤波算法的实现”);
数据获取部分可知:我们替换第二个数据,可得到的矩阵为[9 8 7 ,3 2 1 ,0 0 0]T,第一步, L1max = 9, L1mid = 8, L1min = 7;L2max = 3, L2mid = 2, L2min = 1;L3max = 0, L3mid = 0, L3min = 0;Lmax_max =9, Lmax_mid =3, Lmax_min =0; Lmid_max =8, Lmid_mid =2, Lmid_min =0;Lmin_max =7, Lmin_mid =1, Lmin_min =0;由Lmax_min =0、Lmid_mid =2、Lmin_max =7得midian = 2;
设置的数据如图7所示,现在需替换第2个数据“2000”;需获得的数据为[1000 2000 3000,9001 9002 9003];
仿真图如图8所示,2000为第二位取中值后的数据,红圈为取得的数据,因为由上述算法可知,对三行像素进行排序寄存一拍,对三行像素中的 3 个最大,3 个中间和3个最小分别进行排序进行寄存一拍,由 Lmax_min,Lmid_mid,Lmin_max 得到midian寄存一拍,因此数据是经3次寄存后输出的,因此取得的数据应为红圈处,由仿真可得,得到的数据与想要结果相同。
注:此文是对小梅哥图像处理部分基于 FPGA 的中值滤波算法的实现的理解,使用的代码和算法均来自于‘小梅哥图像处理部分基于 FPGA 的中值滤波算法的实现’