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

时间:2012-05-22 19:21:06

标签: ios signal-processing fft vdsp

// EDIT ...

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

// ... END EDIT

我在使用Accelerate Framework文档时遇到了一些麻烦。我通常会使用FFTW3,但我无法在实际的IOS设备上进行编译(请参阅此question)。任何人都可以使用Accelerate指向一个超级简单的实现,它执行以下操作:

1)将图像数据转换为适当的数据结构,可以传递给Accelerate的FFT方法  在最简单的FFTW3中,使用灰度图像,这涉及将无符号字节放入“fftw_complex”数组中,该数组只是两个浮点数的结构,一个包含实数值,另一个包含虚数(和虚数在哪里)每个像素初始化为零。)

2)采用这种数据结构并对其进行FFT。

3)打印出幅度和相位。

4)对其进行IFFT。

5)根据IFFT产生的数据重新创建原始图像。

虽然这是一个非常基本的例子,但我在使用Apple网站上的文档时遇到了麻烦。 SO answer by Pi here非常有用,但我仍然对如何使用Accelerate使用灰度(或彩色)2D图像执行此基本功能感到困惑。

无论如何,任何指针或特别是一些处理2D图像的简单工作代码都会非常有用!

\\\ EDIT \\\

好的,在花了一些时间深入研究文档和SO上以及pkmital's github repo上的一些非常有用的代码之后,我得到了一些我认为自那以后发布的工作代码。我有一段时间弄明白了2)因为我还有几个问题......

初始化FFT“计划”。假设一个2的平方幂图像:

#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方法的工作版本!)

1 个答案:

答案 0 :(得分:3)

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

困难的部分是放置原始图像数据和填充内容的位置。你真正想从图像中对图像或数据进行的操作至关重要。

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

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

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

这真的只是思考的问题,我自己也没有尝试过,我的确应该自己研究一下。如果你现在正在做这种工作,那么你现在可能有更多的时间。