使用巴特沃斯滤波器去除正弦噪声
我正在尝试去掉这张图片中的正弦噪声:
这是它的DFT频谱(经过对数处理和任意强度缩放后):
我已经有一个巴特沃斯滤波器可以应用到这张图片上。它可以去掉中频的峰值。我在加载后小心地将其缩放从[0..255]到[0..1.0]。这是滤波器:
结果并不好:
我有几个问题:
- 为什么图片中仍然有相当多的噪声残留?
- 为什么结果比原图更暗?滤波器显然没有影响直流分量,所以我本以为平均亮度应该是一样的。
- 为什么滤波器只去掉了一些峰值?它来自一本教科书,所以我倾向于相信它是正确的,但频谱中还有其他峰值——它们也是噪声的一部分吗?我尝试用同心滤波器去掉它们,但效果不大,反而让图片变得模糊不清。
我从Gonzalez和Woods的书《数字图像处理》中获取了这张图片(裁剪过)和滤波器。在他们的例子中,周期性噪声通过滤波完全去掉,图片的平均亮度保持不变。
以下是我加载图片和滤波器、进行DFT、滤波和IDFT的源代码:
import cv
def unshift_crop(comp, width, height):
result = cv.CreateImage((width, height), cv.IPL_DEPTH_8U, 1)
for x in range(height):
for y in range(width):
real, _, _, _ = cv.Get2D(comp, x, y)
real = int(real) * ((-1)**(x+y))
cv.Set2D(result, x, y, cv.Scalar(real))
return result
def load_filter(fname):
loaded = cv.LoadImage(fname, cv.CV_LOAD_IMAGE_GRAYSCALE)
flt = cv.CreateImage(cv.GetSize(loaded), cv.IPL_DEPTH_32F, 2)
width, height = cv.GetSize(loaded)
for i in range(width*height):
px, _, _, _ = cv.Get1D(loaded, i)
#cv.Set1D(flt, i, cv.Scalar(px/255.0, 0))
cv.Set1D(flt, i, cv.Scalar(px/255.0, px/255.0))
return flt
if __name__ == '__main__':
import sys
fname, filt_name, ofname = sys.argv[1:]
img = cv.LoadImage(fname, cv.CV_LOAD_IMAGE_GRAYSCALE)
width, height = cv.GetSize(img)
src = cv.CreateImage((width*2, height*2), cv.IPL_DEPTH_32F, 2)
dst = cv.CreateImage((width*2, height*2), cv.IPL_DEPTH_32F, 2)
cv.SetZero(src)
for x in range(height):
for y in range(width):
px, _, _, _ = cv.Get2D(img, x, y)
px = float(px) * ((-1) ** (x+y))
cv.Set2D(src, x, y, cv.Scalar(px, 0))
cv.DFT(src, dst, cv.CV_DXT_FORWARD)
flt = load_filter(filt_name)
cv.Mul(dst, flt, src)
cv.DFT(src, dst, cv.CV_DXT_INV_SCALE)
result = unshift_crop(dst, width, height)
cv.SaveImage(ofname, result)
编辑
原始代码中有个错误,滤波器的虚部被加载为零。这导致结果图像看起来比实际更暗。我已经修复了这个问题,并注释了相关代码。
使用修复后的代码和@0x69提供的滤波器(是的,我知道这并不是真正的巴特沃斯滤波器,但在这个阶段我愿意尝试任何东西),这是结果:
比我开始时的结果好一些,但仍然没有达到我的期望。有没有人能做得更好?我怀疑增加更多的缺口来去掉剩余的峰值可能会有帮助。
编辑 2
我联系了作者。他们的回复是:
问题在于实验中使用的图像是浮点格式,而书中显示的(以及下载中提供的原始图像)是8位的。这是为了打印等需要。
为了重复实验,你必须从无噪声的图像开始,然后再添加你自己的噪声。
3 个回答
我觉得你把事情搞得有点复杂了。
如果你喜欢的话,就直接在Matlab上做吧。
这样能得到很不错的结果。
% Question: Filtration in Frequency Domain
im = imread('applo_noisy.tif');
FT = fft2(double(im));
FT1 = fftshift(FT);%finding spectrum
%imtool(abs(FT1),[]);
m = size(im,1);
n = size(im,2);
t = 0:pi/15:2*pi;
xc=(m+150)/2; % point around which we filter image
yc=(n-150)/2;
r=200;
r1 = 40;
xcc = r*cos(t)+xc;
ycc = r*sin(t)+yc;
xcc1 = r1*cos(t)+xc;
ycc1 = r1*sin(t)+yc;
mask = poly2mask(double(xcc),double(ycc), m,n); % Convert region-of-interest polygon to mask
mask1 = poly2mask(double(xcc1),double(ycc1), m,n); % generating mask for filtering
% a=51;
% b=5;
% a(b) = 0; % 51 0 0 0 0
mask(mask1)=0;
FT2=FT1;
FT2(mask)=0;%cropping area or bandreject filtering
output = ifft2(ifftshift(FT2));
imtool(output,[]);
我记得几年前在学习图像处理课程时玩过这张图片,结果和你一样。
我不知道教科书的作者是怎么得到书中展示的那张图片的,但他们肯定做了比仅仅应用巴特沃斯滤波器更多的事情。正如你提到的,那里有更多的峰值,所以他们可能使用了多个巴特沃斯滤波器来去除这些峰值。
不过,我发现图片的平均值是保持不变的。你有没有试着计算一下这两张图片的平均值并进行比较?可能只是显示时的缩放导致了更暗的图片。
我尝试使用了一个修改过的滤波器:
结果是这样的 ->
我不能完全解释这些结果,但我猜测是正弦噪声和主图像信号相互作用,产生了二次、三次等谐波噪声波。
结果也离理想状态还有差距,似乎还有一些噪声谐波残留在这里……
顺便说一下,感谢你提出这个有趣的问题。
编辑:
这是我第二次尝试改进滤波器。滤波器:
过滤后的结果:
这次似乎没有明显的正弦噪声模式可见。