/**
* 2D-IDFT [Inverse Discrete Fourier Transform]
* [How to Use]
* <case:>
* Fo[W][H] = {};
* Fn[U][V] = {...};
* idft_2d(&Fo, &Fn);
* [logistic]
* {
* result[W][H] = []; // as byte 2D-array
* // do SDD:
* for y in Range(Height) {
* for x in Range(Wight) {
* Re = 0; Im = 0;
* // do FDD:
* for u in range(NU-Horizontal_Slices) {
* for v in range(NV-Vertical_Slices) {
* Wn = (2 * PI) * Vec< (u / U , v / V)>;;
* An = Re * (Fn[n] · Vec<x,y>T);
* Bn = Im * (Fn[n] · Vec<x,y>T);
* result[t] += Fn[n].to_value(Wn, An, Bn) / (U * V);
* }}
* }
* return result;
* }
* @param original_ Original Function input 2D-array
* (image include width & height)
* @param analyzed_ Fourier Basis analyzed info in 2D
*/
接下来只需要根据思路做代码实现即可:
#include "stdio.h"
#include "math.h"
#define PI 3.1415926f
typedef struct FBasis {
double re_;
double im_;
double w_[2];
} FBasis;
typedef struct Signal2DOriginal {
int GW_;
int GH_;
double *Fo_;
} Signal2DOriginal;
typedef struct Signal2DAnalyzed {
int NU_;
int NV_;
FBasis *Fn_;
} Signal2DAnalyzed;
void dft_2d(Signal2DOriginal *original_, Signal2DAnalyzed *analyzed_) {
for (int u = 0; u < analyzed_->NU_; ++u) {
for (int v = 0; v < analyzed_->NV_; ++v) {
double An = 0;
double Bn = 0;
double Un = (2 * PI / analyzed_->NU_) * u ;
double Vn = (2 * PI / analyzed_->NV_) * v ;
for (int y = 0; y < original_->GH_; ++y) {
for (int x = 0; x < original_->GW_; ++x) {
An += cos(Un * x + Vn * y) * original_->Fo_[y * original_->GW_ + x];
Bn += sin(Un * x + Vn * y) * original_->Fo_[y * original_->GW_ + x];
}
}
FBasis e_ = {An, Bn, {Un, Vn}};
analyzed_->Fn_[u * analyzed_->NV_ + v] = e_;
}
}
}
void idft_2d(Signal2DOriginal *original_, Signal2DAnalyzed *analyzed_) {
for (int y = 0; y < original_->GH_; ++y) {
for (int x = 0; x < original_->GW_; ++x) {
for (int u = 0; u < analyzed_->NU_; ++u) {
for (int v = 0; v < analyzed_->NV_; ++v) {
FBasis e_ = analyzed_->Fn_[u * analyzed_->NV_ + v];
original_->Fo_[y * original_->GW_ + x] += (
e_.re_ * cos(e_.w_[0] * x + e_.w_[1] * y) +
e_.im_ * sin(e_.w_[0] * x + e_.w_[1] * y)
) / (analyzed_->NU_ * analyzed_->NV_);
}
}
}
}
}
写完后还是需要简单测试一下:
int main(void) {
double input_data_[36] = {
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f,
2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 1.0f,
3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 2.0f,
4.0f, 5.0f, 6.0f, 1.0f, 2.0f, 3.0f,
5.0f, 6.0f, 1.0f, 2.0f, 3.0f, 4.0f,
6.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f
};
FBasis output_data_[36] = {};
double versed_data_[36] = {};
Signal2DOriginal Fo = {
6, 6,
input_data_
};
Signal2DAnalyzed Fn = {
6, 6,
output_data_
};
Signal2DOriginal iFo = {
6, 6,
versed_data_
};
printf("\n Original_data: \n");
for (int y = 0; y < Fo.GH_; ++y) {
for (int x = 0; x < Fo.GW_; ++x) {
printf("%f ", Fo.Fo_[x + y * Fo.GW_]);
}
printf("\n");
}
printf("\n DFT_result: \n");
dft_2d(&Fo, &Fn);
for (int v = 0; v < Fn.NV_; ++v) {
for (int u = 0; u < Fn.NU_; ++u) {
printf("%.3f + i %.3f ",
Fn.Fn_[u + v * Fn.NU_].re_,
Fn.Fn_[u + v * Fn.NU_].im_
);
}
printf("\n");
}
printf("\n IDFT_result: \n");
idft_2d(&iFo, &Fn);
for (int y = 0; y < iFo.GH_; ++y) {
for (int x = 0; x < iFo.GW_; ++x) {
printf("%f ", iFo.Fo_[x + y * Fo.GW_]);
}
printf("\n");
}
return 0;
}
得到结果和标准几近相同:
Original_data:
1.000000 2.000000 3.000000 4.000000 5.000000 6.000000
2.000000 3.000000 4.000000 5.000000 6.000000 1.000000
3.000000 4.000000 5.000000 6.000000 1.000000 2.000000
4.000000 5.000000 6.000000 1.000000 2.000000 3.000000
5.000000 6.000000 1.000000 2.000000 3.000000 4.000000
6.000000 1.000000 2.000000 3.000000 4.000000 5.000000
DFT_result:
126.000 + i 0.000 -0.000 + i 0.000 -0.000 + i 0.000 0.000 + i 0.000 0.000 + i 0.000 0.000 + i 0.000
-0.000 + i 0.000 -18.000 + i -31.177 0.000 + i 0.000 0.000 + i -0.000 0.000 + i -0.000 0.000 + i -0.000
-0.000 + i 0.000 0.000 + i 0.000 -18.000 + i -10.392 0.000 + i -0.000 0.000 + i -0.000 0.000 + i -0.000
0.000 + i 0.000 0.000 + i -0.000 0.000 + i -0.000 -18.000 + i 0.000 0.000 + i -0.000 -0.000 + i -0.000
0.000 + i 0.000 0.000 + i -0.000 0.000 + i -0.000 0.000 + i -0.000 -18.000 + i 10.392 -0.000 + i -0.000
0.000 + i 0.000 0.000 + i -0.000 0.000 + i -0.000 -0.000 + i -0.000 -0.000 + i -0.000 -18.000 + i 31.177
IDFT_result:
1.000007 2.000001 2.999999 3.999999 5.000001 6.000003
2.000001 2.999998 3.999998 4.999998 5.999999 1.000000
2.999999 3.999998 4.999997 5.999998 0.999998 2.000000
3.999999 4.999998 5.999998 0.999997 1.999999 3.000001
5.000001 5.999999 0.999998 1.999999 3.000000 4.000003
6.000003 1.000000 2.000000 3.000001 4.000003 5.000005
运行结束。
这就是促成快速傅立叶蝴蝶法工程化的要素。
上式对复平面波 Fω(x,y) 的拆解,从数理上表明了,Fω(x,y) 是由沿着 x 轴方向的一维波 Fξ(x) 和沿着 y 轴方向的一维波 Fη(y) 两部分构成。其中,ξ=U2π⋅u 为 Fξ(x) 的角频率,η=V2π⋅v 为 Fη(y) 的角频率。点位 (x,y) 在二维信号中代表的是实际像素数据在数字平面上的空间位置信息。所以在处理二维傅里叶变换时,我们需要考虑的是平面空间点 P(x,y) 与 k 平面波间的关系,即二维的空频关系。
二维离散傅里叶变换到此结束,那么更多维度的傅里叶变换该怎么处理呢?我们只需要拓展波矢 k 的维度即可。而多维和一维、二维情况,在离散傅里叶变换的逻辑流程上并没有不同。但是,随着波矢 k 的参数维度扩展,我们发现现有的直接计算法实现的离散傅里叶变换,其算法时间复杂度 O{n2} 已不足以支撑超过二维参数量后的敏捷计算。因此,我们迫切需要一种更快的代替算法。