【问题标题】:How to write fftshift and ifftshift in R? [closed]如何在 R 中编写 fftshift 和 ifftshift? [关闭]
【发布时间】:2016-07-06 18:04:01
【问题描述】:

numpy中,我们有以下功能:

import numpy
from numpy.fft import fft2, ifft2, fftshift, ifftshift

我想在 R 中重写这些函数。R 中的 fft 与 python 中的 fftfft2 一样。同样对于ifft2,我们必须做fft(,inverse=T)

现在我想知道如何在 R 中高效地重写 fftshiftifftshift 函数(用于矩阵)。

【问题讨论】:

  • 感谢您的评论。 SynchWave 中的功能仅适用于矢量。我会尝试用matlab doc重写。
  • 好的,你想要二维矩阵吗?我可以为你写点东西。
  • 是的!谢谢你,你真是太好了!
  • 当然可以。请稍等。
  • 其实我是在学习图像处理(频率过滤)。我想知道是否可以直接进行 fft,而无需 fftshift。我尝试在 R 中重现代码here。我注意到,如果我应用不带移位的高斯滤波器,它会给出非常不同的东西。你有一个玩具例子来解释 2D fft 吗?我问了一个很naive question here

标签: python r numpy fft ifft


【解决方案1】:

fftshiftifftshift 背后的概念非常简单。这是我从 MathWorks(MATLAB 的创建者)中提取的一个图:

Source: MathWorks doc page on fftshift

假设您的输入 2D 矩阵被分成多个象限。第 1 象限在左上角,第 2 象限在右上角,第 3 象限在右下角,第 4 象限在左下角。对于二维矩阵,fftshift 默认交换第一和第三象限以及第二和第四象限。您可以覆盖此行为,您可以简单地在一个维度上单独执行fftshift。如果你这样做,你正在交换所谓的半空格。如果您指定沿行交换(即维度 1),则矩阵的上半部分与下半部分交换。如果您指定沿列交换(即维度 2),则右半部分与左半部分交换:

Source: MathWorks doc page on fftshift

默认情况下,使用fftshift 将依次交换维度 1 和维度 2。如果您有一个偶数大小的矩阵,其中行和列是偶数,那么将矩阵切割成四个部分并进行交换是非常明确的。但是,如果矩阵是 odd 大小的,则取决于您正在查看的语言。例如,在 MATLAB 和 Python numpy 中,执行切换的位置定义为(r,c) = ceil(rows/2), ceil(cols/2),其中rowscols 是矩阵的行和列。 rc 是发生交换的行和列。

对于ifftshift,您只需反转fftshift 上执行的操作。因此,默认操作是交换维度 2 和维度 1。但是,对于奇数维度的矩阵,您必须重新定义切换中心的位置。您必须使用floor 而不是ceil,因为这精确地确定了在执行fftshift 之后 半空间的位置,并且您现在正在撤消对原始矩阵所做的操作。因此,新的切换中心是(r,c) = floor(rows/2), floor(cols/2)。除此之外,单个维度之间的交换逻辑是一样的——只是切换的中心已经改变了。

因此,这就是我想出的。这些函数采用 R 中定义的矩阵以及第二个可选参数来确定要交换的维度。省略它会执行我刚才谈到的默认象限交换:

fftshift <- function(input_matrix, dim = -1) {

    rows <- dim(input_matrix)[1]    
    cols <- dim(input_matrix)[2]    

    swap_up_down <- function(input_matrix) {
        rows_half <- ceiling(rows/2)
        return(rbind(input_matrix[((rows_half+1):rows), (1:cols)], input_matrix[(1:rows_half), (1:cols)]))
    }

    swap_left_right <- function(input_matrix) {
        cols_half <- ceiling(cols/2)
        return(cbind(input_matrix[1:rows, ((cols_half+1):cols)], input_matrix[1:rows, 1:cols_half]))
    }

    if (dim == -1) {
        input_matrix <- swap_up_down(input_matrix)
        return(swap_left_right(input_matrix))
    }
    else if (dim == 1) {
        return(swap_up_down(input_matrix))
    }
    else if (dim == 2) {
        return(swap_left_right(input_matrix))
    }
    else {
        stop("Invalid dimension parameter")
    }
}

ifftshift <- function(input_matrix, dim = -1) {

    rows <- dim(input_matrix)[1]    
    cols <- dim(input_matrix)[2]    

    swap_up_down <- function(input_matrix) {
        rows_half <- floor(rows/2)
        return(rbind(input_matrix[((rows_half+1):rows), (1:cols)], input_matrix[(1:rows_half), (1:cols)]))
    }

    swap_left_right <- function(input_matrix) {
        cols_half <- floor(cols/2)
        return(cbind(input_matrix[1:rows, ((cols_half+1):cols)], input_matrix[1:rows, 1:cols_half]))
    }

    if (dim == -1) {
        input_matrix <- swap_left_right(input_matrix)
        return(swap_up_down(input_matrix))
    }
    else if (dim == 1) {
        return(swap_up_down(input_matrix))
    }
    else if (dim == 2) {
        return(swap_left_right(input_matrix))
    }
    else {
        stop("Invalid dimension parameter")
    }
}

在每个函数中,我定义了交换左半部分和右半部分以及上半部分和下半部分的函数。要交换左右两半,只需确定您用于执行交换的列并使用索引通过将这两半连接在一起来创建一个新矩阵,其中前半部分是右半部分,后半部分是左半部分.在交换上半部和下半部时您会做同样的事情,但要找到正确的行来执行交换。

第二个参数dim可以选择设置为1或2来交换对应的维度。请注意,fftshiftifftshift 之间的唯一区别是定义的交换中心以及默认交换两个维度时的操作顺序。其余代码相同。

作为演示的一种方式,假设我已经声明了一个 5 x 5 的数字矩阵,如下所示:

> O <- matrix(1:25, 5, 5)
> O
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    6   11   16   21
[2,]    2    7   12   17   22
[3,]    3    8   13   18   23
[4,]    4    9   14   19   24
[5,]    5   10   15   20   25

请注意,矩阵的大小在两个维度上都是奇数。执行fftshift 会给我们:

> P <- fftshift(O)
> P
     [,1] [,2] [,3] [,4] [,5]
[1,]   19   24    4    9   14
[2,]   20   25    5   10   15
[3,]   16   21    1    6   11
[4,]   17   22    2    7   12
[5,]   18   23    3    8   13

可以看到对应的维度已经交换了。用ifftshift 反转这个应该给我们原来的矩阵,它确实:

> Q <- ifftshift(P)
> Q
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    6   11   16   21
[2,]    2    7   12   17   22
[3,]    3    8   13   18   23
[4,]    4    9   14   19   24
[5,]    5   10   15   20   25

当然,您可以覆盖它并指定要交换的维度,假设您只想交换行:

> fftshift(O, 1)
     [,1] [,2] [,3] [,4] [,5]
[1,]    4    9   14   19   24
[2,]    5   10   15   20   25
[3,]    1    6   11   16   21
[4,]    2    7   12   17   22
[5,]    3    8   13   18   23

> ifftshift(fftshift(O, 1), 1)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    6   11   16   21
[2,]    2    7   12   17   22
[3,]    3    8   13   18   23
[4,]    4    9   14   19   24
[5,]    5   10   15   20   25

请注意,当您对一维交换的矩阵执行 ifftshift 时,您必须使用与使用 fftshift 时用于交换的相同维度,以确保获得原矩阵回来了。

我们也可以对第二个维度做同样的事情:

> ifftshift(O, 2)
     [,1] [,2] [,3] [,4] [,5]
[1,]   11   16   21    1    6
[2,]   12   17   22    2    7
[3,]   13   18   23    3    8
[4,]   14   19   24    4    9
[5,]   15   20   25    5   10

> ifftshift(fftshift(O, 2), 2)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    6   11   16   21
[2,]    2    7   12   17   22
[3,]    3    8   13   18   23
[4,]    4    9   14   19   24
[5,]    5   10   15   20   25

作为一个有趣的说明,我们可以验证numpy 与我们上面讨论的相同。这是一个 IPython 会话:

In [16]: import numpy as np

In [17]: from numpy.fft import fftshift, ifftshift

In [18]: O = np.reshape(np.arange(1,26), (5,5)).T

In [19]: O
Out[19]:
array([[ 1,  6, 11, 16, 21],
       [ 2,  7, 12, 17, 22],
       [ 3,  8, 13, 18, 23],
       [ 4,  9, 14, 19, 24],
       [ 5, 10, 15, 20, 25]])

In [20]: fftshift(O)
Out[20]:
array([[19, 24,  4,  9, 14],
       [20, 25,  5, 10, 15],
       [16, 21,  1,  6, 11],
       [17, 22,  2,  7, 12],
       [18, 23,  3,  8, 13]])

In [21]: ifftshift(fftshift(O))
Out[21]:
array([[ 1,  6, 11, 16, 21],
       [ 2,  7, 12, 17, 22],
       [ 3,  8, 13, 18, 23],
       [ 4,  9, 14, 19, 24],
       [ 5, 10, 15, 20, 25]])

numpy 以及numpy.fft 包中的fftshiftifftshift 被导入并创建一个与您在R 中定义的示例中看到的相同的二维矩阵。然后我们调用@ 987654365@,然后是fftshiftifftshift,我们可以看到我们得到的结果与 R 代码中看到的相同。

【讨论】:

  • 我应用到我的图像上,它是奇妙的高斯模糊!非常感谢。
  • @XRSC 不客气!
猜你喜欢
  • 2013-02-12
  • 1970-01-01
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
  • 2011-02-23
  • 1970-01-01
相关资源
最近更新 更多