FFTW3的筛选泊松解决方案

时间:2019-03-13 09:30:32

标签: c++ image-processing graphics fftw

我想解决此paper中描述的屏蔽Poisson方程,以便根据粗略近似及其垂直和水平梯度来计算图像。我是第一次使用FFTW3。但是,我得到的结果很奇怪。

我对图像的粗略近似如下:

coarse render

但是我的解决方案的输出看起来像这样:

weird output

为了调试它,我尝试了多种方法–

首先,我怀疑我对空间频率的计算不正确,所以我尝试在傅立叶域中计算图像的水平梯度,结果是:

very weird image

最后,当我仅计算图像的FT及其逆变换时,我得到以下信息:

this

但是当我简单地将FT复制到新数组中并计算其逆FT时,我得到了:

this

这是我的功能:

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,而无需进行修改就可以将图像取回,这是一个进步。但是,梯度计算可得出以下结果:

horizontal gradient 所以我想我的空间频率计算仍然有问题

0 个答案:

没有答案