使用IOS Accelerate Framework在非二次幂图像上进行二维信号处理?

Ang*_*bes 13 signal-processing fft ios vdsp

//编辑...

我正在编辑我的问题,以解决专门处理非二次幂图像的问题.我有一个基本结构,适用于尺寸为256x256或1024x1024的方形灰度图像,但无法看到如何推广到任意大小的图像.fft函数似乎希望你包含宽度和高度的log2,但是它不清楚如何解压缩结果数据,或者数据是否只是被扰乱.我认为显而易见的事情是将npot图像置于较大的全黑图像中,然后在查看数据时忽略这些位置中的任何值.但是想知道是否有一种不太笨拙的方法来处理npot数据.

//...END编辑

我在使用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);
Run Code Online (Sandbox Code Playgroud)

传入一个字节数组,用于方形二次灰度图像并将其转换为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

对变换后的图像数据运行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]);
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以对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 );
Run Code Online (Sandbox Code Playgroud)

或者您可以在幅度上运行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 );
Run Code Online (Sandbox Code Playgroud)

最后,您可以将ifft结果放回到图像数组中:

for ( UInt32 i = 0; i < numElements; i++ ) {
  t->data[i] = (int) (out_ifft.realp[i] * 255.0);
}     
Run Code Online (Sandbox Code Playgroud)

我还没有弄清楚如何使用Accelerate框架来处理非二次幂图像.如果我在设置中分配了足够的内存,那么我可以进行FFT,然后使用IFFT来获取原始图像.但如果尝试进行自相关(具有FFT的幅度),那么我的图像会得到不可思议的结果.我不确定适当填充图像的最佳方法,所以希望有人知道如何做到这一点.(或者共享vDSP_conv方法的工作版本!)

tru*_*cks 3

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

困难的部分是在哪里放置原始图像数据以及填充什么。您真正想要对图像或图像中的数据进行的操作至关重要。

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

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

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

这确实值得深思,我自己没有尝试过,确实应该自己研究一下。如果你现在确实在做这种工作,那么你现在可能比我有更多的时间。