【问题标题】:Using IOS Accelerate Framework for 2D Signal Processing on Non-Power-of-Two images?使用 IOS Accelerate Framework 对非二次幂图像进行 2D 信号处理?
【发布时间】:2012-05-29 08:03:30
【问题描述】:

//编辑...

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

//...结束编辑

我在使用 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 图像的简单工作代码都会非常有帮助!

\\\编辑\\\

好的,在花了一些时间深入研究文档和一些非常有用的 SO 以及 pkmital's 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 方法的工作版本!)

【问题讨论】:

  • 看起来你只是在这里做自相关?我认为 Accelerate/vDSP 已经具有自相关功能,因此您不必使用 FFT/IFFT 等自行推出?
  • 嗨,加速库中似乎并不存在 vDSP_acor。 vDSP_conv 存在,但它给了我奇怪的结果......也许我错误地使用它来进行图像自相关。如果您(或任何人)有一个使用 vDSP_conv 进行自相关的工作示例,那么很高兴看到它。部分问题在于它对期望和输出中的哪些数据等感到困惑。

标签: ios signal-processing fft vdsp


【解决方案1】:

我想说,为了对任意大小的图像执行工作,您所要做的就是将输入值数组的大小适当地调整为 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 的输出本质上是流行的频率,然后可以简单地添加这些(仅从频率的角度来看,而不是角度偏移)。 然后我们可以将同样的技术推向二维。此时,我们将考虑每个输入像素,而无需实际填充。

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

【讨论】:

  • 这不像将 20 秒的音频信号处理成 5 秒的块。它更像是通过拆分 0-10khz 和 10khz-20khz 来处理音频信号。你从每个人那里得到不同的乐队,所以你会添加 2khz 和 12khz,或者类似的东西......
  • 这更像是一个问题,因为我仍在为所有这些开发直觉,但 FFT 的可分离性不允许一次执行图像 512 的条带,等等?我观看了一个视频,有人通过一次执行 1 行像素的 1D FFT 嵌套循环来执行 2D FFT。
猜你喜欢
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
相关资源
最近更新 更多