在MATLAB的矩阵运算中,我们难免遇到除数为0的情况,一般来说,我们会选择将其置为eps或者sqrt(eps),但在官方文档中更多的是置为sqrt(eps),如维纳滤波器去卷积函数deonvwnr、有约束最小二乘去卷积函数deconvreg、Lucy-Richarson迭代法去卷积deconvlucy都有对0处理的代码块。
deconvwnr部分代码展示:
deconvreg部分代码展示:
deconvlucy部分代码展示:
一般来说,使用eps和sqrt(eps)是没有区别的,或者说觉得理所当然没有区别,都是非常小的数。实际上,如果在一个矩阵中,0不是成片出现的情况,也就是说在矩阵中偶尔出现一个0,使用eps和sqrt(eps)是没有区别的,但是如果矩阵中有一大片0出现,那么使用eps和sqrt(eps)处理的结果可能会完全不一样。
这是因为在傅里叶变换和傅里叶逆变换中,得到的很小的数可能会有正有负,当0聚集的时候,即使加上eps,这一片0得到的结果仍然会有正有负。虽然是小数,但是在正负波动会给后续傅里叶变换的处理带来错误计算。
例子:
clear
% 以运动模糊的点扩散函数为例
h = fspecial('motion',30,45);
H = psf2otf(h,[513,513]);
% 生成周边为0,中心为1的权重矩阵
% 其目的是产生聚集的0(边缘)
w = zeros(513,513);
w(20:end-19,20:end-19) = 1;
r = real(ifft2(H.*fft2(w))) + sqrt(eps);
% r = real(ifft2(H.*fft2(w))) + eps;
当使用的是sqrt(eps)时,也就是不注释的那一行,得到的边缘部分的值如图:
非常整齐、全为正的小数,如果运行最后一行注释的代码 ,将会得到:
有正有负的小数。
它可能会为后续的计算带来错误。
更多试验发现是:matlab中快速傅里叶变换时,如果矩阵的边长不是2的整数次幂,才会出现这样的情况。
使用eps带来恶劣影响的例子:
(其中图片自己随便导入一张就好)
clc
clear
close all
I = rgb2gray(im2double(imread('图片.png')));
I = im2double(I);
subplot(1,3,1),imshow(I);
LEN = 30;
THETA = 45;
h = fspecial('motion',30,45);
img_motion = imfilter(I,h,'circular');
%添加噪声
noise_var = 0.001;
img_motion = imnoise(img_motion,'gaussian',0,noise_var);
subplot(1,3,2),imshow(img_motion,[0,1])
w = zeros(size(img_motion));
w(20:end-19,20:end-19) = 1;
img_recov = deconvlucy(img_motion,h,10,sqrt(noise_var),w);
subplot(1,3,3),imshow(img_recov)
运行结果:
(左边是原图,中间是模糊图,右边是复原图)
当我们修改官方文档deconvlucy中的sqrt(eps)为eps后再运行代码:
则会得到如此不正确的图:
总的来说,对包含0元素多的矩阵进行处理的时候,我们可能需要一个比eps更大的一个小数,这时sqrt(eps)可以是一个很好的选择。