Example #1
0
void perform_dft(T *out_ptr, const T *mydata, int total_samples, int width, int height, std::string feature){

    fftw_complex *data_in;
    mycomplex *cI = new mycomplex[width*height]();

    ///initialize arrays for fftw operations
    data_in = ( fftw_complex* ) fftw_malloc( sizeof( fftw_complex ) * width* height);

    ///Store data in the real component of the data_in array.
    for(int r = 0; r < height; r++){
        for(int c = 0; c < width; c++){
                data_in[r*width+c][0] = mydata[r*width+c];
            data_in[r*width+c][1] = 0.0;
        }
    }

    fftw_complex    *data_out;
    fftw_plan       plan_f;

    data_out = ( fftw_complex* )fftw_malloc( sizeof( fftw_complex ) * width * height );

    plan_f = fftw_plan_dft_2d(width, height, data_in, data_out,  FFTW_FORWARD,  FFTW_ESTIMATE);

    fftw_execute( plan_f);

    double maxMagnitude =-1e5;
    double maxPower = -1e5;

    int tempr = 0, tempc = 0;
    for(int r = 0; r < height; r++){
        for(int c = 0; c < width; c++){
            /// normalize values

            double realI = data_out[r*width + c][0];
            double imagI = data_out[r*width + c][1];
            double powerI = ((realI * realI) + (imagI * imagI)) / double(total_samples);
            double magI = sqrt(powerI);

            ///Get the maximum value of the magnitude
            if(maxMagnitude < magI)
                maxMagnitude = magI;
            if(maxPower < powerI){
                tempr = r;
                tempc = c;
                maxPower = powerI;
            }

            std::complex<double> ci(realI, imagI);
            double phaseI = arg(ci) + M_PI;
            mycomplex z;
            z.r = realI;
            z.i = imagI;
            z.mag = magI;/// double(total_samples);
            z.phase = phaseI;
            z.power =powerI;
            cI[r*width+c] = z;
        }
    }

    //std::cout << maxPower << " " << tempc << " " << tempr <<  std::endl;
    double constantMagFactor = 1.0 / log10(1.0 + fabs(maxMagnitude));
    double constantPowerLogScaling = 1.0 / log10(1.0 + fabs(maxPower));

    double constantPowerScaling = 1.0 / fabs(maxPower);


    for(int r = 0; r < height; r++){
        for(int c = 0; c < width; c++){

            double magnitude = cI[r*width + c].mag;
            magnitude =  (magnitude < 1e-4) ? 0.0 : magnitude;
            magnitude = (constantMagFactor * log10(1.0 + magnitude));

            double power = cI[r*width + c].power;
            double powerLogScaling = constantPowerLogScaling * power;
            double powerScaling = constantPowerScaling * power; //Simple range mapping to (0,1)

            double phase = cI[r*width+c].phase;


            if(feature == "magnitude" || feature == "mag")
                out_ptr[r*width+c] = magnitude;
            else if(feature == "power-logscaled")
                out_ptr[r*width+c] = powerLogScaling;
            else if(feature == "power-scaled")
                out_ptr[r*width+c] = powerScaling;
            else if(feature == "power")
                out_ptr[r*width+c] = power;
            else if(feature == "phase")
                out_ptr[r*width+c] = phase / double(2 * M_PI);
            else if(feature == "magphase")
                out_ptr[r*width+c] = magnitude + phase;
            else{
                std::cerr << "Please specify the feature (magnitude or power) of the Fourier spectrum !!!" << std::endl;
                exit(-2);
            }
        }
    }

    swapQuadrants(out_ptr, width, height);

    fftw_destroy_plan( plan_f);
    fftw_free( data_out);
    fftw_free(data_in);
    delete [] cI;
}
    /**
     * With the critical edge selection, initial kernel erstimation can be accomplished quickly.
     * Objective function: E(k) = ||∇I^s ⊗ k - ∇B||² + γ||k||²
     * 
     * @param selectionGrads  array of x and y gradients of final selected edges (∇I^s) [-1, 1]
     * @param blurredGrads    array of x and y gradients of blurred image (∇B) [-1, 1]
     * @param kernel          energy preserving kernel (k)
     */
    void fastKernelEstimation(const array<Mat,2>& selectionGrads,
                              const array<Mat,2>& blurredGrads, Mat& kernel,
                              const float weight = 1e-2) {

        assert(selectionGrads[0].rows == blurredGrads[0].rows && "matrixes have to be of same size!");
        assert(selectionGrads[0].cols == blurredGrads[0].cols && "matrixes have to be of same size!");

        // based on Perseval's theorem, perform FFT
        //                __________              __________
        //             (  F(∂_x I^s) * F(∂_x B) + F(∂_y I^s) * F(∂_y B) )
        // k = F^-1 * ( ----------------------------------------------   )
        //             (         F(∂_x I^s)² + F(∂_y I^s)² + γ          )
        // where * is pointwise multiplication
        //                   __________
        // and F(∂_x I^s)² = F(∂_x I^s) * F(∂_x I^s) ! because they mean the norm
        // 
        // here: F(∂_x I^s) = xS
        //       F(∂_x B)   = xB
        //       F(∂_y I^s) = yS
        //       F(∂_y B)   = yB
        
        // compute FFTs
        // the result are stored as 2 channel matrices: Re(FFT(I)), Im(FFT(I))
        Mat xS, xB, yS, yB;
        deblur::dft(selectionGrads[0], xS);
        deblur::dft(blurredGrads[0], xB);
        deblur::dft(selectionGrads[1], yS);
        deblur::dft(blurredGrads[1], yB);

        complex<float> we(weight, 0.0);

        // kernel in Fourier domain
        Mat K = Mat::zeros(xS.size(), xS.type());

        // pixelwise computation of kernel
        for (int y = 0; y < K.rows; y++) {
            for (int x = 0; x < K.cols; x++) { 
                // complex entries at the current position
                complex<float> xs(xS.at<Vec2f>(y, x)[0], xS.at<Vec2f>(y, x)[1]);
                complex<float> ys(yS.at<Vec2f>(y, x)[0], yS.at<Vec2f>(y, x)[1]);

                complex<float> xb(xB.at<Vec2f>(y, x)[0], xB.at<Vec2f>(y, x)[1]);
                complex<float> yb(yB.at<Vec2f>(y, x)[0], yB.at<Vec2f>(y, x)[1]);


                // kernel entry in the Fourier space
                complex<float> k = (conj(xs) * xb + conj(ys) * yb) /
                                   (conj(xs) * xs + conj(ys) * ys + we);
                                   // (abs(xs) * abs(xs) + abs(ys) * abs(ys) + we); // equivalent
                
                K.at<Vec2f>(y, x) = { real(k), imag(k) };
            }
        }

        // only use the real part of the complex output
        Mat kernelBig;
        dft(K, kernelBig, DFT_INVERSE | DFT_REAL_OUTPUT);

        // FIXME: find kernel inside image (kind of bounding box) instead of force user to
        // approximate a correct kernel-width (otherwise some information are lost)

        // cut of kernel in middle of the temporary kernel
        int x = kernelBig.cols / 2 - kernel.cols / 2;
        int y = kernelBig.rows / 2 - kernel.rows / 2;
        swapQuadrants(kernelBig);
        Mat kernelROI = kernelBig(Rect(x, y, kernel.cols, kernel.rows));

        // copy the ROI to the kernel to avoid that some OpenCV functions accidently
        // uses the information outside of the ROI (like copyMakeBorder())
        kernelROI.copyTo(kernel);

        // threshold kernel to erease negative values
        threshold(kernel, kernel, 0.0, -1, THRESH_TOZERO);

        // // kernel has to be energy preserving
        // // this means: sum(kernel) = 1
        kernel /= sum(kernel)[0];
    }