逆滤波与维纳滤波
一、算法描述
1.运动模糊
主要使用课本公式: H(u, v) = sin(pi * (a * u + b * v)) * exp(-1i * pi * (a * u + b * v)) * T / (pi * (a * u + b * v))。但另外需注意图像矩阵f在傅里叶变换前和傅里叶反变换后都要进行中心化,且退化函数H也要进行中心化。
2.加高斯噪声
加上噪声的图像是原图像矩阵加上单独产生的一个元素随机产生的矩阵而得到的图像,这个随机生成的等大矩阵上的每一位都互不相关,但产生的值的出现以0为均值,500为方差,是一个正负值都包含的矩阵。故原图像加上这个噪声矩阵后,每一位的像素值都会变大或变小,但变化情况呈以0为均值,根号500为标准差的高斯分布。
产生噪声矩阵的方法是,产生一个和原图像等大的、值在0到1之间的随机矩阵,作为概率矩阵。对每一个概率值在高斯分布上逆向求得对应该概率值的横坐标,该横坐标就是噪声矩阵对应位置上的值。这样产生的噪声矩阵就会服从以0为均值,500为方差的高斯分布。
3.逆滤波
在已知退化函数频谱H的情况下,由于退化过程G = F * H,那么反之,复原过程大致为F = G / H,这样虽然往往退化后的图像由于只取实部已丢失虚部信息,但还是能恢复较多的信息。
4.维纳滤波
主要根据维纳滤波公式:F(u,v) = (1 / H(u,v)) * (H(u,v)H*(u,v) / (H(u,v)H*(u,v) + Sn(u,v) / Sf(u,v)))。其中Sn(u,v) / Sf(u,v)是噪声功率谱和原图像功率谱的比值,由于该值较难确定,所以实验过程中用多个常数来替代该值,直到找到使恢复效果较优的值。
二.Matlab代码
(1)函数MotionBlur(运动模糊函数,传入原图像矩阵和退化函数频谱):
MotionBlur.m
function g = MotionBlur(f, H)
f = Centralize(f);
F = fft2(f);
G = F .* H;
g = ifft2(G);
g = real(g);
g = Centralize(g);
end
(2)高斯噪声函数GaussianNoise:
GaussianNoise.m
function gn = GaussianNoise(g, mean, var)
[height, width] = size(g);
noise = norminv(rand(height, width), mean, sqrt(var));
gn = noise + double(Expand(g));
end
(3)逆滤波函数InverseFilter:
InverseFilter.m
function f_inv = InverseFilter(g, H)
[height, width] = size(g);
G = fft2(Centralize(g));
B = BLPF(50, 2, height, width);
for u = 1 : height
for v = 1 : width
if abs(H(u, v)) < 0.001
tmp = 1;
else
tmp = H(u, v);
end
F(u, v) = G(u, v) * B(u, v) / tmp;
end
end
f_inv = ifft2(F);
f_inv = real(f_inv);
f_inv = Centralize(f_inv);
end
(4)维纳滤波函数WienerFilter:
WienerFilter.m
function f = WienerFilter(g, H, k)
G = fft2(Centralize(g));
H2 = H .* conj(H);
F = (G .* H2) ./ (H .* (H2 + k));
f = ifft2(F);
f = real(f);
f = Centralize(f);
end
(5)函数Centralize(中心变换):
Centralize.m
function mat = Centralize( mat )
[height, width] = size(mat);
for i = 1 : height
for j = 1 : width
if mod(i + j, 2) == 1
mat(i, j) = -mat(i, j);
end
end
end
end
(6)Butterworth低通滤波器BLPF:
BLPF.m
function H = BLPF( D0, order, height, width )
for i = 1 : height
x = i - (height / 2);
for j = 1 : width
y = j - (width / 2);
H(i, j) = 1 / (1 + ((x ^ 2 + y ^ 2) ^ order) / (D0 ^ (2 * order)));
end
end
end
(7)浮点数拉伸至0~255的函数Expand:
Expand.m
function new_img = Expand( img )
[height, width] = size(img);
max_pixel = max(max(img));
min_pixel = min(min(img));
for i = 1 : height
for j = 1 : width
new_img(i, j) = 255 * (img(i, j) - min_pixel) / (max_pixel - min_pixel);
end
end
new_img = uint8(new_img);
end
(8)调用以上函数,可直接运行的脚本Task:
Task.m
img = imread('book_cover.jpg');
[height, width] = size(img);
f = double(img);
a = 0.1;
b = 0.1;
T = 1;
for u = 1 : height
for v = 1 : width
vt = a * (u - height / 2) + b * (v - width / 2);
H(u, v) = sin(pi * vt) * exp(-1i * pi * vt) * T / (pi * vt);
if isnan(H(u, v)) == 1
H(u, v) = 1;
end
end
end
g = MotionBlur(f, H);
figure();
subplot(2, 2, 1);
imshow(Expand(g));
title('Blurred Image');
gn = GaussianNoise(g, 0, 500);
subplot(2, 2, 2);
imshow(Expand(gn));
title('Blurred Image with Gaussian Noise');
f_inv = InverseFilter(gn, H);
subplot(2, 2, 3);
imshow(uint8(f_inv));
title('Inverse Filtered Image');
f_wie = WienerFilter(gn, H, 0.01);
subplot(2, 2, 4);
imshow(uint8(f_wie));
title('Wiener Filtered Image');
三.处理结果
1.运动模糊
2.加高斯噪声
3.逆滤波
直接对运动模糊图像做逆滤波:
对运动模糊+高斯噪声图像做逆滤波:
4.维纳滤波
维纳滤波功率比值为0.01时:
过高或过低效果都会明显变差。
可以看到,两种滤波方式都能产生一些效果,原来模糊不堪的图片能看出一些内容了。但对于加噪声后的图像,逆滤波丢失的信息较多,恢复效果不会变得更好了;而维纳滤波功率比值为0.01时则效果明显要好多了,能看清封面上写的字了。