我编写了一个C/C++
代码,该代码使用英特尔MKL来计算具有约 300×200×200
个元素的数组的3D卷积。我想应用3×3×3
或5×5×5
的内核。 3D输入数组和内核都具有实际值。
此3D数组以列方式存储为double
类型的1D数组。类似地,内核的类型为double
,并以列方式保存。例如,
for( int k = 0; k < nk; k++ ) // Loop through the height.
for( int j = 0; j < nj; j++ ) // Loop through the rows.
for( int i = 0; i < ni; i++ ) // Loop through the columns.
{
ijk = i + ni * j + ni * nj * k;
my3Darray[ ijk ] = 1.0;
}
对于卷积的计算,我想对输入数组和内核执行not-in-place
FFT并防止它们被修改(我需要稍后在我的代码中使用它们)然后执行反向计算{ {1}}。
当我将从我的代码中获得的结果与由in-place
获得的结果进行比较时,它们是非常不同的。有人可以帮我解决这个问题吗?我的代码中缺少什么?
以下是我使用的MATLAB
代码:
MATLAB
这是我的a = ones( 10, 10, 10 );
kernel = ones( 3, 3, 3 );
aconvolved = convn( a, kernel, 'same' );
代码:
C/C++
答案 0 :(得分:3)
您无法使用实值频率数据(仅幅度)反转FFT。正向FFT需要输出复杂数据。这可以通过将DFTI_FORWARD_DOMAIN
setting设置为DFTI_COMPLEX
来完成。
DftiCreateDescriptor( &fft_desc, DFTI_DOUBLE, DFTI_COMPLEX, 3, sizes );
这样做会隐式地将后向域设置为复杂。
您还需要一种复杂的数据类型。可能是这样的,
MKL_Complex16* in_fft = new MKL_Complex16[NI*NJ*NK];
这意味着您必须将实部和虚部相乘:
for (size_t i = 0; i < (size_t)NI*NJ*NK; ++i) {
out_fft[i].real = in_fft[i].real * ker_fft[i].real;
out_fft[i].imag = in_fft[i].imag * ker_fft[i].imag;
}
逆FFT的输出也很复杂,假设您的输入数据是真实的,您可以抓住.real
组件,这就是您的结果。这意味着您将需要一个临时的复杂输出数组(例如,如上所述out_fft
)。
另请注意,为了避免瑕疵,您希望fft的大小在每个维度上(至少)M + N-1。一般来说,你会为速度选择2的最高功率。
我强烈建议您先使用FFT在MATLAB中实现它。有许多这样的实现可用(example),但我会从基础开始,并自己做一个简单的功能。