近期在研究数字图像去噪方法,碰到了给图像加高斯白噪声的问题,颇为头疼,于是小小研究了一下,做个笔记记一下。
1. randn()
首先来说一下randn()这个函数,它是默认产生一个期望为0,标准差为1的正态分布,具体生成的是向量还是矩阵都是自行控制,比如下面这样可以产生一个期望为1,标准差为2的正态分布矩阵:
r=1+2.*randn(2,2)
r =
-1.0327 0.2521
1.0459 -0.7869
于是下面我们可以用randn()给图像添加均值为0,标准差为10,方差为100的高斯白噪声了:
origImg = imread('Lena.bmp');
figure, imshow(origImg,[])
% 关于此处用double的解释:原图是uint8格式的数据,而randn函数生成的是float类
% 型的数据,因此要进行数据类型转换
distImg = double(origImg) + 10*randn(size(origImg));
figure, imshow(distImg,[])
noise = distImg - double(origImg);
figure,imshow(noise,[])
var = var(double(noise(:))) % 方差
std = std2(noise) % 标准差
mean = mean2(noise) % 二维数组的均值
var =
101.0287
std =
10.0513
mean =
-0.0105
可以看到,所求出来的基本符合预期了。
2. wgn()
官方文档是这样写的:
y = wgn(m,n,power) generates an m-by-n matrix of white Gaussian noise. power specifies the power of y in decibels relative to a watt. The default load impedance is 1 ohm.
然后附加了一个例子:
% Generate a 1000-element column vector
% containing real white Gaussian noise of power 0 dBW.
y1 = wgn(1000,1,0);
% Confirm that the power is approximately 0 dBW, that is, 1 W.
var(y1)
ans = 0.9979
从上面的例子我们可以明白过来,其实产生的噪声的方差就是第三个参数的值,只不过在代码中要将其按照分贝(dB)来设置。我们常见的分贝是度量声音强度的单位。其转换公式为P(dB)=10lgP(W)。于是有了:
y = wgn(m,n,p) 产生一个m行n列的高斯白噪声的矩阵,p以dBW为单位指定输出噪声的强度(方差)。
同理,将上述添加噪声那句代码改为:
distImg=double(origImg) + wgn(size(origImg,1),size(origImg,2),20);
即可得到:
var =
99.7863
std =
9.9893
mean =
0.0065
也是符合要求的。
3. imnoise()
官方文档说明为:
J = imnoise(I,’gaussian’,M,V) adds Gaussian white noise of mean m and variance v to the image I. The default is zero mean noise with 0.01 variance.
也就是说M表示均值,V表示方差。
那么将添加噪声的代码改为:
distImg = imnoise(origImg, 'gaussian', 0, 10^2/255^2);
可得到:
var =
99.3884
std =
9.9694
mean =
-0.0197
Note : The mean and variance parameters for ‘gaussian’, ‘localvar’, and ‘speckle’ noise types are always specified as if the image were of class double in the range [0, 1]. If the input image is of class uint8 or uint16, the imnoise function converts the image to double, adds noise according to the specified type and parameters, and then converts the noisy image back to the same class as the input.
此处解释一下,原始图像origImg是uint8的灰度图像,灰度值范围为[0,255],故imnoise函数在处理时会将图像先转换为[0,1],然后按照所给的均值和方差添加噪声,最后再将图像转换到[0,255]的范围内,因此参数设置尤其要注意,如果所给的图像是uint8时,所给的均值和方差必须是在[0,1]的范围内,也就是说要归一化,不然直接给100的方差时,imnoise函数会将图像归一化,然后按照方差100来添加噪声,这样原先的图像就给淹没了,反而变成了噪声为主导。
笔者试了一下下面的情况:
1. 用imnoise()时不将噪声范围归一化
也就是
distImg = imnoise(origImg, 'gaussian', 0, 10^2);
结果如下:
var =
7.5061e+03
std =
86.6380
mean =
77.4065
很显然,图像和噪声已经倒置了,噪声成为了主导。
2. 将读取的图像用double()函数转换为浮点数
origImg = double(imread('Lena.bmp'));
同样添加噪声
distImg = imnoise(origImg, 'gaussian', 0, 10^2/255^2);
结果
var =
2.7662e+03
std =
52.5943
mean =
-94.8971
加完噪声以后,图像灰度范围变成了[0,1],且图像完全变成了噪声,这说明噪声和图像已经完全倒置了。
3. 将读取的图像用im2double()转换为[0,1]的浮点数
origImg = im2double(imread('Lena.bmp'));
结果得到:
var =
0.0015
std =
0.0389
mean =
2.0223e-04
显然方差就是直接按照10^2/255^2计算得到的,这也难怪,如果图像一开始灰度范围是[0,1], 那么我们所添加的噪声方差也只可能是这个范围了。
先写到这,后续再继续补充,欢迎纠错。