使用巴特沃斯滤波器去除正弦噪声

15 投票
3 回答
6972 浏览
提问于 2025-04-16 12:48

我正在尝试去掉这张图片中的正弦噪声:

在这里输入图片描述

这是它的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 个回答

0

我觉得你把事情搞得有点复杂了。
如果你喜欢的话,就直接在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,[]);
3

我记得几年前在学习图像处理课程时玩过这张图片,结果和你一样。

我不知道教科书的作者是怎么得到书中展示的那张图片的,但他们肯定做了比仅仅应用巴特沃斯滤波器更多的事情。正如你提到的,那里有更多的峰值,所以他们可能使用了多个巴特沃斯滤波器来去除这些峰值。

不过,我发现图片的平均值是保持不变的。你有没有试着计算一下这两张图片的平均值并进行比较?可能只是显示时的缩放导致了更暗的图片。

6

我尝试使用了一个修改过的滤波器:
enter image description here
结果是这样的 ->
enter image description here
我不能完全解释这些结果,但我猜测是正弦噪声和主图像信号相互作用,产生了二次、三次等谐波噪声波。
结果也离理想状态还有差距,似乎还有一些噪声谐波残留在这里……
顺便说一下,感谢你提出这个有趣的问题。

编辑:

这是我第二次尝试改进滤波器。滤波器:
enter image description here
过滤后的结果:
enter image description here
这次似乎没有明显的正弦噪声模式可见。

撰写回答