在上周,我一直在用FFTW编程一些二维卷积,通过将两个信号传递到频域,再乘以,然后返回。
令人惊讶的是,只有当输入大小小于固定数字时才能得到正确的结果!
我发布了一些工作代码,其中我为输入采用值为2的简单初始常量矩阵,为空间域上的滤波器采用1。这样,对它们进行卷积的结果应该是第一矩阵值的平均值的矩阵,即2,因为它是常数。当我改变宽度和高度的大小从0到h = 215,w = 215时,这是输出;如果我设置h = 216,w = 216或更高,那么输出会被破坏!!我真的很感激一些线索,我可以在哪里犯错误。非常感谢你!
#include <fftw3.h>
int main(int argc, char* argv[]) {
int h=215, w=215;
//Input and 1 filter are declared and initialized here
float *in = (float*) fftwf_malloc(sizeof(float)*w*h);
float *identity = (float*) fftwf_malloc(sizeof(float)*w*h);
for(int i=0;i<w*h;i++){
in[i]=5;
identity[i]=1;
}
//Declare two forward plans and one backward
fftwf_plan plan1, plan2, plan3;
//Allocate for complex output of both transforms
fftwf_complex *inTrans = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex)*h*(w/2+1));
fftwf_complex *identityTrans = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex)*h*(w/2+1));
//Initialize forward plans
plan1 = fftwf_plan_dft_r2c_2d(h, w, in, inTrans, FFTW_ESTIMATE);
plan2 = fftwf_plan_dft_r2c_2d(h, w, identity, identityTrans, FFTW_ESTIMATE);
//Execute them
fftwf_execute(plan1);
fftwf_execute(plan2);
//Multiply in frequency domain. Theoretically, no need to multiply imaginary parts; since signals are real and symmetric
//their transform are also real, identityTrans[i][i] = 0, but i leave here this for more generic implementation.
for(int i=0; i<(w/2+1)*h; i++){
inTrans[i][0] = inTrans[i][0]*identityTrans[i][0] - inTrans[i][1]*identityTrans[i][1];
inTrans[i][1] = inTrans[i][0]*identityTrans[i][1] + inTrans[i][1]*identityTrans[i][0];
}
//Execute inverse transform, store result in identity, where identity filter lied.
plan3 = fftwf_plan_dft_c2r_2d(h, w, inTrans, identity, FFTW_ESTIMATE);
fftwf_execute(plan3);
//Output first results of convolution(in, identity) to see if they are the average of in.
for(int i=0;i<h/h+4;i++){
for(int j=0;j<w/w+4;j++){
std::cout<<"After convolution, component (" << i <<","<< j << ") is " << identity[j+i*w]/(w*h*w*h) << endl;
}
}std::cout<<endl;
//Compute average of data
float sum=0.0;
for(int i=0; i<w*h;i++)
sum+=in[i];
std::cout<<"Mean of input was " << (float)sum/(w*h) << endl;
std::cout<< endl;
fftwf_destroy_plan(plan1);
fftwf_destroy_plan(plan2);
fftwf_destroy_plan(plan3);
return 0;
}
答案 0 :(得分:2)
你的问题与fftw无关!它来自这一行:
std::cout<<"After convolution, component (" << i <<","<< j << ") is " << identity[j+i*w]/(w*h*w*h) << endl;
如果w=216
和h=216
则`w * h * w * h = 2 176 782 336.有符号32位整数的上限是2 147 483 647.您正面临溢出..
解决方案是将分母投射到float
。
std::cout<<"After convolution, component (" << i <<","<< j << ") is " << identity[j+i*w]/(((float)w)*h*w*h) << endl;
您要面对的下一个问题是:
float sum=0.0;
for(int i=0; i<w*h;i++)
sum+=in[i];
请记住,float
有7个有用的十进制数字。如果w=h=4000
,计算的平均值将低于实际平均值。在对外循环(double
)求和之前,使用localsum
或在内循环(sum+=localsum
)上写两个循环并求和!
再见,
弗朗西斯