ITKeyword,专注技术干货聚合推荐

注册 | 登录

自适应图像降噪滤波器的设计与实现

baimafujinji 分享于 2017-06-16

2019阿里云双11返场狂欢继续,
地址https://www.aliyun.com/1111/2019/home

有一个说法:好奇心和懒惰是推动人类发明创造的两大动力!所以今天我又再次展现了我的好奇心。何况”我的眼里为什么常含着泪水,因为我有一个算法不会。“ 为了节约一点泪水,还是应该把一些算法搞清楚。

如果说让你对一幅含有噪声的图像进行去噪,你会想到什么最原始、最简单的、教科书上就会讲到的方法。我猜或许应该是Box Filter(也称均值滤波)或者Gaussian Filter,关于Box Filter可以参考本博主之间的一篇文章(文章链接)。但是无论Box Filter还是Gaussian Filter,它们的一个共有的不足就在于对待噪声和图像的纹理细节都采用一视同仁的处理方式,结果导致噪声被去掉的同时,图像的纹理和细节也会被一同磨平。这个Side effect是我们所不想见到的!

于是,几乎所有真正有价值的图像降噪方法都在试图让程序可以自适应地区隔无用的噪声和有用的图像纹理细节,然后再采取不同的处理方式,从而实现details preserving(或者edge preserving)。而且这样的方法还特别特别多,例如比较有名的双边滤波、基于PM方程的各向异性扩散滤波,以及基于TV-norm的去噪方法等等。关于这些内容你也可以参考《图像处理中的数学修炼》一书。在实际中,这些算法都具有非常广泛而重要的用途,例如医学影像处理中常常需要利用数字图像处理的技术对X-ray或者MRI图像等进行降噪,再比如现在手机中比较popular的美颜嫩肤都要以上面提到的那些details preserving的denoise算法。但是,上面提到的那些算法动辄就要用到像偏微分方程或者欧拉-拉格朗日方程等深奥晦涩的数学知识。我们能不能从一个比较简单的方法入手来一窥details preserving的denoise算法的能力和效果呢?这个可以有!


为什么开篇会提到好奇心这个问题呢?因为之前使用MATLAB时都知道其中的图像处理工具箱提供了一个wiener2函数,可以对图像进行降噪。从名字上看来它应该是利用了维纳滤波器来进行降噪的。但具体说它到底是怎么进行去噪的恐怕就很难说得清楚了。所以本文的源起也就是作者设法检视了一下MATLAB中的wiener2函数背后到底搞得什么鬼。例如上面是一张土星照片的局部图像。我们首先向其中加入一些高斯噪声(如下图左所示),然后再利用wiener2函数来对其进行降噪。效果如下图右所示。

可见原图像的纹理(例如图形环和远处的星辰等)都得到了很好的保护,而噪声也得到了有效的降低。但问题又回来了,wiener2函数到底是如何做到这一切的,其背后的原理是什么呢?

我们引入经典教科书中都会使用的一个图像退化模型,并以此作为算法讨论的开始。如下图所示,输入待处理图像 f(x,y) 在退化函数 H 的作用下,由于受到噪声 η(x,y) 的影响,最终得到一个退化图像 g(x,y) 。图像复原的过程就是在给定 g(x,y) 以及关于退化函数 H 和加性噪声 η(x,y) 的一些信息后,设法估计出原始图像的近似值 f^(x,y) 。当然,我们期望最终的近似值可以最大限度地逼近原始图像。显然关于 H 和 η 的信息掌握得越多,那么最终得到的估计结果就越接近原始图像。

如果 H 是一个线性移不变系统,那么在时域中给出的退化过程可由如下公式给出:

g(x,y)=h(x,y)∗f(x,y)+η(x,y) 其中, h(x,y) 是退化函数在时域下的表示,运算符 ∗ 表示时域卷积。由卷积定理可知,时域上的卷积等同于频域上的乘积,所以上式在频域中的表述如下: G(u,v)=H(u,v)F(u,v)+N(u,v) 其中的大写字母项是之前公式里对应项的傅里叶变换。


退化函数 H 通常是指模糊、抖动等影响,因为本文主要讨论降噪方法,于是处理对象仅仅是在噪声 η 的作用下受到污染的图像,所以现在的图像退化公式可以简化为: g(x,y)=f(x,y)+η(x,y) 此时,(相当于普通的Box Filter或者Gaussian Filter)一个更好的降噪方法被称为Adaptive Filter,它的公式为: f^(x,y)=g(x,y)−σ2gσ^2L[g(x,y)−μ^L] 其中, σ2g 是整张图像 g 中的噪声方差, μ^L 是点 (x,y) 附近的(一个窗口内)的像素灰度均值, σ^2L 是点 (x,y) 附近的(一个窗口内)的像素灰度的方差。其实你大概可以看出Adaptive Filter是用等式右端后面的一整项来作为(未知的)加性噪声的估计。那如何解释这样做的道理呢?我们可以从如下几个方面来考虑:

  • 如果 σ2g=0 ,即整幅图像的噪声方差为零,其实也就相当于噪声为0,而此时公式表示 f^(x,y)=g(x,y) ,恰好符合。
  • 如果 σ^2L>>σ2g ,这其实暗示这个局部包含的图像边缘、纹理、细节较多(因为大于整体噪声方差),而这部分内容是应该被保护的。此时公式变为 f^(x,y)=g(x,y) ,也就表示不需要做过多处理,也符合我们details preserving的需求。
  • 如果 σ^2L≈σ2g ,则有 f^(x,y)=μ^L ,这表明 (x,y) 处在一个普通的区域,此时便可以应用普通的均值滤波来做处理。

当然,上面这个算法其实还有一个地方是需要我们加以应对的,那就是我们需要估计 σ2g 。在wiener2函数的实现过程中,具体做法是:点 (x,y) 处的局部均值为

μL=1MN∑(x,y)∈Wg(x,y) 局部方差为 σ2L=1MN∑(x,y)∈Wg2(x,y)−μ2L 其中 W 是一个大小为 N×M 的图像 g 中点 (x,y) 邻域窗口。然后算法创造一个使用这些估计值的逐像素的维纳滤波器: f^(x,y)=μL+σ2L−v2σ2L[g(x,y)−μL] 其中, v2 是整体噪声的方差,即 σ2g 。If the noise variance is not given, here we use the average of all the estimated variances。如果你对维纳滤波器还不是很清楚也完全没有关系,因为前面的推导中其实已经得到我们现在需要的结果了。对上述等式的右侧做一些变量名替换,并进行简单的代数运算,可得: μL+σ2L−v2σ2L[g(x,y)−μL]=μ^L+[g(x,y)−μ^L]−σ2gσ^2L[g(x,y)−μL]=g(x,y)−σ2gσ^2L[g(x,y)−μL] 于是便得到了之前一模一样的结果。

这个方法看起来如此的简单,它真的能按照我们预期的那样工作吗?下面就在MATLAB中编程实现这个算法。

function [f,noise] = mywiener2(g, nhood, noise)

if (nargin<3)
    noise = [];
end

% Estimate the local mean of f.
localMean = filter2(ones(nhood), g) / prod(nhood);

% Estimate of the local variance of f.
localVar = filter2(ones(nhood), g.^2) / prod(nhood) - localMean.^2;

% Estimate the noise power if necessary.
if (isempty(noise))
  noise = mean2(localVar);
end

% Compute result
% f = localMean + (max(0, localVar - noise) ./ ...
% max(localVar, noise)) .* (g - localMean);
%
% Computation is split up to minimize use of memory for temp arrays.
f = g - localMean;
g = localVar - noise; 
g = max(g, 0);

f = localMean + ((f ./ max(localVar, noise)) .* g);

下面来试验一下上面这个看起来只有聊聊几行的简单函数是否可以实现保持图像细节的去噪功能。下面的MATLAB代码调用了上述函数,执行下面的代码将得到本文最开始所展示出来的效果图,而且这与直接调用wiener2函数所得之结果也是完全一致的。

RGB = imread('saturn.png');
I = rgb2gray(RGB);
I = I(601:1000,1:600);

J = imnoise(I,'gaussian',0,0.005);
J = im2double(J);

K = mywiener2(J,[5 5]);

figure;
imshow(I), title('original image');

figure;
subplot(1,2,1), subimage(J), title('noised image');
subplot(1,2,2), subimage(K), title('denoised image');

更多图像处理中的数学问题请参考《图像处理中的数学修炼》,也欢迎广大读者到图像处理书籍读者群中参与讨论学习,并交流关于图像去噪算法和PDE图像处理算法的研究心得。

有一个说法:好奇心和懒惰是推动人类发明创造的两大动力!所以今天我又再次展现了我的好奇心。何况”我的眼里为什么常含着泪水,因为我有一个算法不会。“ 为了节约一点泪水,还是应该把一些算

相关阅读排行


用户评论

游客

相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。