二维离散快速傅里叶变换公式-二维离散快速傅里叶变换公式
2D FFT 这东西,别老想着把它当成一个冷冰冰的公式堆砌。它就像把一张大网撒在二维棋盘上,先把该留的留,该打的打,最终剩下的全是“干净利落”的块儿。
这种处理方式在图像处理、信号处理里特别好用,比如咱们做视频压缩要么做图像边缘检测,直接切分解离成二维的块儿,处理速度比在脑子里搞半天快多了。 刚启动看公式,脑子里肯定会蹦出“离散傅里叶变换”这四个大字。但实际写代码动笔的时候,你会发现它本质上就是个循环的魔法。
要是咱们只有二维的数据,那它就能自动变成四个独立的二维数组,要么拆成两个“一维”的难题来解。
要是数据量不大,哪怕手写个几十行的代码都能跑通,这时候你看代码像不像数学公式?反正那时候不算啥。 真正有意思的时候,是数据量大了,内存都装不下,要么核心算法特别吃内存的时候,这时候就得用到 FFT 了。
这时候公式就不再是那样死板的美式,而是变成了一个动态计算的过程。 咱们拿一个二维矩阵 $X$ 来举例,假设它是 $N times M$ 的。它对应的频率域数据就是 $X_{uv}$,记在数组 $Y$ 里。计算公式里有个 $N^2 M^2$ 这一项,那是重点。别看数字多,实际运行里它往往是个循环,效率没那么低。
要是咱们把数据设得有点大,比如 $64 times 64$,那每个点的计算量都挺大,但换个角度想,这实际上就是在做两次“一维 FFT"。先把行变成频率,再对列做变换,结局就是一个二维的频谱。
实际上 一维 FFT 本质上就是一个单循环,二维的就变成了四个单循环,逻辑上好办多了,只是执行时多了一层嵌套。 要算得更快,就得利用对称性。FFT 公式里有“共轭对称”要么“共轭反演”的概念。在离散域里,同一个位置上下左右取反的数值,实际上是一样的。
比如 $X_0$ 和 $X_{N-1}$ 往往有某种关系,这样在算的时候,有些点能够共用代码,不用重复跑,省了不少工夫。
这就好比在打地鼠,有些地鼠是同一批人打的,不用各自跑圈。 再具体点,假设我们有个 $4 times 4$ 的矩阵,每行每列都一样。
那它的频谱实际上就是重复了四遍的相同信息。
这时候直接暴力算,每个位置都要算 $4 times 4 = 16$ 次。但这层重复的重复,实际上能够简化。
只要算一次,加上相关的对称项,整个矩阵的频谱就能出来了。
这时候公式里的 $N^2$ 项就变成 $N^2 + text{gain}$ 的形式,其中 $N$ 是维度,gain 是相关的系数。 实际工程中,有一类难题特别典型,就是那个 $O(M^2)$ 的局部。
比如 $M=1024$,那就要算 $10^6$ 次乘法。
这时候要是直接用一般/平平算法,内存压力就大了,并且速度也慢。
这时候就得依赖 FFT 的高效性,特别是利用“分治”要么“皮克定理”的思路。把二维切分成四个小矩框,每个小矩框单独算一维 FFT,最终合起来就能拿到整个的二维结局。
这个思路在图像处理里用得特别广,像 JPEG 压缩要么某些视频编码标准里,核心逻辑就是这样的“分而治之”。 咱们能够换个思路看看,如何把二维变一维。
比如把二维数组看作是一个一维数组的切片。
这时候二维 FFT 就变成了一个带索引的一维 FFT。代码里会有个循环,外层循环管住行号,内层循环管住列号。
每次行号转变时,里面的索引也要跟着变,这就构成了皮克定理那种结构。公式里的 $N times M$ 变成了 $N$ 和 $M$ 分别作为两个维度。
要是只有一维,公式挺好办。
要是二维,就多了个维度参数。 这种结构的本质,就是利用了“卷积”的性质。二维的卷积能够看作是一维卷积的两次操作。
要是数据本身就是卷积的,那在频域上就会表现为两个一维序列的乘积。
要是用 FFT 去算二维卷积,实际上是算两个一维 FFT 的乘积,再加上一些额外的因子。
这样做的益处,就是整体复杂度降下来了,从 $O(N^2)$ 降到了 $O(N)$ 级别(具体看算法优化程度)。 不过,这玩意儿有个坑。
要是你用的内存空间不够大,要么算得特别慢,直接上二维 FFT 可能会超时。
这时候就得退一步,先对其中一行做一次一维 FFT,拿到一个频域序列,然后再对这一列做一次一维 FFT,拿到另一个频域序列。把这两个序列乘起来,再做个逆 FFT,就能拿到整个的结局。
这种方式在资源受限的设备上特别有优势,但计算量会比直接二维 FFT 略高一点点。 在实际项目里,大家往往不会只写一个好办的 2D 公式。
一般会结合一些预处理,比如先对图像进行小波变换,再按阈值保留能量大的块儿,这时候再套用 FFT 就顺手了。
有时候还会结合“池化”要么“卷积核”的操作,把二维难题进一步简化成一维要么二维的核运算,然后再套上 FFT 公式。 最终总结一下,二维 FFT 的核心就俩:一个是分治的思想,一个是利用对称性剪枝。别死磕那个 $N^2 M^2$ 的数学表达,那只是中间步骤。真正关键的是它能把二维的暴力枚举变成两个一维的好办循环,再把两个一维的好办循环变成两个一维的乘积。
这种从 $O(N^2)$ 到 $O(N^2)$ 再到 $O(N)$ 的降维打击,才是 FFT 在工程上能大杀四方的根本缘由。 故此,下次要是写 2D FFT 的代码,先别管公式,先看看数据量多大,内存够不够,能不能接纳分块策略。
要是数据量小,直接暴力循环;要是数据量大,那就分块 FFT。
只要抓住了这个“分”和“乘”的本质,代码就能写得既高效又清楚,没必要去纠结那些繁琐的数学推导。毕竟在工程世界里,能跑通且跑得快的东西,比那些漂亮的数学公式更能解决难题。
声明:演示网站所有内容,若无特殊说明或标注,均来源于网络转载,仅供学习交流使用,禁止商用。若本站侵犯了你的权益,可联系本站删除。
