【问题标题】:Creating a high pass filter in matlab在matlab中创建一个高通滤波器
【发布时间】:2018-06-23 22:45:32
【问题描述】:

我正在尝试在 Matlab 中创建一个高通滤波器。我使用

生成高斯内核
function kernel = compute_kernel(sigma,size)
[x,y] = meshgrid(-size/2:size/2,-size/2:size/2);
constant = 1/(2*pi*sigma*sigma);
kernel = constant*exp( -(y.^2 + x.^2 )/(2 * sigma * sigma));
kernel = (kernel - min(kernel(:)))./(max(kernel(:)) - min(kernel(:)));
end

然后在创建内核后,我用它为图像创建一个低通滤波器(变量im2):

g = compute_kernel(9,101);
im2_low = conv2(im2,g,'same');

据我了解,然后我可以使用从原始图像中减去过滤后的图像(在频域中)来提取高频,使其相当于高通滤波器。

F = fft2(im2_low);
IM2 = fft2(im2);
IM2_high = IM2 - F;

figure; fftshow(IM2_high);
im2_high = ifft2(IM2_high);
figure; imshow(im2_high,[]);

这似乎有什么问题。当我查看高通滤波图像时,它似乎是一个彩色反转模糊图像,而不是我在网上看到的边缘定义的图像。我不确定我的过程是否错误,或者我是否只是为我的高斯内核使用了错误的值。

【问题讨论】:

    标签: matlab image-processing


    【解决方案1】:

    这是一个简短问题的长答案。如果您想学习一些东西,请阅读它。

    低通滤波器和高通滤波器都是线性滤波器。 线性滤波器可以通过卷积在空间域中应用,也可以在频域(也称为傅里叶域)中作为乘法应用。

    确实,在傅里叶域中,低通滤波器内核和恒等滤波器(全通滤波器)的区别在于高通滤波器:

    high_pass_filter = identity_filter - low_pass_filter
    

    身份过滤器将是一个内核,其中每个元素都是 1。过滤器通过乘法应用,所以

    IM2 * high_pass_filter = IM2 * ( identity_filter - low_pass_filter )
    

    相同
    IM2 * high_pass_filter = IM2 - IM2 * low_pass_filter
    

    (这里,和问题一样,IM2 是图像im2 的傅立叶域表示;所有带有黄色边框的东西都是方程式,但都是用伪代码编写的,@ 987654329@ 用于乘法的符号)。

    因此,OP 想要应用低通滤波器并在傅里叶域中减去输入图像以获得高通滤波图像。

    但是,properties of the Fourier transform 之一是它是线性变换。这意味着

    F(a*f + b*g) == a * F(f) + b * F(g)
    

    (使用F(.) 傅里叶变换、ab 常量,以及fg 函数)。设置a=1b=-1g低通滤波图像和f输入图像,我们得到

    F(im2 - im2_low) == F(im2) - F(im2_low)
    

    也就是说,空间域和傅里叶域的减法是等价的。因此,如果在空间域中计算im2_low,则无需去傅里叶域进行减法。这两位代码产生相同的结果(达到数值精度):

    F = fft2(im2_low);
    IM2 = fft2(im2);
    IM2_high = IM2 - F;
    im2_high = ifft2(IM2_high);
    
    im2_high = im2 - im2_low;
    

    此外,卷积也是线性的。这意味着,如果您将上述等式中的F(.) 视为卷积,那么这些等式仍然成立。你可以做这样的操作:

    conv(f, h) - f == conv(f, h) - conv(f, 1) == conv(f, h-1)
    

    这直接导致了空间域中高通滤波器的定义:

    g = - compute_kernel(9,101);
    g(51,51) = g(51,51) + 1;
    im2_high2 = conv2(im2,g,'same');
    

    您会看到max(max(abs(im2_high-im2_high2))) 产生的值非常接近于 0。


    关于计算高斯滤波器的说明:

    问题中发布的compute_kernel 函数通过直接评估二维高斯来计算二维滤波器内核。生成的过滤器内核为 101x101 像素,这意味着计算卷积需要 101 * 101 * N 乘法和加法 (MAD),N 是过滤后图像中的像素数。但是,高斯滤波器是可分离的,这意味着只能在 101 * 2 * N MAD 中获得相同的结果(少 50 倍!)。此外,对于sigma = 9,也可以使用更小的内核。

    1. 高斯核大小:

      高斯函数永远不会达到零,但它会很快达到非常接近零的值。在3*sigma 切断它时,几乎没有丢失。我发现 3 sigma 是一个很好的平衡。在 sigma = 9 的情况下,3 sigma 截止导致内核具有 55 个像素 (3*sigma * 2 + 1)。

    2. 高斯可分性:

      多维高斯可以通过一维高斯相乘得到:

      exp(-(y.^2+x.^2)/(2*sigma*sigma)) == exp(-(x.^2)/(2*sigma*sigma)) * exp(-(y.^2)/(2*sigma*sigma))
      

      这导致卷积的实现更加高效:

      conv(f,h1*h2) == conv( conv(f,h1), h2 )
      

      也就是说,使用列过滤器h1 对图像进行卷积,然后使用行过滤器h2 对结果进行卷积与使用二维过滤器h1*h2 对图像进行卷积相同。在代码中:

      sigma = 9;
      sizei = ceil(3*sigma); % 3 sigma cutoff
      g = exp(-(-sizei:sizei).^2/(2*sigma.^2)); % 1D Gaussian kernel
      g = g/sum(g(:)); % normalize kernel
      im2_low = conv2(g,g,im2,'same');
      
      g2d = g' * g;
      im2_low2 = conv2(im2,g2d,'same');
      

      区别在于数值不精确:

      max(max(abs(im2_low-im2_low2)))
      
      ans =
         1.3927e-12
      

    您可以在我的博客上找到a more detailed description about Gaussian filtering,以及some issues you can run into when using MATLAB's Image Processing Toolbox

    【讨论】:

    • 很棒的答案。
    • 你似乎在做im2_low - im2,而不是im2 - im2_low。不应该是im2 - im2_low吗?
    • @user3927312:你说得对。感谢您指出。修复了帖子。
    【解决方案2】:

    任何你想用来维护图像特征的内核(即你不想要某物的大小,但图像看起来像人类可识别的图像)你需要确保你对内核做了一些事情:规范化它。

    您似乎已经尝试过,但您误解了内核中规范化的含义。不必为 [0-1],它们的 sum 需要为 1。

    所以,拿你的代码:

    im2=imread('https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png');
    im2=double(rgb2gray(im2));
    
    sigma=9;
    sizei=101;
    [x,y] = meshgrid(-sizei/2:sizei/2,-sizei/2:sizei/2);
    constant = 1/(2*pi*sigma*sigma);
    kernel = constant*exp( -(y.^2 + x.^2 )/(2 * sigma * sigma));
    %%%%%% NORMALIZATION
    kernel=kernel/sum(kernel(:));
    %%%%%%
    
    im2_low = conv2(im2,kernel,'same');
    
    F = fft2(im2_low);
    IM2 = fft2(im2);
    IM2_high = IM2 - F;
    
    
    im2_high = ifft2(IM2_high);
    figure; imshow(im2_high,[]);
    

    但是,正如 CrisLuengo 所提到的,减法是一种在傅立叶域中不会改变的运算,因此答案是

    im2_high=im2-im2_low
    

    【讨论】:

    • 现在试试这个。谢谢。
    • @user3927312 说服自己,尝试用彩条绘制im2_low,并检查极值。如果您想有意义地添加/减去它们,这两个图像应该在同一范围内。
    • 您的回答解决了我的问题。不过,我在理解您在上面评论中的意思时遇到了一些麻烦。如果你能解释得更多,那会有所帮助。如您所知,我是图像处理的新手。
    • 字面意思。在计算内核之后执行figure();imshow(im2_low,[]);colorbar;figure();imshow(im2,[]);colorbar;f。注意颜色条的值。在您的情况下,低通滤波器为数千,而原始图像仅达到 255。如果您想保持值的范围,则需要对内核进行归一化以加起来为 1。
    • 傅里叶域中的减法与空间域中的减法相同。对fftifft 的调用是多余的。
    猜你喜欢
    • 1970-01-01
    • 2011-08-01
    • 2013-03-29
    • 2014-07-06
    • 2017-09-17
    • 2010-12-17
    • 1970-01-01
    • 2015-07-10
    • 2012-09-22
    相关资源
    最近更新 更多