中值滤波matlab及FPGA实现
1赞中值滤波是一种统计排序滤波器,它使用一个像素领域中的灰度级的中值来代替该像素的值,对于某些类型的随机噪声,中值滤波可提供良好的去噪能力,且比相同尺寸的线性平滑滤波器带来的模糊更少。对于单极性或者双极性脉冲噪声,中值滤波尤其有效,因此对于被椒盐噪声污染的图像,往往可以选用中值滤波的方法来去噪。
下面介绍一种快速中值滤波算法,并提供一种在FPGA上实现的思路,在进行中值滤波时通常选用3*3窗口,因此使用类似上一篇博文中的方法,调用移位寄存器IP核,输出3行数据,进入第一级3*3共9个寄存器缓存。
(1) 第1个时钟周期,对a00和a01,a10和a11,a20和a21进行比较,大的放在前面,结果存入第2级3*3共9个寄存器;
(2) 第2个时钟周期,将a02分别和a00、a01,a12分别和a10、a11,a22分别a20、a21进行比较,并从左到右按从大到小排序,结果存入第3级3*3共9个寄存器;
(3) 第3个时钟周期,分别对列进行第一次排序,结果存入第4级3*3共9个寄存器;
(4) 第4个时钟周期,对列进行第二次排序,结果存入第5级3*3共9个寄存器中,经过4次比较,得到下图所示从左到右,从上到下都按从到大小的顺序排序的3*3窗口,通过简单分析可知,中值为a02、a11、a20中的一个,继续排序;
(5) 第5个时钟周期,对a02和a11进行排序,结果存入1*3共3个寄存器中;
(6) 第6个时钟周期,将a20分别和a02和a11进行排序,得到中值。
下面给出matlab实现的代码,可用作FPGA实现的参考
clc; clear all; close all; im1 = imread('lena_salt.tif'); %原始图像 [m,n] = size(im1); im2 = uint8(zeros(m,n)); %定义一滤波后图像 %为了实现对边缘的滤波,对图像进行扩展 im1_mid1 = uint16(zeros(m+2,n+2)); im1_mid1(2:m+1,2:n+1) = im1; im1_mid1(1,2:n+1) = im1_mid1(3,2:n+1); im1_mid1(m+2,2:n+1) = im1_mid1(m,2:n+1); im1_mid1(1:m+2,1) = im1_mid1(1:m+2,3); im1_mid1(1:m+2,n+2) = im1_mid1(1:m+2,n+2); %为了实现对边缘的滤波,对图像进行扩展 %定义3x3窗口,存储排序后的数据 im_mid1 = uint8(zeros(3,3)); im_mid2 = uint8(zeros(3,3)); im_mid3 = uint8(zeros(3,3)); im_mid4 = uint8(zeros(3,3)); im_mid5 = uint8(zeros(3,3)); for i=2:1:m+1 for j=2:1:n+1 %水平方向第1次调整顺序 if(im1_mid1(i-1,j-1)>=im1_mid1(i-1,j)) im_mid1(1,1) = im1_mid1(i-1,j-1); im_mid1(1,2) = im1_mid1(i-1,j); im_mid1(1,3) = im1_mid1(i-1,j+1); else im_mid1(1,1) = im1_mid1(i-1,j); im_mid1(1,2) = im1_mid1(i-1,j-1); im_mid1(1,3) = im1_mid1(i-1,j+1); end if(im1_mid1(i,j-1)>=im1_mid1(i,j)) im_mid1(2,1) = im1_mid1(i,j-1); im_mid1(2,2) = im1_mid1(i,j); im_mid1(2,3) = im1_mid1(i,j+1); else im_mid1(2,1) = im1_mid1(i,j); im_mid1(2,2) = im1_mid1(i,j-1); im_mid1(2,3) = im1_mid1(i,j+1); end if(im1_mid1(i+1,j-1)>=im1_mid1(i+1,j)) im_mid1(3,1) = im1_mid1(i+1,j-1); im_mid1(3,2) = im1_mid1(i+1,j); im_mid1(3,3) = im1_mid1(i+1,j+1); else im_mid1(3,1) = im1_mid1(i+1,j); im_mid1(3,2) = im1_mid1(i+1,j-1); im_mid1(3,3) = im1_mid1(i+1,j+1); end %水平方向第2次调整顺序 %水平方向第2次调整顺序 if(im_mid1(1,3)>=im_mid1(1,1)) im_mid2(1,1) = im_mid1(1,3); im_mid2(1,2) = im_mid1(1,1); im_mid2(1,3) = im_mid1(1,2); else if(im_mid1(1,3)im_mid1(1,2)) im_mid2(1,1) = im_mid1(1,1); im_mid2(1,2) = im_mid1(1,3); im_mid2(1,3) = im_mid1(1,2); else if(im_mid1(1,3)<=im_mid1(1,2)) im_mid2(1,:) = im_mid1(1,:); end end end if(im_mid1(2,3)>=im_mid1(2,1)) im_mid2(2,1) = im_mid1(2,3); im_mid2(2,2) = im_mid1(2,1); im_mid2(2,3) = im_mid1(2,2); else if(im_mid1(2,3) im_mid1(2,2)) im_mid2(2,1) = im_mid1(2,1); im_mid2(2,2) = im_mid1(2,3); im_mid2(2,3) = im_mid1(2,2); else if(im_mid1(2,3)<=im_mid1(2,2)) im_mid2(2,:) = im_mid1(2,:); end end end if(im_mid1(3,3)>=im_mid1(3,1)) im_mid2(3,1) = im_mid1(3,3); im_mid2(3,2) = im_mid1(3,1); im_mid2(3,3) = im_mid1(3,2); else if(im_mid1(3,3) im_mid1(3,2)) im_mid2(3,1) = im_mid1(3,1); im_mid2(3,2) = im_mid1(3,3); im_mid2(3,3) = im_mid1(3,2); else if(im_mid1(3,3)<=im_mid1(3,2)) im_mid2(3,:) = im_mid1(3,:); end end end %水平方向第2次调整顺序 %垂直方向第1次调整顺序 if(im_mid2(1,1)>=im_mid2(2,1)) im_mid3(1,1) = im_mid2(1,1); im_mid3(2,1) = im_mid2(2,1); im_mid3(3,1) = im_mid2(3,1); else im_mid3(1,1) = im_mid2(2,1); im_mid3(2,1) = im_mid2(1,1); im_mid3(3,1) = im_mid2(3,1); end if(im_mid2(1,2)>=im_mid2(2,2)) im_mid3(1,2) = im_mid2(1,2); im_mid3(2,2) = im_mid2(2,2); im_mid3(3,2) = im_mid2(3,2); else im_mid3(1,2) = im_mid2(2,2); im_mid3(2,2) = im_mid2(1,2); im_mid3(3,2) = im_mid2(3,2); end if(im_mid2(1,3)>=im_mid2(2,3)) im_mid3(1,3) = im_mid2(1,3); im_mid3(2,3) = im_mid2(2,3); im_mid3(3,3) = im_mid2(3,3); else im_mid3(1,3) = im_mid2(2,3); im_mid3(2,3) = im_mid2(1,3); im_mid3(3,3) = im_mid2(3,3); end %垂直方向第1次调整顺序 %垂直方向第2次调整顺序 if(im_mid3(3,1)>=im_mid3(1,1)) im_mid4(1,1) = im_mid3(3,1); im_mid4(2,1) = im_mid3(1,1); im_mid4(3,1) = im_mid3(2,1); else if(im_mid3(3,1) im_mid1(2,1)) im_mid4(1,1) = im_mid1(1,1); im_mid4(2,1) = im_mid1(3,1); im_mid4(3,1) = im_mid1(2,1); else if(im_mid3(1,3)<=im_mid3(1,2)) im_mid4(:,1) = im_mid3(:,1); end end end if(im_mid3(3,2)>=im_mid3(1,2)) im_mid4(1,2) = im_mid3(3,2); im_mid4(2,2) = im_mid3(1,2); im_mid4(3,2) = im_mid3(2,2); else if(im_mid3(3,2) im_mid1(2,2)) im_mid4(1,2) = im_mid1(1,2); im_mid4(2,2) = im_mid1(3,2); im_mid4(3,2) = im_mid1(2,2); else if(im_mid3(1,3)<=im_mid3(1,2)) im_mid4(:,2) = im_mid3(:,2); end end end if(im_mid3(3,3)>=im_mid3(1,3)) im_mid4(1,3) = im_mid3(3,3); im_mid4(2,3) = im_mid3(1,3); im_mid4(3,3) = im_mid3(2,3); else if(im_mid3(3,3) im_mid1(2,3)) im_mid4(1,3) = im_mid1(1,3); im_mid4(2,3) = im_mid1(3,3); im_mid4(3,3) = im_mid1(2,3); else if(im_mid3(1,3)<=im_mid3(1,3)) im_mid4(:,3) = im_mid3(:,3); end end end %垂直方向第2次调整顺序 %对角线方向调整顺序 if(im_mid4(1,3)>im_mid4(2,2) && im_mid4(2,2)>im_mid4(3,1)) im_mid5(1,3) = im_mid4(1,3); im_mid5(2,2) = im_mid4(2,2); im_mid5(3,1) = im_mid4(3,1); else if(im_mid4(1,3)>im_mid4(3,1) && im_mid4(3,1)>im_mid4(2,2)) im_mid5(1,3) = im_mid4(1,3); im_mid5(2,2) = im_mid4(3,1); im_mid5(3,1) = im_mid4(2,2); else if(im_mid4(2,2)>im_mid4(1,3) && im_mid4(1,3)>im_mid4(3,1)) im_mid5(1,3) = im_mid4(2,2); im_mid5(2,2) = im_mid4(1,3); im_mid5(3,1) = im_mid4(3,1); else if(im_mid4(2,2)>im_mid4(3,1) && im_mid4(3,1)>im_mid4(1,3)) im_mid5(1,3) = im_mid4(2,2); im_mid5(2,2) = im_mid4(3,1); im_mid5(3,1) = im_mid4(1,3); else if(im_mid4(3,1)>im_mid4(2,2) && im_mid4(2,2)>im_mid4(1,3)) im_mid5(1,3) = im_mid4(3,1); im_mid5(2,2) = im_mid4(2,2); im_mid5(3,1) = im_mid4(1,3); else if(im_mid4(3,1)>im_mid4(1,3) && im_mid4(1,3)>im_mid4(2,2)) im_mid5(1,3) = im_mid4(3,1); im_mid5(2,2) = im_mid4(1,3); im_mid5(3,1) = im_mid4(2,2); else im_mid5(1,3) = im_mid4(1,3); im_mid5(2,2) = im_mid4(2,2); im_mid5(3,1) = im_mid4(3,1); end end end end end end im2(i-1,j-1) = im_mid5(2,2); end end subplot(1,2,1); imshow(im1); subplot(1,2,2); imshow(uint8(im2));
测试结果如下,输入一幅被椒盐噪声污染的图像,输出滤波后的图像,效果还是很nice的。
上面的代码实现效率很低,不过对于FPGA板级实现倒是挺有参考价值,mathworks库中带有medfilt2函数,在matlab中可以地调用对于上位机上的中值滤波,建议用库中的函数。
参考:
1. 数字图像处理,Gonzalez
2. 图像实时滤波方法及其FPGA实现,杨免艳