我想解决此paper中描述的屏蔽Poisson方程,以便根据粗略近似及其垂直和水平梯度来计算图像。我是第一次使用FFTW3。但是,我得到的结果很奇怪。
我对图像的粗略近似如下:
但是我的解决方案的输出看起来像这样:
。
为了调试它,我尝试了多种方法–
首先,我怀疑我对空间频率的计算不正确,所以我尝试在傅立叶域中计算图像的水平梯度,结果是:
。
最后,当我仅计算图像的FT及其逆变换时,我得到以下信息:
但是当我简单地将FT复制到新数组中并计算其逆FT时,我得到了:
。
这是我的功能:
void RayTrace::computeFT(double* &image_in, double* &dx_in, double* &dy_in, double* &result){
fftw_complex image_FT[width*height];
fftw_complex dx_FT[width*height];
fftw_complex dy_FT[width*height];
fftw_plan image_plan = fftw_plan_dft_r2c_2d(width, height, image_in, image_FT, FFTW_ESTIMATE);
fftw_plan dx_plan = fftw_plan_dft_r2c_2d(width, height, dx_in, dx_FT, FFTW_ESTIMATE);
fftw_plan dy_plan = fftw_plan_dft_r2c_2d(width, height, dy_in, dy_FT, FFTW_ESTIMATE);
//compute the FTs
fftw_execute(image_plan);
fftw_execute(dx_plan);
fftw_execute(dy_plan);
//delete plans after that
fftw_destroy_plan(image_plan);
fftw_destroy_plan(dx_plan);
fftw_destroy_plan(dy_plan);
fftw_cleanup();
//modify the image in the Fourier domain
fftw_complex result_FT[width*height];
for(int i=0 ; i<height ; i++){
for(int j=0 ; j<width ; j++){
float sx = (i>height/2 ? i-height : i) / float(height);
float sy = (j>width/2 ? j-width : j) / float(width);
int idx = i*width+j;
//These are the things that I tried to do
//compute the screened Poisson solution
result_FT[idx][0] = (alpha*image_FT[idx][0] + 2*M_PI*sx*dx_FT[idx][1] + 2*M_PI*sy*dy_FT[idx][1])/(alpha + 4*M_PI*M_PI*(sx*sx+sy*sy));
result_FT[idx][1] = (alpha*image_FT[idx][1] - 2*M_PI*sx*dx_FT[idx][0] - 2*M_PI*sy*dy_FT[idx][0])/(alpha + 4*M_PI*M_PI*(sx*sx+sy*sy));
//horizontal gradient
result_FT[idx][0] = -2*M_PI*sx*image_FT[idx][1];
result_FT[idx][1] = 2*M_PI*sx*image_FT[idx][0];
//simple copy
result_FT[idx][0] = image_FT[idx][0];
result_FT[idx][1] = image_FT[idx][1];
}
}
//inverse transform
fftw_plan r_back_plan = fftw_plan_dft_c2r_2d(width, height, image_FT, result, FFTW_ESTIMATE);
fftw_execute(r_back_plan);
//delete plan after that
fftw_destroy_plan(r_back_plan);
fftw_cleanup();
//normalize the result
float norm = height * width;
for(int i=0 ; i<height ; i++){
for(int j=0 ; j<width ; j++){
result[i*width + j] /= norm;
}
}
}
请告诉我您是否在实施中遇到错误
此外,这是我从中调用该方法的一种方法,一次用于图像中的每个颜色分量:
void RayTrace::computeGradient(glm::vec3* &image, glm::vec3* &xGradient, glm::vec3* &zGradient, glm::vec3* &gradient){
//compute the gradient of the image in the fourier domain
double *r_in = new double[width*height];
double *r_dx_in = new double[width*height];
double *r_dy_in = new double[width*height];
double *r_out = new double[width*height];
double *g_in = new double[width*height];
double *g_dx_in = new double[width*height];
double *g_dy_in = new double[width*height];
double *g_out = new double[width*height];
double *b_in = new double[width*height];
double *b_dx_in = new double[width*height];
double *b_dy_in = new double[width*height];
double *b_out = new double[width*height];
for(int i=0 ; i<height ; i++){
for(int j=0 ; j<width ; j++){
r_in[i*width + j] = image[i*width + j].x;
r_dx_in[i*width + j] = xGradient[i*width + j].x;
r_dy_in[i*width + j] = zGradient[i*width + j].x;
g_in[i*width + j] = image[i*width + j].y;
g_dx_in[i*width + j] = xGradient[i*width + j].y;
g_dy_in[i*width + j] = zGradient[i*width + j].y;
b_in[i*width + j] = image[i*width + j].z;
b_dx_in[i*width + j] = xGradient[i*width + j].z;
b_dy_in[i*width + j] = zGradient[i*width + j].z;
}
}
std::cout << width << " " << height << std::endl;
computeFT(r_in, r_dx_in, r_dy_in, r_out);
computeFT(g_in, g_dx_in, g_dy_in, g_out);
computeFT(b_in, b_dx_in, b_dy_in, b_out);
for(int i=0 ; i<height ; i++){
for(int j=0 ; j<width ; j++){
gradient[i*width + j] = glm::vec3(r_out[i*width + j], g_out[i*width + j], b_out[i*width + j]);
}
}
delete r_in;
delete r_out;
delete r_dx_in;
delete r_dy_in;
delete g_in;
delete g_out;
delete g_dx_in;
delete g_dy_in;
delete b_in;
delete b_out;
delete b_dx_in;
delete b_dy_in;
}
编辑:事实证明我的路径跟踪器输出根本没有被标准化,因此我数组中的值的范围从1e-3到1e6,因此我想FFTW很难缩放它。现在,我对其进行了归一化,可以在计算完FFT之后再恢复其IFFT,而无需进行修改就可以将图像取回,这是一个进步。但是,梯度计算可得出以下结果: