//编辑...
我正在稍微编辑我的问题,以解决专门处理非二次幂图像的问题。我有一个基本结构,适用于大小为 256x256 或 1024x1024 的方形灰度图像,但看不到如何推广到任意大小的图像。fft 函数似乎希望您包含宽度和高度的 log2,但随后不清楚如何解压缩结果数据,或者数据是否只是被打乱。我想显而易见的事情是将 npot 图像居中在一个更大的全黑图像中,然后在查看数据时忽略这些位置的任何值。但是想知道是否有一种不那么尴尬的方式来处理 npot 数据。
//...结束编辑
我在使用 Accelerate Framework 文档时遇到了一些问题。我通常会使用 FFTW3,但我无法在实际的 IOS 设备上编译它(参见这个问题)。谁能指出我使用 Accelerate 的一个超级简单的实现,它执行以下操作:
1) 将图像数据转换为可以传递给 Accelerate 的 FFT 方法的适当数据结构。
在 FFTW3 中,最简单的是,使用灰度图像,这涉及将无符号字节放入“fftw_complex”数组中,该数组只是两个浮点数的结构,一个保存实数,另一个保存虚数(虚数在每个像素初始化为零)。
2) 采用此数据结构并对其执行 FFT。
3) 打印出幅度和相位。
4) 对其执行IFFT。
5) 根据 IFFT 产生的数据重新创建原始图像。
尽管这是一个非常基本的示例,但我在使用 Apple 网站上的文档时遇到了问题。Pi 在这里的 SO回答非常有帮助,但我仍然对如何使用 Accelerate 使用灰度(或彩色)2D 图像执行此基本功能感到有些困惑。
无论如何,任何指针或特别是一些处理 2D 图像的简单工作代码都会非常有帮助!
\\\ 编辑 \\\
好的,在花一些时间深入研究 SO 以及pkmital 的 github repo上的文档和一些非常有用的代码之后,我有一些我认为我会发布的工作代码 1)我花了一段时间才弄清楚2)因为我还有几个问题......
初始化 FFT“计划”。假设一个二次方图像:
#include <Accelerate/Accelerate.h>
...
UInt32 N = log2(length*length);
UInt32 log2nr = N / 2;
UInt32 log2nc = N / 2;
UInt32 numElements = 1 << ( log2nr + log2nc );
float SCALE = 1.0/numElements;
SInt32 rowStride = 1;
SInt32 columnStride = 0;
FFTSetup setup = create_fftsetup(MAX(log2nr, log2nc), FFT_RADIX2);
传入一个字节数组以获得二次方灰度图像并将其转换为 COMPLEX_SPLIT:
COMPLEX_SPLIT in_fft;
in_fft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
in_fft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
for ( UInt32 i = 0; i < numElements; i++ ) {
if (i < t->width * t->height) {
in_fft.realp[i] = t->data[i] / 255.0;
in_fft.imagp[i] = 0.0;
}
}
对转换后的图像数据运行 FFT,然后获取幅度和相位:
COMPLEX_SPLIT out_fft;
out_fft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
out_fft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
fft2d_zop ( setup, &in_fft, rowStride, columnStride, &out_fft, rowStride, columnStride, log2nc, log2nr, FFT_FORWARD );
magnitude = (float *) malloc(numElements * sizeof(float));
phase = (float *) malloc(numElements * sizeof(float));
for (int i = 0; i < numElements; i++) {
magnitude[i] = sqrt(out_fft.realp[i] * out_fft.realp[i] + out_fft.imagp[i] * out_fft.imagp[i]) ;
phase[i] = atan2(out_fft.imagp[i],out_fft.realp[i]);
}
现在您可以对 out_fft 数据运行 IFFT 以获取原始图像...
COMPLEX_SPLIT out_ifft;
out_ifft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
out_ifft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
fft2d_zop (setup, &out_fft, rowStride, columnStride, &out_ifft, rowStride, columnStride, log2nc, log2nr, FFT_INVERSE);
vsmul( out_ifft.realp, 1, SCALE, out_ifft.realp, 1, numElements );
vsmul( out_ifft.imagp, 1, SCALE, out_ifft.imagp, 1, numElements );
或者您可以在幅度上运行 IFFT 以获得自相关......
COMPLEX_SPLIT in_ifft;
in_ifft.realp = ( float* ) malloc ( numElements * sizeof ( float ) );
in_ifft.imagp = ( float* ) malloc ( numElements * sizeof ( float ) );
for (int i = 0; i < numElements; i++) {
in_ifft.realp[i] = (magnitude[i]);
in_ifft.imagp[i] = 0.0;
}
fft2d_zop ( setup, &in_fft, rowStride, columnStride, &out_ifft, rowStride, columnStride, log2nc, log2nr, FFT_INVERSE );
vsmul( out_ifft.realp, 1, SCALE, out_ifft.realp, 1, numElements );
vsmul( out_ifft.imagp, 1, SCALE, out_ifft.imagp, 1, numElements );
最后,您可以将 ifft 结果放回图像数组中:
for ( UInt32 i = 0; i < numElements; i++ ) {
t->data[i] = (int) (out_ifft.realp[i] * 255.0);
}
我还没有弄清楚如何使用 Accelerate 框架来处理非二次幂图像。如果我在设置中分配了足够的内存,那么我可以进行 FFT,然后进行 IFFT 以获得我的原始图像。但是,如果尝试进行自相关(与 FFT 的幅度),那么我的图像会得到不稳定的结果。我不确定适当填充图像的最佳方法,所以希望有人知道如何做到这一点。(或分享 vDSP_conv 方法的工作版本!)