TEST(CBuffer2D, FftShiftEven) { auto original = std::make_shared<CBuffer2D>(4, 4); auto originalData = original->data(); // generate test data for (int64_t i = 0; i < 16; ++i) originalData[i] = Complex(static_cast<Real>(i)); auto shifted = original->fftShift(); auto shiftedData = shifted.data(); EXPECT_EQ(Complex(10.0), shiftedData[ 0]); EXPECT_EQ(Complex(11.0), shiftedData[ 1]); EXPECT_EQ(Complex( 8.0), shiftedData[ 2]); EXPECT_EQ(Complex( 9.0), shiftedData[ 3]); EXPECT_EQ(Complex(14.0), shiftedData[ 4]); EXPECT_EQ(Complex(15.0), shiftedData[ 5]); EXPECT_EQ(Complex(12.0), shiftedData[ 6]); EXPECT_EQ(Complex(13.0), shiftedData[ 7]); EXPECT_EQ(Complex( 2.0), shiftedData[ 8]); EXPECT_EQ(Complex( 3.0), shiftedData[ 9]); EXPECT_EQ(Complex( 0.0), shiftedData[10]); EXPECT_EQ(Complex( 1.0), shiftedData[11]); EXPECT_EQ(Complex( 6.0), shiftedData[12]); EXPECT_EQ(Complex( 7.0), shiftedData[13]); EXPECT_EQ(Complex( 4.0), shiftedData[14]); EXPECT_EQ(Complex( 5.0), shiftedData[15]); }
TEST(TestFFTShift,Shift_2x2x1) { const int N = 4; int data[N]; for (int i = 0; i<N; i++) data[i] = i; IndType3 gridDims; gridDims.x = 2; gridDims.y = 2; gridDims.z = 1; IndType3 offset; offset.x = 1; offset.y = 1; offset.z = 1; int expected[] = {3,2,1,0}; debugGrid(data,gridDims); fftShift(&data[0],N,gridDims,offset); for (int i=0; i<N;i++) EXPECT_EQ(expected[i],data[i]); printf("shifted: \n"); debugGrid(data,gridDims); }
TEST(TestFFTShift,Shift_4x4x2) { const int N = 32; int data[N]; for (int i = 0; i<N; i++) data[i] = i; IndType3 gridDims; gridDims.x = 4; gridDims.y = 4; gridDims.z = 2; IndType3 offset; offset.x = 2; offset.y = 2; offset.z = 1; int expected[] = {26,27,24,25,30,31,28,29,18,19,16,17,22,23,20,21,10,11,8,9,14,15,12,13,2,3,0,1,6,7,4,5}; debugGrid(data,gridDims); fftShift(&data[0],N,gridDims,offset); for (int i=0; i<N;i++) EXPECT_EQ(expected[i],data[i]); printf("shifted: \n"); debugGrid(data,gridDims); }
TEST(CBuffer2D, FftShiftOdd) { auto original = std::make_unique<CBuffer2D>(3, 3); auto originalData = original->data(); // generate test data for (int64_t i = 0; i < 9; ++i) originalData[i] = Complex(static_cast<Real>(i)); auto shifted = original->fftShift(); auto shiftedData = shifted.data(); EXPECT_EQ(Complex(8.0), shiftedData[0]); EXPECT_EQ(Complex(6.0), shiftedData[1]); EXPECT_EQ(Complex(7.0), shiftedData[2]); EXPECT_EQ(Complex(2.0), shiftedData[3]); EXPECT_EQ(Complex(0.0), shiftedData[4]); EXPECT_EQ(Complex(1.0), shiftedData[5]); EXPECT_EQ(Complex(5.0), shiftedData[6]); EXPECT_EQ(Complex(3.0), shiftedData[7]); EXPECT_EQ(Complex(4.0), shiftedData[8]); }
int main(int argc, char *argv[]) { ProgramOptions options(argc, argv); options.showParameters(); ReconParameters params = options.getReconParameters(); // -------------- Load multi-channel data ----------------- auto reconData = ReconData<float>::Create(params.samples, params.projections, options.isGPU()); loadReconData(params, reconData.get()); unsigned threads = std::min(reconData->channels(), omp_get_num_procs()); QElapsedTimer timer0, timer; timer0.start(); // -------------- Gridding ------------------------------- timer.start(); auto grid = GridLut<float>::Create(*reconData); #ifdef BUILD_CUDA if (options.isGPU()) { dynamic_cast<cuGridLut<float> *>(grid.get())->setNumOfPartitions(25); } #endif // BUILD_CUDA grid->setNumOfThreads(threads); grid->plan(params.rcxres, params.overgridding_factor, params.kernel_width, 512); auto imgData = grid->execute(); std::cout << "Gridding total time " << timer.elapsed() << " ms" << std::endl; ImageData<float> imgMap; if (params.pils) imgMap = *imgData; auto filter = ImageFilter<float>::Create(*imgData); filter->setNumOfThreads(threads); // --------------- FFT ---------------------------------- filter->fftPlan(); timer.restart(); filter->fftExecute(); filter->fftShift(); std::cout << "FFT total time " << timer.restart() << " ms" << std::endl; // -------------- Recon Methods ----------------------------------- timer.restart(); if (params.pils) { auto filterMap = ImageFilter<float>::Create(imgMap); std::cout << "\nRecon PILS... " << std::endl; filterMap->lowFilter(22); std::cout << "\nLow pass filtering | " << timer.restart() << " ms" << std::endl; std::cout << "\nFFT low res image... " << std::endl; filterMap->fftExecute(); filterMap->fftShift(); std::cout << "FFT total time " << timer.restart() << " ms" << std::endl; filterMap->normalize(); std::cout << "\nSum of Square Field Map..." << std::flush; filter->SOS(imgMap, {params.rcxres, params.rcyres, params.rczres}); std::cout << " | " << timer.elapsed() << " ms" << std::endl; } else { std::cout << "\nRecon SOS... " << std::flush; filter->SOS({params.rcxres, params.rcyres, params.rczres}); std::cout << " | " << timer.elapsed() << " ms" << std::endl; } std::cout << "\nProgram total time excluding I/O: " << timer0.elapsed() / 1000.0 << " s" << std::endl; // -------------------------- Save Data --------------------------- QFile file(params.path + params.outFile); file.open(QIODevice::WriteOnly); for (const auto &data : *imgData->getChannelImage()) { auto value = std::abs(data); file.write((const char *)&value, sizeof(decltype(value))); } file.close(); // -------------------------- Display Data ----------------------- int n = 0; if (options.isDisplay()) { QApplication app(argc, argv); for (int i = 0; i < imgData->channels(); i++) { auto data = imgData->getChannelImage(i); displayData(*data, imgData->imageSize(), QString("channel ") + QString::number(n++)); } return app.exec(); } else return 0; }
cv::Mat WavefrontSensor::WavefrontSensing(const std::vector<cv::Mat>& d, const double& meanPowerNoise) { unsigned int numberOfZernikes = 20; //total number of zernikes to be considered int M = numberOfZernikes; int K = d.size(); cv::Mat Q2; //We introduce here the lineal relationship between parameter phases of each optical path partlyKnownDifferencesInPhaseConstraints(M, K, Q2); std::vector<cv::Mat> Q2_v = {Q2, cv::Mat::zeros(Q2.size(), Q2.type())}; cv::Mat LEC; //Linear equality constraints cv::merge(Q2_v, LEC); //Build also the complex version of Q2 //process each patch independently cv::Mat dd; std::vector<cv::Mat> d_w; std::vector<Metric> mtrc_v; std::vector<std::pair<cv::Range,cv::Range> > rngs; unsigned int pixelsBetweenTiles = (int)(d.front().cols); unsigned int tileSize = 34; OpticalSetup tsettings( tileSize ); std::shared_ptr<Zernike> zrnk = std::make_shared<Zernike>(tsettings.pupilRadiousPixels(), tileSize, numberOfZernikes); divideIntoTiles(d.front().size(), pixelsBetweenTiles, tileSize, rngs); //Random row selector: Pick incoherent measurements cv::Mat eye_nn = cv::Mat::eye(K*tileSize*tileSize, K*tileSize*tileSize, cv::DataType<double>::type); unsigned int a = 400; //number of incoheren measurements cv::Mat shuffle_eye; shuffleRows(eye_nn, shuffle_eye); //Split 'a' into rngs.size() pieces std::vector<cv::Mat> A_v = {shuffle_eye(cv::Range(0, a), cv::Range::all()), cv::Mat::zeros(a, K*tileSize*tileSize, cv::DataType<double>::type)}; cv::Mat A; cv::merge(A_v, A); std::cout << "Number of anisoplanatic patches to annalize at once: " << rngs.size() << std::endl; for(auto rng_i : rngs) { cv::Mat d_col; //get ready dataset format std::vector<cv::Mat> D; std::vector<cv::Mat> d_col_v; for(cv::Mat di : d) { cv::Mat Di; cv::dft(di(rng_i.first, rng_i.second), Di, cv::DFT_COMPLEX_OUTPUT + cv::DFT_SCALE); fftShift(Di); D.push_back(Di); cv::Mat Di_t(Di.t()); d_col_v.push_back(Di_t.reshape(0, Di_t.total() )); } cv::vconcat(d_col_v, d_col); cv::gemm(A, d_col, 1.0, cv::Mat(), 1.0, d_col); //Picks rows randomly d_w.push_back( d_col ); mtrc_v.push_back( Metric(D, zrnk, meanPowerNoise) ); } cv::vconcat(d_w, dd); //-----------------------BY MEANS OF CONVEX OPTIMIZATION: //Objective function and gradient of the objective function if(false) { for(auto mtrc : mtrc_v) { std::function<double(cv::Mat)> func = std::bind(&Metric::objective, &mtrc, std::placeholders::_1); std::function<cv::Mat(cv::Mat)> dfunc = std::bind(&Metric::gradient, &mtrc, std::placeholders::_1); ConvexOptimization minimizationKit; cv::Mat x0_conv = cv::Mat::zeros(M*K, 1, cv::DataType<double>::type); //reset starting point //Lambda function that turn minimize function + constraints problem into minimize function lower dimension problem auto F_constrained = [] (cv::Mat x, std::function<double(cv::Mat)> func, const cv::Mat& Q2) -> double { return func(Q2*x); }; auto DF_constrained = [] (cv::Mat x, std::function<cv::Mat(cv::Mat)> dfunc, const cv::Mat& Q2) -> cv::Mat { return Q2.t() * dfunc(Q2*x); }; std::function<double(cv::Mat)> f_constrained = std::bind(F_constrained, std::placeholders::_1, func, Q2); std::function<cv::Mat(cv::Mat)> df_constrained = std::bind(DF_constrained, std::placeholders::_1, dfunc, Q2); //Define a new starting point with lower dimensions after reduction with contraints cv::Mat p_constrained = Q2.t() * x0_conv; ConvexOptimization min; min.perform_BFGS(p_constrained, f_constrained, df_constrained); x0_conv = Q2 * p_constrained; //Go back to original dimensional std::cout << "mimumum: " << x0_conv.t() << std::endl; } std::cout << "END OF CONVEX OPTIMIZATION" << std::endl; } //-----------------------BY MEANS OF SPARSE RECOVERY: //Create phase_div bias: only for the case of two diversity images!! // cv::Mat phase_div = cv::Mat::zeros(rngs.size()*M*K, 1, cv::DataType<double>::type); // phase_div.at<double>(M + 3, 0) = tsettings.k() * 3.141592/(2.0*std::sqrt(3.0)); cv::Mat x0 = cv::Mat::zeros(rngs.size()*M*K, 1, cv::DataType<double>::type); //Starting point std::vector<double> gamma_v(M*K, 1.0); for(unsigned int count=0;count<600;++count) { std::vector<cv::Mat> x0_vvv; cv::split(x0, x0_vvv); x0_vvv.at(0).copyTo(x0); cv::Mat_<std::complex<double> > blockMatrix_M; std::vector<cv::Mat> De_v; for(unsigned int t=0; t < rngs.size(); ++t) { cv::Mat jacob_i; mtrc_v.at(t).jacobian( x0(cv::Range(t*M*K, (t*M*K) + (M*K)), cv::Range::all()), jacob_i ); cv::gemm(A, jacob_i, 1.0, cv::Mat(), 1.0, jacob_i); //Picks rows randomly cv::gemm(jacob_i, LEC, 1.0, cv::Mat(), 1.0, jacob_i); //Apply constraints LECs cv::copyMakeBorder(blockMatrix_M, blockMatrix_M, 0, jacob_i.size().height, 0, jacob_i.size().width, cv::BORDER_CONSTANT, cv::Scalar(0.0, 0.0) ); cv::Rect rect(cv::Point(t*jacob_i.size().width, t*jacob_i.size().height), jacob_i.size() ); jacob_i.copyTo(blockMatrix_M( rect )); cv::Mat De_i; mtrc_v.at(t).phi( x0(cv::Range(t*M*K, (t*M*K) + (M*K)), cv::Range::all()), De_i ); cv::gemm(A, De_i, 1.0, cv::Mat(), 1.0, De_i); //Picks rows randomly De_v.push_back( De_i ); } cv::Mat De; cv::vconcat(De_v, De); std::vector<cv::Mat> x0_v = {x0, cv::Mat::zeros(x0.size(), x0.type())}; cv::merge(x0_v, x0); //Apply algorithm to get solution unsigned int blkLen = rngs.size(); cv::Mat blockMatrix_M_r; reorderColumns(blockMatrix_M, M, blockMatrix_M_r); //reorder columns so correlated data form a single block gamma_v = std::vector<double>(M*K, 1.0); //cv::Mat coeffs = perform_BSBL(blockMatrix_M_r, dd - De, NoiseLevel::Noiseless, gamma_v, blkLen); //Noiseless, LittleNoise //cv::Mat coeffs = perform_SBL(blockMatrix_M_r, dd - De, NoiseLevel::Noiseless, gamma_v); //Noiseless, LittleNoise cv::Mat coeffs = perform_projection(blockMatrix_M_r, dd - De); //Noiseless, LittleNoise cv::Mat coeffs_r; reorderColumns(coeffs.t(), blockMatrix_M.cols/M, coeffs_r); cv::Mat coeffs_r_n(coeffs_r.t()); //Undo constraints cv::Mat sol = cv::Mat::zeros(x0.size(), cv::DataType<std::complex<double> >::type); for(unsigned int t=0; t < rngs.size(); ++t) { cv::Mat sol_i; cv::gemm(LEC, coeffs_r_n(cv::Range(t*LEC.cols, (t*LEC.cols) + (LEC.cols)), cv::Range::all()), 1.0, cv::Mat(), 1.0, sol_i); sol_i.copyTo(sol(cv::Range(t*M*K, (t*M*K) + (M*K)), cv::Range::all())); } std::cout << "cv::norm(sol): " << cv::norm(sol) << std::endl; if(cv::norm(sol) < 1e-4 ) {std::cout << "Solution found" << std::endl; break;} x0 = x0 - sol; std::cout << "Solution number: " << count << std::endl; std::cout << "x0: " << x0.t() << std::endl; } return cv::Mat(); //mtrc.F(); }