中值滤波
Matlab实现图像滤波(叁):高效的中值滤波
文章目录
- 背景介绍
- 高效的中值滤波算法
- 算法的Matlab实现
- 结果验证
背景介绍
在Matlab实现图像滤波(贰)中介绍到了有关中值滤波的相关知识。
基本思想是:用一个中值滤波器窗口依次遍历整个图像,在每个位置都计算得到一个中值,然后将这些值拼在一起就得到了中值滤波后的图像。中值滤波可以很好地去除椒盐噪声,如:
参考代码:
% imgOrg = rgb2gray(imread("peppers.png")); imgOrg = imread("peppers.png"); imgOrg = imnoise(imgOrg, 'salt & pepper'); % Adding salt-pepper noise subplot(1,3,1); imshow(imgOrg); title("Originall img"); % median filter imgMedian = medianfilter(imgOrg, 3); % Generally, the size of a filter is an odd num subplot(1,3,2); imshow(imgMedian); title("Median filter img"); % Using Matlab API subplot(1,3,3); [~, ~, c] = size(imgOrg); newImg = zeros(size(imgOrg)); for i = 1:c newImg(:,:,i) = medfilt2(imgOrg(:,:,i)); end newImg = uint8(newImg); imshow(newImg); title("Medfilt img by API"); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function imgMedian = medianfilter(img,filterSize) % img: image % filterSize: if=5, it means 5*5 % Generate new blank image [h, w, c] = size(img); padSize = (filterSize-1)/2; imgMedianT = zeros([h+2*padSize, w+2*padSize, c]); imgMedianT(1+padSize:padSize+h, 1+padSize:padSize+w, :) = img; imgMedian = zeros([h, w, c]); for k = 1:c for i = 1:h for j = 1:w block = imgMedianT(i:i-1+filterSize, j:j-1+filterSize, k); imgMedian(i, j, k) = median(block, 'all'); end end end imgMedian = uint8(imgMedian); end
Elapsed time is 0.895780 seconds.
从上面可知,每次移动滤波器窗口就要重新求一次中值,而要求中值需要进行排序,所以开销很大,那么有没有更快地方法呢?请看下文。
高效的中值滤波算法
不难发现,每一移动滤波器窗口时,该窗口的变化为:丢掉最左边的一列而新增最右边的一列,对于m*n的中值滤波窗口,有mn-2m个像素没有发生变化,因此不需要重新排序。
由此我们得到新的算法:
设滤波器窗口大小为 x ∗ y = 3 ∗ 3 x ∗ y = 3 ∗ 3 x∗y=3∗3 ,一个图像的像素分布为
则:
Step 1
令 t = c e i l ( x y 2 ) \textcolor{FF8F80}{令t = ceil(\dfrac{xy}{2})} 令t=ceil(2xy)
解释: t = c e i l ( 3 ∗ 3 2 ) = 5 t=ceil(\dfrac{3*3}{2})=5 t=ceil(23∗3)=5 为排序后中位数所处的位置。取整可以避免不必要的浮点数运算。
Step 2
将 窗 口 移 至 一 个 新 行 的 开 始 , 对 其 内 容 排 序 。 建 立 窗 口 像 素 的 直 方 图 H , 确 定 其 中 值 m , 记 下 亮 度 ≤ m 的 像 素 数 目 n m \textcolor{FF8F80}{将窗口移至一个新行的开始,对其内容排序。建立窗口像素的直方图H,确定其中值m,记下亮度\leq m的像素数目n_m} 将窗口移至一个新行的开始,对其内容排序。建立窗口像素的直方图H,确定其中值m,记下亮度≤m的像素数目nm
解释:当滤波器移至如图示黄色区域窗口时:
n m n_m nm 相当于当前中值的位置,例如下图 3 ∗ 3 3*3 3∗3 滤波器窗口排序好后, 105 105 105 为中值,此时 n m = 5 n_m=5 nm=5 ,即此时中值的位置为 5 5 5 号位置。
Step 3
向 右 移 动 滤 波 器 , 对 于 移 出 的 左 列 的 每 个 亮 度 为 p g 的 像 素 p , 做 如 下 操 作 : H [ p g ] = H [ p g ] − 1 , 若 p g ≤ m , 则 n m = n m − 1 \textcolor{FF8F80}{向右移动滤波器,对于移出的左列的每个亮度为p_g的像素p,做如下操作:\\H[p_g] = H[p_g]-1,若p_g\leq m,则n_m=n_m-1} 向右移动滤波器,对于移出的左列的每个亮度为pg的像素p,做如下操作:H[pg]=H[pg]−1,若pg≤m,则nm=nm−1
解释:当滤波器移至如图示黄色区域窗口时:
最左侧(如红色部分)一列被移除,最右侧一列被移入。所以执行 H [ 0 ] = H [ 0 ] − 1 , H [ 84 ] = H [ 84 ] − 1 , H [ 105 ] = H [ 105 ] − 1 H[0]=H[0]-1,H[84]=H[84]-1,H[105]=H[105]-1 H[0]=H[0]−1,H[84]=H[84]−1,H[105]=H[105]−1 ,即:
由于 0 ≤ m , 84 ≤ m , 105 ≤ m , w h e r e m = 105 0\leq m, 84 \leq m, 105 \leq m, \space where\space m=105 0≤m,84≤m,105≤m, where m=105 ,所以现在的 n m = 5 − 1 − 1 − 1 = 2 n_m=5-1-1-1=2 nm=5−1−1−1=2
Step 4
对 于 移 入 的 右 列 的 每 个 亮 度 为 p g 的 像 素 p , 做 如 下 操 作 : H [ p g ] = H [ p g ] + 1 , 若 p g ≤ m , 则 n m = n m + 1 \textcolor{FF8F80}{对于移入的右列的每个亮度为p_g的像素p,做如下操作:\\H[p_g] = H[p_g]+1,若p_g\leq m,则n_m=n_m+1} 对于移入的右列的每个亮度为pg的像素p,做如下操作:H[pg]=H[pg]+1,若pg≤m,则nm=nm+1
解释:紧接着 S t e p 3 Step3 Step3 ,执行 H [ 55 ] = H [ 55 ] + 1 , H [ 120 ] = H [ 120 ] + 1 , H [ 255 ] = H [ 255 ] + 1 H[55]=H[55]+1,H[120]=H[120]+1,H[255]=H[255]+1 H[55]=H[55]+1,H[120]=H[120]+1,H[255]=H[255]+1 ,即:
由于 55 ≤ m w h e r e m = 105 55 \leq m\space where\space m=105 55≤m where m=105 ,所以现在的 n m = 2 + 1 = 3 n_m=2+1=3 nm=2+1=3
Step 5
若 n m = t , 则 跳 至 S t e p 8 若 n m < t , 则 跳 至 S t e p 6 若 n m > t , 则 跳 至 S t e p 7 \textcolor{FF8F80}{若n_m=t,则跳至Step8 \\ 若n_m < t,则跳至Step6 \\ 若n_m > t,则跳至Step7} 若nm=t,则跳至Step8若nm<t,则跳至Step6若nm>t,则跳至Step7
解释: n m = t n_m=t nm=t ,意味着,移动滤波器后,没有改变中值,所以无需进行额外操作。 n m ≠ t n_m\neq t nm=t ,意味着,移动滤波器后,改变了中值的位置,所以需要进行额外修正操作。这里, n m = 3 , t = 5 , n m < t = n_m=3,t=5,n_m<t= nm=3,t=5,nm<t= ,故跳至 S t e p 6 Step6 Step6 。其他情况类似,此处不再举例赘述。
Step 6
重 复 执 行 以 下 操 作 : m = m + 1 n m = n m + H [ m ] 直 到 n m ≥ t , 然 后 跳 至 S t e p 8 \textcolor{FF8F80}{重复执行以下操作:\\m=m+1 \\ n_m=n_m+H[m]\\直到n_m\geq t,然后跳至Step8} 重复执行以下操作:m=m+1nm=nm+H[m]直到nm≥t,然后跳至Step8
解释: m 从 105 开 始 往 上 增 , 当 m = 116 时 , 由 于 H [ 116 ] = 1 ( 有 一 个 像 素 的 亮 度 为 116 ) , 故 n m 加 1 得 到 n m = 4 。 在 116 120 之 间 , 不 存 在 亮 度 为 117 119 的 像 素 , 故 H [ m ] = 0 , n m 无 变 化 。 同 理 当 m = 120 时 , n m = 5 , 此 时 n m ≥ t = 5 , 故 跳 至 S t e p 8 m从105开始往上增,当m=116时,由于H[116]=1(有一个像素的亮度为116),故n_m加1得到n_m=4。在116\text{~}120之间,不存在亮度为117\text{~}119的像素,故H[m]=0,n_m无变化。同理当m=120时,n_m=5,此时n_m \geq t=5,故跳至Step8 m从105开始往上增,当m=116时,由于H[116]=1(有一个像素的亮度为116),故nm加1得到nm=4。在116 120之间,不存在亮度为117 119的像素,故H[m]=0,nm无变化。同理当m=120时,nm=5,此时nm≥t=5,故跳至Step8
注 意 , 若 有 两 个 像 素 的 亮 度 都 是 116 , 则 H [ 116 ] = 2 , n m 应 该 加 2 \textcolor{red}{注意,若有两个像素的亮度都是116,则H[116]=2,n_m应该加2} 注意,若有两个像素的亮度都是116,则H[116]=2,nm应该加2
Step 7
重 复 执 行 以 下 操 作 : n m = n m − H [ m ] m = m − 1 直 到 n m ≤ t , 然 后 跳 至 S t e p 8 \textcolor{FF8F80}{重复执行以下操作:\\ n_m=n_m-H[m] \\m=m-1 \\直到n_m\leq t,然后跳至Step8} 重复执行以下操作:nm=nm−H[m]m=m−1直到nm≤t,然后跳至Step8
解释:原理同 S t e p 6 Step6 Step6 ,这里不多赘述。
Step 8
记 录 m 为 当 前 窗 口 的 中 值 。 然 后 检 查 滤 波 窗 口 的 右 列 是 否 为 图 像 的 右 边 界 : 若 是 , 跳 至 S t e p 9 ; 反 之 , 跳 至 S t e p 3 \textcolor{FF8F80}{记录m为当前窗口的中值。然后检查滤波窗口的右列是否为图像的右边界:\\ 若是,跳至Step9;反之,跳至Step3} 记录m为当前窗口的中值。然后检查滤波窗口的右列是否为图像的右边界:若是,跳至Step9;反之,跳至Step3
解释:中值滤波窗口需要遍历图像的一整行。
Step 9
检 查 滤 波 窗 口 的 底 列 是 否 为 图 像 的 下 边 界 : 若 是 , 图 像 遍 历 完 成 , 算 法 结 束 ; 反 之 , 跳 至 S t e p 2 \textcolor{FF8F80}{检查滤波窗口的底列是否为图像的下边界:\\ 若是,图像遍历完成,算法结束;反之,跳至Step2} 检查滤波窗口的底列是否为图像的下边界:若是,图像遍历完成,算法结束;反之,跳至Step2
解释:中值滤波窗口需要遍历图像的每一行,一行滤波完成后换新行重复操作。
2 算法的Matlab实现
主文件main.m:
img = imnoise(imread("football.jpg"),'salt & pepper',0.1); filterSize = 5; % odd tic; newImg = effMedian(img, filterSize); toc; subplot(1,2,1); imshow(img); title("Original Image"); subplot(1,2,2); imshow(newImg); title("Filtered Image");
函数文件:
function [resultImg] = effMedian(inputImg, fSize) %EFFMEDIAN Summary of this function goes here % Detailed explanation goes here % inpuImg: input image % fSize: filter size x*x fSize = [fSize, fSize]; [ih, iw, ic] = size(inputImg); % height, width and channel of inputImg ch = round((fSize(1)-1)/2); cw = round((fSize(2)-1)/2); % padding inputImg tempImg = zeros([ih+ch*2, iw+cw*2, ic]); tempImg(1+ch:ih+ch, 1+cw:iw+cw, :) = inputImg; resultImg = zeros([ih, iw, ic]); % step1 t = ceil(fSize(1)*fSize(2)/2); for c = 1:ic for h = 1+ch:ih+ch % Step 9 w = 1+cw; H = zeros([1,256]); % histogram filterBlock = tempImg(h-ch:h+ch, w-cw:w+cw, c); tempBlock = filterBlock(:); for tmpi = 1:fSize(1)*fSize(2) H(tempBlock(tmpi)+1) = H(tempBlock(tmpi)+1)+1;% +1:亮度0对应位置1 end m = median(tempBlock); n_m = length(find(tempBlock <= m)); resultImg(h-ch,w-1,c) = m; for w = 2+cw:iw+cw % Step 8 moveOut = tempImg(h-ch:h+ch,w-1-cw,c); moveIn = tempImg(h-ch:h+ch,w+cw,c); tempBlock = moveOut(:); for tmpi = 1:fSize(1) % Step 3 H(tempBlock(tmpi)+1) = H(tempBlock(tmpi)+1)-1; end n_m = n_m - length(find(tempBlock <= m)); % Step 3 tempBlock = moveIn(:); for tmpi = 1:fSize(1) % Step 4 H(tempBlock(tmpi)+1) = H(tempBlock(tmpi)+1)+1; end n_m = n_m + length(find(tempBlock <= m)); % Step 4 jmpFlag = n_m - t; % Step 5 if (jmpFlag < 0) % Step 6 while(n_m < t) m = m + 1; n_m = n_m + H(m+1); end elseif (jmpFlag > 0) % Step 7 while(n_m > t) n_m = n_m - H(m+1); m = m - 1; end end resultImg(h-cw,w-cw,c) = m; end end end resultImg = uint8(resultImg); end
3 结果验证
Elapsed time is 0.759880 seconds.
显然,高效的中值滤波效果好的同时,实现了更少的开销。
4 工程下载地址
见文内代码