无法使用 FFT 和 FFTW 检索原始图像
Cannot retrieve original image using FFT with FFTW
我在我的 C 代码中使用 FFTW,但遇到了一些问题。
首先,我可以将原始图像转换为两个图像(mag+phase)并通过逆变换取回原始图像。
但是,如果我想得到一个以频率为中心的 mag 文件,它就不再起作用了:最终图像有一些问题。
这是我的一些代码。有人可以帮我找出代码中的错误吗?
编辑:我已修复代码以遵循@francis 的建议,但我的问题始终存在。
enum {
TYPE_CENTERED,
TYPE_REGULAR
};
static void fft_to_spectra(fits* fit, fftw_complex *frequency_repr, double *as,
double *ps, int nbdata) {
unsigned int i;
for (i = 0; i < nbdata; i++) {
double r = creal(frequency_repr[i]);
double im = cimag(frequency_repr[i]);
as[i] = hypot(r, im);
ps[i] = atan2(im, r);
}
}
static void fft_to_freq(fits* fit, fftw_complex *frequency_repr, double *as, double *ps, int nbdata) {
unsigned int i;
for (i = 0; i < nbdata; i++) {
frequency_repr[i] = as[i] * (cos(ps[i]) + I * sin(ps[i]));
}
}
void change_symmetry(unsigned int width, unsigned int height, unsigned int i, unsigned int j, unsigned int *x,
unsigned int *y) {
if (i < width / 2 && j < height / 2) {
*x = i + width / 2;
*y = j + height / 2;
}
if (i >= width / 2 && j < height / 2) {
*x = i - width / 2;
*y = j + height / 2;
}
if (i < width / 2 && j >= height / 2) {
*x = i + width / 2;
*y = j - height / 2;
}
if (i >= width / 2 && j >= height / 2) {
*x = i - width / 2;
*y = j - height / 2;
}
}
static void centered(WORD *buf, unsigned int width,
unsigned int height) {
unsigned int i, j;
WORD *temp = malloc(width * height * sizeof(WORD));
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
unsigned int x = i;
unsigned int y = j;
change_symmetry(width, height, i, j, &x, &y);
temp[j * width + i] = buf[y * width + x];
}
}
memcpy(buf, temp, sizeof(WORD) * width * height);
free(temp);
}
static void normalisation_spectra(unsigned int w, unsigned int h, double *modulus, double *phase,
WORD *abuf, WORD *pbuf) {
unsigned int i;
for (i = 0; i < h * w; i++) {
pbuf[i] = round_to_WORD(((phase[i] + M_PI) * USHRT_MAX_DOUBLE / (2 * M_PI)));
abuf[i] = round_to_WORD((modulus[i] / w / h));
}
}
static void save_dft_information_in_gfit(fits *fit) {
strcpy(gfit.dft.ord, fit->dft.type);
strcpy(gfit.dft.ord, fit->dft.ord);
}
static void FFTD(fits *fit, fits *x, fits *y, int type_order, int layer) {
WORD *xbuf = x->pdata[layer];
WORD *ybuf = y->pdata[layer];
WORD *gbuf = fit->pdata[layer];
unsigned int i;
unsigned int width = fit->rx, height = fit->ry;
int nbdata = width * height;
fftw_complex *spatial_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!spatial_repr) {
return;
}
fftw_complex *frequency_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!frequency_repr) {
fftw_free(spatial_repr);
return;
}
/* copying image selection into the fftw data */
#ifdef _OPENMP
#pragma omp parallel for num_threads(com.max_thread) private(i) schedule(static) if(nbdata > 15000)
#endif
for (i = 0; i < nbdata; i++) {
spatial_repr[i] = (double) gbuf[i];
}
/* we run the Fourier Transform */
fftw_plan p = fftw_plan_dft_2d(height, width, spatial_repr, frequency_repr,
FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(p);
/* we compute modulus and phase */
double *modulus = malloc(nbdata * sizeof(double));
double *phase = malloc(nbdata * sizeof(double));
fft_to_spectra(fit, frequency_repr, modulus, phase, nbdata);
//We normalize the modulus and the phase
normalisation_spectra(width, height, modulus, phase, xbuf, ybuf);
if (type_order == TYPE_CENTERED) {
strcpy(x->dft.ord, "CENTERED");
centered(xbuf, width, height);
centered(ybuf, width, height);
}
free(modulus);
free(phase);
fftw_destroy_plan(p);
fftw_free(spatial_repr);
fftw_free(frequency_repr);
}
static void FFTI(fits *fit, fits *xfit, fits *yfit, int type_order, int layer) {
WORD *xbuf = xfit->pdata[layer];
WORD *ybuf = yfit->pdata[layer];
WORD *gbuf = fit->pdata[layer];
unsigned int i;
unsigned int width = xfit->rx;
unsigned int height = xfit->ry;
int nbdata = width * height;
double *modulus = calloc(1, nbdata * sizeof(double));
double *phase = calloc(1, nbdata * sizeof(double));
if (type_order == TYPE_CENTERED) {
centered(xbuf, width, height);
centered(ybuf, width, height);
}
for (i = 0; i < height * width; i++) {
modulus[i] = (double) xbuf[i] * (width * height);
phase[i] = (double) ybuf[i] * (2 * M_PI / USHRT_MAX_DOUBLE);
phase[i] -= M_PI;
}
fftw_complex* spatial_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!spatial_repr) {
return;
}
fftw_complex* frequency_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!frequency_repr) {
fftw_free(spatial_repr);
return;
}
fft_to_freq(fit, frequency_repr, modulus, phase, nbdata);
fftw_plan p = fftw_plan_dft_2d(height, width, frequency_repr, spatial_repr,
FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(p);
for (i = 0; i < nbdata; i++) {
double pxl = creal(spatial_repr[i]) / nbdata;
gbuf[i] = round_to_WORD(pxl);
}
free(modulus);
free(phase);
fftw_destroy_plan(p);
fftw_free(spatial_repr);
fftw_free(frequency_repr);
}
这是我的图像,原始图像和 FFTD(居中)->FFTI 结果
计划是使用标志 FFTW_MEASURE
创建的。因此,计算了多个 DFT,并且输入数组可能被覆盖。这是documentation of FFTW:
中规划器标志描述的开始
FFTW_ESTIMATE
specifies that, instead of actual measurements of different algorithms, a simple heuristic is used to pick a (probably sub-optimal) plan quickly. With this flag, the input/output arrays are not overwritten during planning.
FFTW_MEASURE
tells FFTW to find an optimized plan by actually computing several FFTs and measuring their execution time. Depending on your machine, this can take some time (often a few seconds). FFTW_MEASURE is the default planning option.
切换到 FFTW_ESTIMATE
或在填充输入数组之前创建计划:
/* we run the Fourier Transform */
fftw_plan p = fftw_plan_dft_2d(width, height, spatial_repr, frequency_repr,
FFTW_FORWARD, FFTW_MEASURE);
/* copying image selection into the fftw data */
#ifdef _OPENMP
#pragma omp parallel for num_threads(com.max_thread) private(i) schedule(static) if(nbdata > 15000)
#endif
for (i = 0; i < nbdata; i++) {
spatial_repr[i] = (double) gbuf[i];
}
如果您打算使用单个图像,使用 FFTW_ESTIMATE
是可行的方法。相反,如果您考虑处理多个图像,使用 FFTW_MEASURE
创建一次计划并存储它是一个不错的选择。那么你可以在每次执行 FFT 时使用 New-array Execute Functions:
fftw_execute_dft(p, spatial_repr, frequency_repr);
您可以测试 malloc()
或 fftw_malloc()
的 return 值来检查分配是否正确。如果不是,它 returns NULL
。 fftw_malloc()
在 fftw-3.3.6-pl2/kernel/kalloc.c 中作为函数 *X(kernel_malloc)(size_t n)
实现。它会调用 memalign()
or _aligned_malloc()
等函数。这两个 return NULL
就像 malloc()
以防失败。最后,我没有在您提供的代码段中发现有关释放内存分配的关键问题。
fft_to_spectra()
中的参数 double nbdata
应该是一个整数。 Valgrind 可能认为它很奇怪...
编辑:change_symmetry()
将被修改为奇数尺寸。类似于:
void change_symmetry_forward(unsigned int width, unsigned int height, unsigned int i, unsigned int j, unsigned int *x,
unsigned int *y) {
*x = i + width / 2;
if (*x>=width){
*x=*x-width;
}
*y = j + height / 2;
if(*y>=height){
*y =*y-height;
}
}
和
void change_symmetry_backward(unsigned int width, unsigned int height, unsigned int i, unsigned int j, unsigned int *x,
unsigned int *y) {
*x = i +width- width / 2;
if (*x>=width){
*x=*x-width;
}
*y = j +height- height / 2;
if(*y>=height){
*y =*y-height;
}
}
我在我的 C 代码中使用 FFTW,但遇到了一些问题。 首先,我可以将原始图像转换为两个图像(mag+phase)并通过逆变换取回原始图像。 但是,如果我想得到一个以频率为中心的 mag 文件,它就不再起作用了:最终图像有一些问题。
这是我的一些代码。有人可以帮我找出代码中的错误吗?
编辑:我已修复代码以遵循@francis 的建议,但我的问题始终存在。
enum {
TYPE_CENTERED,
TYPE_REGULAR
};
static void fft_to_spectra(fits* fit, fftw_complex *frequency_repr, double *as,
double *ps, int nbdata) {
unsigned int i;
for (i = 0; i < nbdata; i++) {
double r = creal(frequency_repr[i]);
double im = cimag(frequency_repr[i]);
as[i] = hypot(r, im);
ps[i] = atan2(im, r);
}
}
static void fft_to_freq(fits* fit, fftw_complex *frequency_repr, double *as, double *ps, int nbdata) {
unsigned int i;
for (i = 0; i < nbdata; i++) {
frequency_repr[i] = as[i] * (cos(ps[i]) + I * sin(ps[i]));
}
}
void change_symmetry(unsigned int width, unsigned int height, unsigned int i, unsigned int j, unsigned int *x,
unsigned int *y) {
if (i < width / 2 && j < height / 2) {
*x = i + width / 2;
*y = j + height / 2;
}
if (i >= width / 2 && j < height / 2) {
*x = i - width / 2;
*y = j + height / 2;
}
if (i < width / 2 && j >= height / 2) {
*x = i + width / 2;
*y = j - height / 2;
}
if (i >= width / 2 && j >= height / 2) {
*x = i - width / 2;
*y = j - height / 2;
}
}
static void centered(WORD *buf, unsigned int width,
unsigned int height) {
unsigned int i, j;
WORD *temp = malloc(width * height * sizeof(WORD));
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
unsigned int x = i;
unsigned int y = j;
change_symmetry(width, height, i, j, &x, &y);
temp[j * width + i] = buf[y * width + x];
}
}
memcpy(buf, temp, sizeof(WORD) * width * height);
free(temp);
}
static void normalisation_spectra(unsigned int w, unsigned int h, double *modulus, double *phase,
WORD *abuf, WORD *pbuf) {
unsigned int i;
for (i = 0; i < h * w; i++) {
pbuf[i] = round_to_WORD(((phase[i] + M_PI) * USHRT_MAX_DOUBLE / (2 * M_PI)));
abuf[i] = round_to_WORD((modulus[i] / w / h));
}
}
static void save_dft_information_in_gfit(fits *fit) {
strcpy(gfit.dft.ord, fit->dft.type);
strcpy(gfit.dft.ord, fit->dft.ord);
}
static void FFTD(fits *fit, fits *x, fits *y, int type_order, int layer) {
WORD *xbuf = x->pdata[layer];
WORD *ybuf = y->pdata[layer];
WORD *gbuf = fit->pdata[layer];
unsigned int i;
unsigned int width = fit->rx, height = fit->ry;
int nbdata = width * height;
fftw_complex *spatial_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!spatial_repr) {
return;
}
fftw_complex *frequency_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!frequency_repr) {
fftw_free(spatial_repr);
return;
}
/* copying image selection into the fftw data */
#ifdef _OPENMP
#pragma omp parallel for num_threads(com.max_thread) private(i) schedule(static) if(nbdata > 15000)
#endif
for (i = 0; i < nbdata; i++) {
spatial_repr[i] = (double) gbuf[i];
}
/* we run the Fourier Transform */
fftw_plan p = fftw_plan_dft_2d(height, width, spatial_repr, frequency_repr,
FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(p);
/* we compute modulus and phase */
double *modulus = malloc(nbdata * sizeof(double));
double *phase = malloc(nbdata * sizeof(double));
fft_to_spectra(fit, frequency_repr, modulus, phase, nbdata);
//We normalize the modulus and the phase
normalisation_spectra(width, height, modulus, phase, xbuf, ybuf);
if (type_order == TYPE_CENTERED) {
strcpy(x->dft.ord, "CENTERED");
centered(xbuf, width, height);
centered(ybuf, width, height);
}
free(modulus);
free(phase);
fftw_destroy_plan(p);
fftw_free(spatial_repr);
fftw_free(frequency_repr);
}
static void FFTI(fits *fit, fits *xfit, fits *yfit, int type_order, int layer) {
WORD *xbuf = xfit->pdata[layer];
WORD *ybuf = yfit->pdata[layer];
WORD *gbuf = fit->pdata[layer];
unsigned int i;
unsigned int width = xfit->rx;
unsigned int height = xfit->ry;
int nbdata = width * height;
double *modulus = calloc(1, nbdata * sizeof(double));
double *phase = calloc(1, nbdata * sizeof(double));
if (type_order == TYPE_CENTERED) {
centered(xbuf, width, height);
centered(ybuf, width, height);
}
for (i = 0; i < height * width; i++) {
modulus[i] = (double) xbuf[i] * (width * height);
phase[i] = (double) ybuf[i] * (2 * M_PI / USHRT_MAX_DOUBLE);
phase[i] -= M_PI;
}
fftw_complex* spatial_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!spatial_repr) {
return;
}
fftw_complex* frequency_repr = fftw_malloc(sizeof(fftw_complex) * nbdata);
if (!frequency_repr) {
fftw_free(spatial_repr);
return;
}
fft_to_freq(fit, frequency_repr, modulus, phase, nbdata);
fftw_plan p = fftw_plan_dft_2d(height, width, frequency_repr, spatial_repr,
FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(p);
for (i = 0; i < nbdata; i++) {
double pxl = creal(spatial_repr[i]) / nbdata;
gbuf[i] = round_to_WORD(pxl);
}
free(modulus);
free(phase);
fftw_destroy_plan(p);
fftw_free(spatial_repr);
fftw_free(frequency_repr);
}
这是我的图像,原始图像和 FFTD(居中)->FFTI 结果
计划是使用标志 FFTW_MEASURE
创建的。因此,计算了多个 DFT,并且输入数组可能被覆盖。这是documentation of FFTW:
FFTW_ESTIMATE
specifies that, instead of actual measurements of different algorithms, a simple heuristic is used to pick a (probably sub-optimal) plan quickly. With this flag, the input/output arrays are not overwritten during planning.
FFTW_MEASURE
tells FFTW to find an optimized plan by actually computing several FFTs and measuring their execution time. Depending on your machine, this can take some time (often a few seconds). FFTW_MEASURE is the default planning option.
切换到 FFTW_ESTIMATE
或在填充输入数组之前创建计划:
/* we run the Fourier Transform */
fftw_plan p = fftw_plan_dft_2d(width, height, spatial_repr, frequency_repr,
FFTW_FORWARD, FFTW_MEASURE);
/* copying image selection into the fftw data */
#ifdef _OPENMP
#pragma omp parallel for num_threads(com.max_thread) private(i) schedule(static) if(nbdata > 15000)
#endif
for (i = 0; i < nbdata; i++) {
spatial_repr[i] = (double) gbuf[i];
}
如果您打算使用单个图像,使用 FFTW_ESTIMATE
是可行的方法。相反,如果您考虑处理多个图像,使用 FFTW_MEASURE
创建一次计划并存储它是一个不错的选择。那么你可以在每次执行 FFT 时使用 New-array Execute Functions:
fftw_execute_dft(p, spatial_repr, frequency_repr);
您可以测试 malloc()
或 fftw_malloc()
的 return 值来检查分配是否正确。如果不是,它 returns NULL
。 fftw_malloc()
在 fftw-3.3.6-pl2/kernel/kalloc.c 中作为函数 *X(kernel_malloc)(size_t n)
实现。它会调用 memalign()
or _aligned_malloc()
等函数。这两个 return NULL
就像 malloc()
以防失败。最后,我没有在您提供的代码段中发现有关释放内存分配的关键问题。
fft_to_spectra()
中的参数 double nbdata
应该是一个整数。 Valgrind 可能认为它很奇怪...
编辑:change_symmetry()
将被修改为奇数尺寸。类似于:
void change_symmetry_forward(unsigned int width, unsigned int height, unsigned int i, unsigned int j, unsigned int *x,
unsigned int *y) {
*x = i + width / 2;
if (*x>=width){
*x=*x-width;
}
*y = j + height / 2;
if(*y>=height){
*y =*y-height;
}
}
和
void change_symmetry_backward(unsigned int width, unsigned int height, unsigned int i, unsigned int j, unsigned int *x,
unsigned int *y) {
*x = i +width- width / 2;
if (*x>=width){
*x=*x-width;
}
*y = j +height- height / 2;
if(*y>=height){
*y =*y-height;
}
}