NLmeans(非局部均值去噪)
非局部均值(NL-means)充分利用了图像中的冗余信息,在去噪的同时能最大程度地保持图像的细节特征。基本思想是:当前像素的估计值由图像中与它具有相似邻域结构的像素加权平均得到。
对于NLmeans算法我们会经常看到下面这张图。从这张图中我们可以看出算法的基本原理。图中有p,q1,q2,q3四个像素块,当前像素点的大小是由其他三个像素块的相似性所决定。
针对当前点像素,算法应该对整幅图像进行相关性搜索,也就是说,每计算一个像素点,都需要计算它与整幅图像的相似性,但是这样做需要耗费大量的运行时间,所以文章设定了两个窗口的定义,一个是搜索窗口,一个是邻域窗口,邻域窗口在搜索窗口中滑动,根据邻域间的相似性确定像素的权值。
NLmeans的执行过程如下图所示,大窗口是以目标像素为中心的搜索窗口,两个灰色小窗口分别是以
、
为中心的邻域窗口。其中以
为中心的邻域窗口在搜索窗口中滑动,通过计算两个邻域窗口间的相似程度为
赋以权值
。
算法核心步骤:
含噪声图像v,和去噪图像NL[v]:
权重w(i,j)表示像素点i,j之间的相似度,他是由i和j的矩形领域v(i)和v(j)中心点的欧氏距离所决定:,h为高斯核;
Z(i)表示归一化函数。
整个算法流程如下
Nlmeans算法由于需要进行窗口搜索,所以算法效率不高,但是具有较好的参考价值,值得学习一下。
matlab代码:
clc
clear
I=imread('lean.png');
I1=rgb2gray(I);
out=NLmeans(I1,7,21,20);
imshow([I1,out]);
function DenoisedImg=NLmeans(I,ds,Ds,h)
%I:含噪声图像
%ds:邻域窗口半径
%Ds:搜索窗口半径
%h:高斯函数平滑参数
%DenoisedImg:去噪图像
I=double(I);
[m,n]=size(I);
DenoisedImg=zeros(m,n);
PaddedImg = padarray(I,[ds,ds],'symmetric','both');
kernel=ones(2*ds+1,2*ds+1);
kernel=kernel./((2*ds+1)*(2*ds+1));
h2=h*h;
for i=1:m
for j=1:n
i1=i+ds;
j1=j+ds;
W1=PaddedImg(i1-ds:i1+ds,j1-ds:j1+ds);%邻域窗口1
wmax=0;
average=0;
sweight=0;
%%搜索窗口
rmin = max(i1-Ds,ds+1);
rmax = min(i1+Ds,m+ds);
smin = max(j1-Ds,ds+1);
smax = min(j1+Ds,n+ds);
for r=rmin:rmax
for s=smin:smax
if(r==i1&&s==j1)
continue;
end
W2=PaddedImg(r-ds:r+ds,s-ds:s+ds);%邻域窗口2
Dist2=sum(sum(kernel.*(W1-W2).*(W1-W2)));%邻域间距离
w=exp(-Dist2/h2);
if(w>wmax)
wmax=w;
end
sweight=sweight+w;
average=average+w*PaddedImg(r,s);
end
end
average=average+wmax*PaddedImg(i1,j1);%自身取最大权值
sweight=sweight+wmax;
DenoisedImg(i,j)=average/sweight;
end
end
结果
C++ opencv代码:参考https://zhuanlan.zhihu.com/p/45966784
参考以下博客
https://www.cnblogs.com/luo-peng/p/4785922.html
BM3D