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]; }