图像处理系列-均值滤波和中值滤波
1.均值滤波与中值滤波介绍
在经典书籍《数字图像处理第三版-冈萨雷斯》中介绍了滤波相关概念,并详细讲解了均值滤波与中值滤波的原理。如果本文有不详尽之处,可查阅本书P93平滑空间滤波部分。
宏观上,让我们了解均值滤波和中值滤波在图像处理中的位置。在数字图像处理中,滤波是很重要的一部分,均值滤波和中值滤波是都属于空间滤波(对于某一像素点,以该点为中心,通过对该像素点邻域部分的像素进行处理,得到中心替代像素点的滤波方法)中的平滑滤波方法(还有锐化滤波等)。进一步,平滑滤波分为平滑线性滤波器和平滑非线性滤波器,而均值滤波属于前者,中值滤波属于后者。
应用上,均值滤波处理高斯噪声效果较好,中值滤波处理椒盐噪声比较好,原因点击查看。
2.原理说明
对于通用的加权平滑滤波器,计算公式由下式给出:
其中f(x,y)为图像上坐标为(x,y)的点的灰度值,a与b为以(x,y)为中心的矩形(窗口)的半长与半宽,w(s,t)为给点(s,t)所加的权重。
对于窗口大小为3的均值滤波器,化简公式如下:
其中,Zi为以点(x,y)为中心,3×3的正方形中的九个点的灰度值。同理,窗口大小为n时,正方形的边长随之改变为n。可以看出,如果噪声为高斯噪声,测量值在真实值周围波动,取得平均之后会得到相对准确的值。
对于窗口大小为3的中值滤波器,f(x,y)的值应为Zi组成的数列(长度为9)的中值。可以看出,如果噪声为椒盐噪声,像素会出现剧烈跳动,而中值对极大值和极小值不敏感,取中值后可以很好过滤掉此类噪声。
3.图像边界处理
由于在窗口滑动的过程中,图像的边界不能作为小窗口的中心,故需要对图像边界进行一些人为处理。常见的处理方法如下。
- 不做处理咳咳咳。
- 忽略掉图像边界点,输出图像的尺寸会减小。
- 忽略掉图像边界点,滤波计算完成后裁剪掉未滤波的像素点,再将裁剪后的图像放大到原图大小。
- 根据窗口大小,想边界外填补一些像素,填充的像素灰度值与最近像素灰度值相同。
本文代码才用的是第三个处理方案,使用双线性插值法来放大。
4.效果
5.代码
clc;clear;
%% 参数输入区,在此选择窗口大小和滤波方式
filterSize = 7;
% filterMode = 'median';
filterMode = 'average';
I=imread('./circuit.jpg');
%% 开始运行
I = rgb2gray(I);
%%边界,数据格式(图像uint8,默认类型转换)
switch filterMode
case 'average'
[h,w] = size(I);
imageOut = zeros(h, w);%为了扩充图像而创建的临时图像
stepRange = (filterSize-1)/2;
%%外层两个for循环用来定位窗口中心,内层两个for用来窗口滤波计算
for pointRow = 1+stepRange : h-stepRange
for pointCol = 1+stepRange : w-stepRange
pixelSum = 0;
for i = pointRow-stepRange:pointRow+stepRange
for j = pointCol-stepRange:pointCol+stepRange
pixelSum = pixelSum + double(I(i, j));
end
end
pixelValue = pixelSum/filterSize^2;
imageOut(pointRow, pointCol) = uint8(pixelValue);
end
end
imageOut = uint8(imageOut); %double转化为uint8格式
imageOut = imcrop(imageOut,[1+stepRange,1+stepRange,w-2*stepRange-1,h-2*stepRange-1]);
imageOut = imresize(imageOut, [h, w], 'bilinear');
case 'median'
[h,w] = size(I);
imageOut = zeros(h, w);%为了扩充图像而创建的临时图像
stepRange = (filterSize-1)/2;
%%外层两个for循环用来定位窗口中心,内层两个for用来窗口滤波计算
for pointRow = 1+stepRange : h-stepRange
for pointCol = 1+stepRange : w-stepRange
pixelArray = zeros(1, filterSize^2);
ptrPA = 1;
for i = pointRow-stepRange:pointRow+stepRange
for j = pointCol-stepRange:pointCol+stepRange
pixelArray(ptrPA) = double(I(i, j));
ptrPA = ptrPA + 1;
end
end
imageOut(pointRow, pointCol) = uint8(median(pixelArray));
end
end
imageOut = uint8(imageOut); %double转化为uint8格式
imageOut = imcrop(imageOut,[1+stepRange,1+stepRange,w-2*stepRange-1,h-2*stepRange-1]);
imageOut = imresize(imageOut, [h, w], 'bilinear');
end
subplot(121),imshow(I);
subplot(122),imshow(imageOut);
impixelinfo;