均值濾波
均值濾波的計算非常簡單,將圖像像素點灰度記錄在數組中,然後設置方框半徑的值,然後將方框中的所有點的像素求和取平均,得到的結果就是均值濾波後對應像素點的灰度值。
優點:
計算很快而且簡單
從算法可以看出,只是求了平均,並沒有很複雜的計算
缺點:
得到的圖像很模糊
當方框的半徑越大,得到的圖像中那些變化較大的地方(邊緣)計算後變化就越小,即邊緣不明顯,即模糊
非局部均值濾波
非局部均值濾波的基本原理與均值濾波類似,都是要取平均值,但是非局部均值濾波在計算中加入了每一個點的權重值,所以能夠保證在相鄰且相差很大的點在方框中求平均值時相互之間的影響減小,也就對圖像邊緣細節部分保留很多,這樣圖像看起來會更清晰。非局部均值濾波的算法我認爲可以大致分爲以下幾個步驟:
1. 首先在一個點A周圍取一個大的框(搜索框),設邊長爲s,A在方框的中心,然後再在方框中取小的方框,即相似框,設邊長爲d
2. 那麼在A周圍也有一個邊長爲d的方框,然後在大方框中找到所有邊長爲d的小方框的組合(就是一個小正方形在一個大正方形中到處移動,記錄小正方形中心點的座標就行了),設小方框的中心點爲B,分別於A周圍的相似框求減法,並且加入高斯覈計算得到的加權值,這樣可以計算出一個二維數組,裏面存放着各個點的差值乘以權重後的值,加入高斯核主要是因爲距離中心點距離不同對中心點的影響大小也不同,而且高斯核的權重和是1,所以就不用再歸一化了。
3. 然後將這個二維數組求和並平均,得到的值就是這個相似框的中心點B對於A的權重值。計算出A周圍所有點的權重值,其實這個時候這個值和權重是成反比的,以A本身爲例(以A爲中心點的相似框),計算出來A對於A的所謂權重值是零。然後根據計算出來的值用一個指數減函數就得到了成正比的權重關係,具體的函數見下面的代碼,w=exp(-d/h),就是這個,其中d就是計算出來的值啦,代入後w就是成正比的權重關係啦,h是一個濾波百分比值。可以先固定爲一個常數。 而且這個計算出來w就是一個(0,1)的值哦,自動歸一化啦
4. 然後就是根據得到的權重值以及各個點本身的灰度值計算出非局部均值濾波後A點的灰度值。
5. 以此類推,可以計算出圖中所有點經過非局部均值濾波後的值
優點
可以既去除噪聲,又保留圖像邊緣細節
當然去噪聲指的一般是高斯白噪聲,因爲高斯白噪聲的均值是0,所以求和取平均會比較有效果
缺點
計算起來很慢
如果圖像像素點比較多,而且計算的時候取的框還比較大的話,那麼計算一般幾分鐘是要的了。
function [output]=NLmeansfilter(input,t,f,h)
[m n]=size(input);
%f:搜索框半徑;t:相似框半徑;h:濾波頻率百分比
Output=zeros(m,n);
input2 = padarray(input,[f f],'symmetric');
%將邊緣對稱摺疊上去
% f :加寬的寬度值
kernel = make_kernel(f); %計算得到一個高斯核,用於後續的計算
kernel = kernel / sum(sum(kernel)); %sum:對矩陣k的每一列求和,k表示矩陣k的總和
h=h*h;
for i=1:m
for j=1:n
i1 = i+ f;
j1 = j+ f;
W1= input2(i1-f:i1+f , j1-f:j1+f);
wmax=0;
average=0;
sweight=0;
rmin = max(i1-t,f+1); %確定相似框的邊長,其實可以在代入數據的時候就設置搜索框和邊界框邊長的大小關係,就不用求最大最小值了
rmax = min(i1+t,m+f); %這段主要是控制不超出索引值
smin = max(j1-t,f+1);
smax = min(j1+t,n+f);
for r=rmin:1:rmax
for s=smin:1:smax
if(r==i1 && s==j1) continue; end;
W2= input2(r-f:r+f , s-f:s+f);
d = sum(sum(kernel.*(W1-W2).*(W1-W2)));
w=exp(-d/h);
if w>wmax
wmax=w;
end
sweight = sweight + w;
average = average + w*input2(r,s);
end
end
average = average + wmax*input2(i1,j1);
sweight = sweight + wmax;
if sweight > 0
output(i,j) = average / sweight;
else
output(i,j) = input(i,j);
end
end
end
function [kernel] = make_kernel(f) %這是一個高斯核
kernel=zeros(2*f+1,2*f+1);
for d=1:f
value= 1 / (2*d+1)^2 ;
for i=-d:d
for j=-d:d
kernel(f+1-i,f+1-j)= kernel(f+1-i,f+1-j) + value ;
end
end
end
kernel = kernel ./ f;