14

//编辑...

我正在稍微编辑我的问题,以解决专门处理非二次幂图像的问题。我有一个基本结构,适用于大小为 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 方法的工作版本!)

4

1 回答 1

3

我想说,为了对任意图像大小执行工作,您所要做的就是将输入值数组的大小适当地调整为 2 的下一个幂。

困难的部分是放置原始图像数据的位置以及要填充的内容。您真正想要对图像或从图像中挖掘数据做的事情是至关重要的。

在下面链接的 PDF 中,请特别注意 12.4.2 http://www.mathcs.org/java/programs/FFT/FFTInfo/c12-4.pdf上方的段落

虽然上面谈到了沿 2 个轴的操作,但我们可能会在第二个维度之前执行类似的想法,然后进入第二个维度。如果我是正确的,那么这个例子可以适用(这绝不是一个精确的算法):

假设我们有一个 900 x 900 的图像:首先我们可以将图像分成 512、256、128 和 4 个垂直条带。然后我们将为每一行处理 4 个 1D FFT,一个用于前 512 个像素,下一个用于对于接下来的 256 个像素,接下来是 128 个像素,然后是剩下的 4 个像素。由于 FFT 的输出本质上是频率的流行度,因此可以简单地添加这些(仅从频率的角度来看,而不是角度偏移)。然后我们可以将同样的技术推向二维。在这一点上,我们将考虑每个输入像素,而无需实际填充。

这实在是令人深思,我自己没有尝试过,确实应该自己研究一下。如果你现在真的在做这样的工作,你现在可能比我有更多的时间。

于 2012-05-30T21:25:16.040 回答