void maxAbsolute(const hoNDArray<T>& x, T& r, size_t& ind) { size_t N = x.get_number_of_elements(); const T* pX = x.begin(); ind = 0; if ( N == 0 ) return; long long n; typename realType<T>::Type v = abs(pX[0]); typename realType<T>::Type v2; ind = 0; for ( n=1; n<(long long)N; n++ ) { v2 = std::abs(pX[n]); if ( v2 > v ) { v = v2; ind = n; } } r = pX[ind]; }
void correct_time_stamp_with_fitting(hoNDArray<float>& time_stamp, size_t startE1, size_t endE1) { try { size_t E1 = time_stamp.get_size(0); size_t N = time_stamp.get_size(1); size_t rE1 = endE1 - startE1 + 1; size_t e1, n; size_t num_acq_read_outs = 0; for ( n=0; n<N; n++ ) { for ( e1=0; e1<E1; e1++ ) { if ( time_stamp(e1, n) > 0 ) { num_acq_read_outs++; } } } GDEBUG_STREAM(" Number of acquired lines : " << num_acq_read_outs); float a, b; // y = a + b*x { std::vector<float> x(num_acq_read_outs), y(num_acq_read_outs); size_t ind = 0; for ( n=0; n<N; n++ ) { for ( e1=startE1; e1<=endE1; e1++ ) { float acq_time = time_stamp(e1, n); if ( acq_time > 0 ) { x[ind] = (float)(e1-startE1 + n*rE1); y[ind] = acq_time; ind++; } } } Gadgetron::simple_line_fit(x, y, a, b); } for ( n=0; n<N; n++ ) { for ( e1=startE1; e1<=endE1; e1++ ) { float x_v = (float)(e1-startE1 + n*rE1); time_stamp(e1, n) = a + b*x_v; } } } catch(...) { GADGET_THROW("Exceptions happened in correct_time_stamp_with_fitting(...) ... "); } }
void grappa2d_calib_convolution_kernel(const hoNDArray<T>& acsSrc, const hoNDArray<T>& acsDst, size_t accelFactor, double thres, size_t kRO, size_t kNE1, hoNDArray<T>& convKer) { size_t startRO = 0; size_t endRO = acsSrc.get_size(0) - 1; size_t startE1 = 0; size_t endE1 = acsSrc.get_size(1) - 1; grappa2d_calib_convolution_kernel(acsSrc, acsDst, accelFactor, thres, kRO, kNE1, startRO, endRO, startE1, endE1, convKer); }
int CS_FOCUSS_2D::fRecon(hoNDArray<std::complex<float> > &hacfInput, hoNDArray<std::complex<float> > &hacfRecon){ // input dimensions vtDim_ = *hacfInput.get_dimensions(); // number of channels iNChannels_ = (int)vtDim_[2]; // if Matlab is used, initialize singleton variables /*if (bMatlab_){ for (int iI = 0; iI < 20; iI++){ GlobalVar_FOCUSS::instance()->vbStatPrinc_.push_back(false); GlobalVar_FOCUSS::instance()->vfPrincipleComponents_.push_back(new hoNDArray<std::complex<float> > ()); } }*/ // const complex values const std::complex<float> cfZero(0.0); const std::complex<float> cfOne(1.0); // store incoming data in array hoNDArray<std::complex<float> > hacfKSpace = hacfInput; // permute kSpace: x-y-c -> y-x-c std::vector<size_t> vtDimOrder; vtDimOrder.push_back(1); vtDimOrder.push_back(0); vtDimOrder.push_back(2); hacfKSpace = *permute(&hacfKSpace, &vtDimOrder,false); // update dim_ vector vtDim_.clear(); vtDim_ = *hacfKSpace.get_dimensions(); //------------------------------------------------------------------------ //-------------------------- sampling mask ------------------------------- //------------------------------------------------------------------------ hoNDArray<std::complex<float> > hacfFullMask(hacfKSpace.get_dimensions()); hacfFullMask.fill(cfZero); hoNDArray<bool> habFullMask(hacfKSpace.get_dimensions()); habFullMask.fill(false); pcfPtr_ = hacfKSpace.get_data_ptr(); pcfPtr2_ = hacfFullMask.get_data_ptr(); pbPtr_ = habFullMask.get_data_ptr(); for (int i = 0; i < hacfKSpace.get_number_of_elements(); i++) if (pcfPtr_[i] != cfZero){ pcfPtr2_[i] = cfOne; pbPtr_[i] = true; } //------------------------------------------------------------------------- //---------------- iFFT x direction - x ky kz ^= v (n�) ------------------- //------------------------------------------------------------------------- if (Transform_fftBA_->get_active()){ if (!bMatlab_ && bDebug_) #if __GADGETRON_VERSION_HIGHER_3_6__ == 1 GDEBUG("FFT in read direction..\n"); #else GADGET_DEBUG1("FFT in read direction..\n"); #endif else if(bMatlab_ && bDebug_){ // mexPrintf("FFT in read direction..\n");mexEvalString("drawnow;"); } Transform_fftBA_->FTransform(hacfKSpace); }
void compute_phase_time_stamp(const hoNDArray<float>& time_stamp, const hoNDArray<float>& cpt_time_stamp, size_t startE1, size_t endE1, hoNDArray<float>& phs_time_stamp, hoNDArray<float>& phs_cpt_time_stamp) { try { size_t E1 = time_stamp.get_size(0); size_t N = time_stamp.get_size(1); size_t rE1 = endE1 - startE1 + 1; size_t e1, n; for ( n=0; n<N; n++ ) { // phase time stamp as the mean of all aquired lines size_t num = 0; float tt = 0.0f; for ( e1=startE1; e1<=endE1; e1++ ) { if(time_stamp(e1, n)>0) { tt += time_stamp(e1, n); num++; } } phs_time_stamp(n, 0) = tt/((num>0) ? num : 1); //// phase cpt time as the median of all acquired lines //std::vector<float> cpt_buf(rE1, 0); //for ( e1=startE1; e1<=endE1; e1++ ) //{ // if(cpt_time_stamp(e1, n)>=0) // cpt_buf[e1-startE1] = cpt_time_stamp(e1, n); //} //std::sort(cpt_buf.begin(), cpt_buf.end()); //phs_cpt_time_stamp(n, 0) = cpt_buf[E1/2-startE1]; // phase cpt time as the cpt time of center line phs_cpt_time_stamp(n, 0) = cpt_time_stamp(E1/2, n); } } catch(...) { GADGET_THROW("Exceptions happened in compute_phase_time_stamp(...) ... "); } }
void grappa2d_calib_convolution_kernel(const hoNDArray<T>& dataSrc, const hoNDArray<T>& dataDst, hoNDArray<unsigned short>& dataMask, size_t accelFactor, double thres, size_t kRO, size_t kNE1, hoNDArray<T>& convKer) { try { bool fitItself = false; if (&dataSrc != &dataDst) fitItself = true; GADGET_CHECK_THROW(dataSrc.dimensions_equal(&dataMask)); GADGET_CHECK_THROW(dataDst.dimensions_equal(&dataMask)); // find the fully sampled region size_t RO = dataMask.get_size(0); size_t E1 = dataMask.get_size(1); size_t srcCHA = dataSrc.get_size(2); size_t dstCHA = dataDst.get_size(2); size_t startRO(0), endRO(0), startE1(0), endE1(0); size_t ro, e1, scha, dcha; for (e1 = 0; e1 < E1; e1++) { for (ro = 0; ro < RO; ro++) { if (dataMask(ro, e1)>0) { if (ro < startRO) startRO = ro; if (ro > endRO) endRO = ro; if (e1 < startE1) startE1 = e1; if (e1 > endE1) endE1 = e1; } } } GADGET_CHECK_THROW(endRO>startRO); GADGET_CHECK_THROW(endE1>startE1 + accelFactor); GADGET_CATCH_THROW(grappa2d_calib_convolution_kernel(dataSrc, dataDst, accelFactor, thres, kRO, kNE1, startRO, endRO, startE1, endE1, convKer)); } catch (...) { GADGET_THROW("Errors in grappa2d_calib_convolution_kernel(dataMask) ... "); } }
void apply_unmix_coeff_kspace(const hoNDArray<T>& kspace, const hoNDArray<T>& unmixCoeff, hoNDArray<T>& complexIm) { try { GADGET_CHECK_THROW(kspace.get_size(0) == unmixCoeff.get_size(0)); GADGET_CHECK_THROW(kspace.get_size(1) == unmixCoeff.get_size(1)); GADGET_CHECK_THROW(kspace.get_size(2) == unmixCoeff.get_size(2)); hoNDArray<T> buffer2DT(kspace); GADGET_CATCH_THROW(Gadgetron::hoNDFFT<typename realType<T>::Type>::instance()->ifft2c(kspace, buffer2DT)); std::vector<size_t> dim; kspace.get_dimensions(dim); dim[2] = 1; if (!complexIm.dimensions_equal(&dim)) { complexIm.create(&dim); } Gadgetron::multiply(buffer2DT, unmixCoeff, buffer2DT); Gadgetron::sum_over_dimension(buffer2DT, complexIm, 2); } catch (...) { GADGET_THROW("Errors in apply_unmix_coeff_kspace(const hoNDArray<T>& kspace, const hoNDArray<T>& unmixCoeff, hoNDArray<T>& complexIm) ... "); } }
void apply_unmix_coeff_aliased_image(const hoNDArray<T>& aliasedIm, const hoNDArray<T>& unmixCoeff, hoNDArray<T>& complexIm) { try { GADGET_CHECK_THROW(aliasedIm.get_size(0) == unmixCoeff.get_size(0)); GADGET_CHECK_THROW(aliasedIm.get_size(1) == unmixCoeff.get_size(1)); GADGET_CHECK_THROW(aliasedIm.get_size(2) == unmixCoeff.get_size(2)); std::vector<size_t> dim; aliasedIm.get_dimensions(dim); dim[2] = 1; if (!complexIm.dimensions_equal(&dim)) { complexIm.create(&dim); } hoNDArray<T> buffer2DT(aliasedIm); Gadgetron::multiply(aliasedIm, unmixCoeff, buffer2DT); Gadgetron::sum_over_dimension(buffer2DT, complexIm, 2); } catch (...) { GADGET_THROW("Errors in apply_unmix_coeff_aliased_image(const hoNDArray<T>& aliasedIm, const hoNDArray<T>& unmixCoeff, hoNDArray<T>& complexIm) ... "); } }
hoNDArray<uint16_t> update_field_map(const hoNDArray<uint16_t> &field_map_index, const hoNDArray<uint16_t> &proposed_field_map_index, const hoNDArray<float> &residuals_map, const hoNDArray<float> &lambda_map) { hoNDArray<float> residual_diff_map(field_map_index.get_dimensions()); const auto X = field_map_index.get_size(0); const auto Y = field_map_index.get_size(1); const auto Z = field_map_index.get_size(2); for (size_t kz = 0; kz < Z; kz++) { for (size_t ky = 0; ky < Y; ky++) { for (size_t kx = 0; kx < X; kx++) { residual_diff_map(kx, ky,kz) = residuals_map(field_map_index(kx, ky,kz), kx, ky,kz) - residuals_map(proposed_field_map_index(kx, ky,kz), kx, ky,kz); } } } std::vector<boost::default_color_type> color_map; if (Z == 1) { color_map = graph_cut<2>(field_map_index, proposed_field_map_index, lambda_map, residual_diff_map); } else { color_map = graph_cut<3>(field_map_index, proposed_field_map_index, lambda_map, residual_diff_map); } auto result = field_map_index; size_t updated_voxels = 0; for (size_t i = 0; i < field_map_index.get_number_of_elements(); i++) { if (color_map[i] != boost::default_color_type::black_color) { updated_voxels++; result[i] = proposed_field_map_index[i]; } } return result; }
void maxValue(const hoNDArray<T>& a, T& v) { typedef T ValueType; try { const ValueType* pA = a.begin(); size_t n = a.get_number_of_elements(); v = pA[0]; size_t ii; for (ii=1; ii<n; ii++) { if (pA[ii]>v) v = pA[ii]; } } catch(...) { GADGET_THROW("Errors in maxValue(const hoNDArray<T>& a, T& v) ... "); } }
void sort(const hoNDArray<T>& x, hoNDArray<T>& r, bool isascending) { if ( &r != &x ) { if ( r.get_number_of_elements()!=x.get_number_of_elements()) { r = x; } else { memcpy(r.begin(), x.begin(), x.get_number_of_bytes()); } } sort(x.get_number_of_elements(), x.begin(), r.begin(), isascending); }
void outputPlotIm(const hoNDArray<unsigned char>& im, bool trueColor, hoNDArray<float>& plotIm) { size_t xsize = im.get_size(1); size_t ysize = im.get_size(2); plotIm.copyFrom(im); if (trueColor) { std::vector<size_t> dim_order(3); dim_order[0] = 1; dim_order[1] = 2; dim_order[2] = 0; hoNDArray<float> plotImPermuted; plotImPermuted.copyFrom(plotIm); plotIm.create(xsize, ysize, 3); Gadgetron::permute(plotImPermuted, plotIm, dim_order); } else { hoNDArray<float> plotIm2D; Gadgetron::sum_over_dimension(plotIm, plotIm2D, 0); plotIm2D.squeeze(); std::vector<size_t> dim_order(2); dim_order[0] = 0; dim_order[1] = 1; plotIm.create(xsize, ysize); Gadgetron::permute(plotIm2D, plotIm, dim_order); } }
hoNDArray< std::complex<float> > fatwater_separation(hoNDArray< std::complex<float> >& data, FatWaterParameters p, FatWaterAlgorithm a) { //Get some data parameters //7D, fixed order [X, Y, Z, CHA, N, S, LOC] uint16_t X = data.get_size(0); uint16_t Y = data.get_size(1); uint16_t Z = data.get_size(2); uint16_t CHA = data.get_size(3); uint16_t N = data.get_size(4); uint16_t S = data.get_size(5); uint16_t LOC = data.get_size(6); GDEBUG("Size of my array: %d, %d, %d .\n", X,Y,Z); hoNDArray< std::complex<float> > out(X,Y,Z,CHA,N,2,LOC); // S dimension gets replaced by water/fat stuff float fieldStrength = p.fieldStrengthT_; std::vector<float> echoTimes = p.echoTimes_; bool precessionIsClockwise = p.precessionIsClockwise_; for (auto& te: echoTimes) { te = te*0.001; // Echo times in seconds rather than milliseconds } GDEBUG("In toolbox - Field Strength: %f T \n", fieldStrength); for (auto& te: echoTimes) { GDEBUG("In toolbox - Echo time: %f seconds \n", te); } GDEBUG("In toolbox - PrecessionIsClockwise: %d \n", precessionIsClockwise); //Get or set some algorithm parameters //Gadgetron::ChemicalSpecies w = a.species_[0]; //Gadgetron::ChemicalSpecies f = a.species_[1]; // GDEBUG("In toolbox - Fat peaks: %f \n", f.ampFreq_[0].first); // GDEBUG("In toolbox - Fat peaks 2: %f \n", f.ampFreq_[0].second); // Set some initial parameters so we can get going // These will have to be specified in the XML file eventually std::pair<float,float> range_r2star = std::make_pair(0.0,0.0); uint16_t num_r2star = 1; std::pair<float,float> range_fm = std::make_pair(-80.0,80.0); uint16_t num_fm = 101; uint16_t num_iterations = 40; uint16_t subsample = 1; float lmap_power = 2.0; float lambda = 0.02; float lambda_extra = 0.02; //Check that we have reasonable data for fat-water separation //Calculate residual // float relAmp, freq_hz; uint16_t npeaks; uint16_t nspecies = a.species_.size(); uint16_t nte = echoTimes.size(); GDEBUG("In toolbox - NTE: %d \n", nte); hoMatrix< std::complex<float> > phiMatrix(nte,nspecies); for( int k1=0;k1<nte;k1++) { for( int k2=0;k2<nspecies;k2++) { phiMatrix(k1,k2) = 0.0; npeaks = a.species_[k2].ampFreq_.size(); for( int k3=0;k3<npeaks;k3++) { relAmp = a.species_[k2].ampFreq_[k3].first; freq_hz = fieldStrength*GAMMABAR*a.species_[k2].ampFreq_[k3].second; phiMatrix(k1,k2) += relAmp*std::complex<float>(cos(2*PI*echoTimes[k1]*freq_hz),sin(2*PI*echoTimes[k1]*freq_hz)); } GDEBUG("Cur value phiMatrix = (%f,%f) \n", phiMatrix(k1,k2).real(), phiMatrix(k1,k2).imag()); } } //auto a_phiMatrix = as_arma_matrix(&phiMatrix); //auto mymat2 = mymat.t()*mymat; for(int ka=0;ka<phiMatrix.get_size(0);ka++) { for(int kb=0;kb<phiMatrix.get_size(1);kb++) { GDEBUG("Check phiMatrix(%d,%d) = %f + i %f \n", ka,kb,phiMatrix(ka,kb).real(),phiMatrix(ka,kb).imag()); } } hoMatrix< std::complex<float> > IdentMat(nte,nte); for( int k1=0;k1<nte;k1++) { for( int k2=0;k2<nte;k2++) { if( k1==k2 ) { IdentMat(k1,k2) = std::complex<float>(1.0,0.0); } else { IdentMat(k1,k2) = std::complex<float>(0.0,0.0); } } } // auto a_phiMatrix = as_arma_matrix(&IdentMat); float fm; std::vector<float> fms(num_fm); fms[0] = range_fm.first; for(int k1=1;k1<num_fm;k1++) { fms[k1] = range_fm.first + k1*(range_fm.second-range_fm.first)/(num_fm-1); } float r2star; std::vector<float> r2stars(num_r2star); r2stars[0] = range_r2star.first; for(int k2=1;k2<num_r2star;k2++) { r2stars[k2] = range_r2star.first + k2*(range_r2star.second-range_r2star.first)/(num_r2star-1); } std::complex<float> curModulation; hoMatrix< std::complex<float> > tempM1(nspecies,nspecies); hoMatrix< std::complex<float> > tempM2(nspecies,nte); hoMatrix< std::complex<float> > psiMatrix(nte,nspecies); hoNDArray< std::complex<float> > Ps(nte,nte,num_fm,num_r2star); hoMatrix< std::complex<float> > P1(nte,nte); hoMatrix< std::complex<float> > P(nte,nte); for(int k3=0;k3<num_fm;k3++) { fm = fms[k3]; for(int k4=0;k4<num_r2star;k4++) { r2star = r2stars[k4]; for( int k1=0;k1<nte;k1++) { curModulation = exp(-r2star*echoTimes[k1])*std::complex<float>(cos(2*PI*echoTimes[k1]*fm),sin(2*PI*echoTimes[k1]*fm)); for( int k2=0;k2<nspecies;k2++) { psiMatrix(k1,k2) = phiMatrix(k1,k2)*curModulation; } } herk( tempM1, psiMatrix, 'L', true ); // tempM1.copyLowerTriToUpper(); for (int ka=0;ka<tempM1.get_size(0);ka++ ) { for (int kb=ka+1;kb<tempM1.get_size(1);kb++ ) { tempM1(ka,kb) = conj(tempM1(kb,ka)); } } if(k3==50) { for(int ka=0;ka<tempM1.get_size(0);ka++) { for(int kb=0;kb<tempM1.get_size(1);kb++) { GDEBUG(" tempM1(%d,%d) = %f + i %f \n", ka,kb,tempM1(ka,kb).real(),tempM1(ka,kb).imag()); } } } potri(tempM1); for (int ka=0;ka<tempM1.get_size(0);ka++ ) { for (int kb=ka+1;kb<tempM1.get_size(1);kb++ ) { tempM1(ka,kb) = conj(tempM1(kb,ka)); } } if(k3==50) { for(int ka=0;ka<tempM1.get_size(0);ka++) { for(int kb=0;kb<tempM1.get_size(1);kb++) { GDEBUG(" inv tempM1(%d,%d) = %f + i %f \n", ka,kb,tempM1(ka,kb).real(),tempM1(ka,kb).imag()); } } } //GDEBUG(" (%d,%d) = (%d,%d) X (%d,%d) \n", tempM2.get_size(0),tempM2.get_size(1),tempM1.get_size(0),tempM1.get_size(1),psiMatrix.get_size(1),psiMatrix.get_size(0)); gemm( tempM2, tempM1, false, psiMatrix, true ); if(k3==50) { for(int ka=0;ka<tempM2.get_size(0);ka++) { for(int kb=0;kb<tempM2.get_size(1);kb++) { GDEBUG(" tempM2(%d,%d) = %f + i %f \n", ka,kb,tempM2(ka,kb).real(),tempM2(ka,kb).imag()); } } } //GDEBUG(" (%d,%d) = (%d,%d) X (%d,%d) \n", P1.get_size(0),P1.get_size(1),psiMatrix.get_size(0),psiMatrix.get_size(1),tempM2.get_size(0),tempM2.get_size(1)); gemm( P1, psiMatrix, false, tempM2, false ); if(k3==50) { for(int ka=0;ka<P1.get_size(0);ka++) { for(int kb=0;kb<P1.get_size(1);kb++) { GDEBUG(" P1(%d,%d) = %f + i %f \n", ka,kb,P1(ka,kb).real(),P1(ka,kb).imag()); } } } subtract(IdentMat,P1,P); if(k3==50) { for(int ka=0;ka<P.get_size(0);ka++) { for(int kb=0;kb<P.get_size(1);kb++) { GDEBUG(" P(%d,%d) = %f + i %f \n", ka,kb,P(ka,kb).real(),P(ka,kb).imag()); } } } // Keep all projector matrices together for( int k1=0;k1<nte;k1++) { for( int k2=0;k2<nte;k2++) { Ps(k1,k2,k3,k4) = P(k1,k2); } } } } // Need to check that S = nte // N should be the number of contrasts (eg: for PSIR) hoMatrix< std::complex<float> > tempResVector(S,N); hoMatrix< std::complex<float> > tempSignal(S,N); hoNDArray<float> residual(num_fm,X,Y); hoNDArray<uint16_t> r2starIndex(X,Y,num_fm); hoNDArray<uint16_t> fmIndex(X,Y); float curResidual, minResidual, minResidual2; for( int k1=0;k1<X;k1++) { for( int k2=0;k2<Y;k2++) { // Get current signal for( int k4=0;k4<N;k4++) { for( int k5=0;k5<S;k5++) { tempSignal(k5,k4) = data(k1,k2,0,0,k4,k5,0); if (k1==107 && k2==144) { tempSignal(k5,k4) = std::complex<float>(1000.0,0.0);; GDEBUG(" (%d,%d) --> %f + i %f \n",k5,k4, tempSignal(k5,k4).real(),tempSignal(k5,k4).imag()); } } } minResidual2 = 1.0 + nrm2(&tempSignal); for(int k3=0;k3<num_fm;k3++) { minResidual = 1.0 + nrm2(&tempSignal); for(int k4=0;k4<num_r2star;k4++) { // Get current projector matrix for( int k5=0;k5<nte;k5++) { for( int k6=0;k6<nte;k6++) { P(k5,k6) = Ps(k5,k6,k3,k4); } } // Apply projector gemm( tempResVector, P, false, tempSignal, false ); curResidual = nrm2(&tempResVector); if (curResidual < minResidual) { minResidual = curResidual; r2starIndex(k1,k2,k3) = k4; } } residual(k3,k1,k2) = minResidual; if (minResidual < minResidual2) { minResidual2 = minResidual; fmIndex(k1,k2) = k3; } if (k1==107 && k2==144) { GDEBUG(" %f --> %f \n",fms[k3],minResidual); } } } } //arma::Mat< std::complex<float> > arma_phiMatrix = as_arma_matrix( phiMatrix ); //Do graph cut iterations using namespace boost; // create a typedef for the Graph type typedef adjacency_list<vecS, vecS, bidirectionalS> Graph; // Make convenient labels for the vertices enum { A, B, C, D, E }; const int num_vertices = 5; const char* name = "ABCDE"; // writing out the edges in the graph typedef std::pair<int, int> Edge; Edge edge_array[] = { Edge(A,B), Edge(A,D), Edge(C,A), Edge(D,C), Edge(C,E), Edge(B,D), Edge(D,E) }; const int num_edges = sizeof(edge_array)/sizeof(edge_array[0]); // declare a graph object Graph g(edge_array, edge_array + sizeof(edge_array) / sizeof(Edge), num_vertices); /* property_map<Graph, edge_capacity_t>::type capacity = get(edge_capacity, g); property_map<Graph, edge_reverse_t>::type rev = get(edge_reverse, g); property_map<Graph, edge_residual_capacity_t>::type residual_capacity = get(edge_residual_capacity, g); Traits::vertex_descriptor s, t; read_dimacs_max_flow(g, capacity, rev, s, t); long flow; #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 // Use non-named parameter version property_map<Graph, vertex_index_t>::type indexmap = get(vertex_index, g); flow = push_relabel_max_flow(g, s, t, capacity, residual_capacity, rev, indexmap); #else flow = push_relabel_max_flow(g, s, t); #endif std::cout << "c The total flow:" << std::endl; std::cout << "s " << flow << std::endl << std::endl; std::cout << "c flow values:" << std::endl; graph_traits<Graph>::vertex_iterator u_iter, u_end; graph_traits<Graph>::out_edge_iterator ei, e_end; for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) if (capacity[*ei] > 0) std::cout << "f " << *u_iter << " " << target(*ei, g) << " " << (capacity[*ei] - residual_capacity[*ei]) << std::endl; */ //Do final calculations once the field map is done hoMatrix< std::complex<float> > curWaterFat(2,N); hoMatrix< std::complex<float> > AhA(2,2); // Do fat-water separation with current field map and R2* estimates for( int k1=0;k1<X;k1++) { for( int k2=0;k2<Y;k2++) { // Get current signal for( int k4=0;k4<N;k4++) { for( int k5=0;k5<S;k5++) { tempSignal(k5,k4) = data(k1,k2,0,0,k4,k5,0); } } // Get current Psi matrix fm = fms[fmIndex(k1,k2)]; r2star = r2stars[r2starIndex(k1,k2,fmIndex(k1,k2))]; for( int k3=0;k3<nte;k3++) { curModulation = exp(-r2star*echoTimes[k3])*std::complex<float>(cos(2*PI*echoTimes[k3]*fm),sin(2*PI*echoTimes[k3]*fm)); for( int k4=0;k4<nspecies;k4++) { psiMatrix(k3,k4) = phiMatrix(k3,k4)*curModulation; } } // Solve for water and fat gemm( curWaterFat, psiMatrix, true, tempSignal, false ); herk( AhA, psiMatrix, 'L', true ); // AhA.copyLowerTriToUpper(); for (int ka=0;ka<AhA.get_size(0);ka++ ) { for (int kb=ka+1;kb<AhA.get_size(1);kb++ ) { AhA(ka,kb) = conj(AhA(kb,ka)); } } hesv(AhA,curWaterFat); for ( int k4=0;k4<N;k4++ ) { for ( int k5=0;k5<2;k5++ ) { // 2 elements for water and fat currently out(k1,k2,0,0,k4,k5,0) = curWaterFat(k5,k4); } } } } //Clean up as needed return out; }
void correct_heart_beat_time_stamp_with_fitting(hoNDArray<float>& cpt_time_stamp, hoNDArray<int>& ind_hb, size_t startE1, size_t endE1, const std::vector<size_t>& start_e1_hb, const std::vector<size_t>& end_e1_hb, const std::vector<size_t>& start_n_hb, const std::vector<size_t>& end_n_hb ) { try { size_t E1 = cpt_time_stamp.get_size(0); size_t N = cpt_time_stamp.get_size(1); size_t rE1 = endE1-startE1+1; size_t e1, n, ind, ii; size_t num_acq_read_outs = 0; for ( n=0; n<N; n++ ) { for ( e1=0; e1<E1; e1++ ) { if ( cpt_time_stamp(e1, n) >= 0 ) { num_acq_read_outs++; } } } size_t numOfHB = start_e1_hb.size(); std::vector<size_t> ind_HB_start(numOfHB); std::vector<size_t> ind_HB_end(numOfHB); for ( ind=0; ind<numOfHB; ind++ ) { ind_HB_start[ind] = start_e1_hb[ind] + start_n_hb[ind] * E1; ind_HB_end[ind] = end_e1_hb[ind] + end_n_hb[ind] * E1; } // -------------------------------------------------------- // fit a line to every heart beat // -------------------------------------------------------- float a, b; std::vector<float> A(numOfHB, 0.0f), B(numOfHB, 0.0f); for ( ind=0; ind<numOfHB; ind++ ) { std::vector<float> x, y; size_t cpt; for ( cpt=ind_HB_start[ind]; cpt<=ind_HB_end[ind]; cpt++ ) { size_t n = cpt / E1; size_t e1 = cpt - n*E1; if(e1>=startE1 && e1<=endE1) { if ( cpt_time_stamp[cpt] > -1 ) { size_t x_ind = (e1-startE1) + n*rE1; x.push_back( (float)x_ind ); y.push_back(cpt_time_stamp[cpt]); } } } if ( !x.empty() ) { Gadgetron::simple_line_fit(x, y, a, b); A[ind] = a; B[ind] = b; } } // -------------------------------------------------------- // compute cpt time stamp for every line // -------------------------------------------------------- size_t num = cpt_time_stamp.get_number_of_elements(); for ( ind=0; ind<num; ind++ ) { n = ind / E1; e1 = ind - n*E1; if(e1>=startE1 && e1<=endE1) { // find to which heart beat this line belongs bool foundHB = false; for ( ii=0; ii<numOfHB; ii++ ) { size_t startHB = ind_HB_start[ii]; size_t endHB = ind_HB_end[ii]; if ( ii==0 && ind<=startHB ) { foundHB = true; break; } if ( ii==numOfHB-1 && ind>=endHB ) { foundHB = true; break; } if ( ind>=startHB && ind<=endHB ) { foundHB = true; break; } } // if cannot find a heart beat, this kspace line will not be used if ( foundHB && (std::abs(B[ii])>0) ) { ind_hb(e1, n) = ii; size_t x_ind = (e1-startE1) + n*rE1; cpt_time_stamp(e1, n) = (float)(A[ii] + B[ii]*x_ind); } else { ind_hb(e1, n) = -1; } } else { cpt_time_stamp(e1, n) = -1; ind_hb(e1, n) = -1; } } } catch(...) { GADGET_THROW("Exceptions happened in correct_heart_beat_time_stamp_with_fitting(...) ... "); } }
void dotu(const hoNDArray<T>& x, const hoNDArray<T>& y, T& r) { GADGET_DEBUG_CHECK_THROW(x.get_number_of_elements()==y.get_number_of_elements()); dotu(x.get_number_of_elements(), x.begin(), y.begin(), r); }
template<class T> size_t amax(const hoNDArray<T>& x) { return amax(x.get_number_of_elements(), x.begin()); }
void grappa2d_convert_to_convolution_kernel(const hoNDArray<T>& ker, size_t kRO, const std::vector<int>& kE1, const std::vector<int>& oE1, hoNDArray<T>& convKer) { try { long long srcCHA = (long long)(ker.get_size(2)); long long dstCHA = (long long)(ker.get_size(3)); long long kNE1 = (long long)(kE1.size()); long long oNE1 = (long long)(oE1.size()); long long kROhalf = kRO / 2; if (2 * kROhalf == kRO) { GWARN_STREAM("grappa2d_convert_to_convolution_kernel - 2*kROhalf == kRO " << kRO); } kRO = 2 * kROhalf + 1; //// fill the convolution kernels long long convKRO = 2 * kRO + 3; long long maxKE1 = std::abs(kE1[0]); if (std::abs(kE1[kNE1 - 1]) > maxKE1) { maxKE1 = std::abs(kE1[kNE1 - 1]); } long long convKE1 = 2 * maxKE1 + 1; //// allocate the convolution kernel convKer.create(convKRO, convKE1, srcCHA, dstCHA); Gadgetron::clear(&convKer); //// index long long oe1, kro, ke1, src, dst; //// fill the convolution kernel and sum up multiple kernels for (oe1 = 0; oe1<oNE1; oe1++) { for (ke1 = 0; ke1<kNE1; ke1++) { for (kro = -kROhalf; kro <= kROhalf; kro++) { for (dst = 0; dst<dstCHA; dst++) { for (src = 0; src<srcCHA; src++) { convKer(-kro + kRO + 1, oE1[oe1] - kE1[ke1] + maxKE1, src, dst) = ker(kro + kROhalf, ke1, src, dst, oe1); } } } } } if (oE1[0] != 0) { for (dst = 0; dst<dstCHA; dst++) { convKer(kRO + 1, maxKE1, dst, dst) = 1.0; } } } catch (...) { GADGET_THROW("Errors in grappa2d_convert_to_convolution_kernel(...) ... "); } return; }
void detect_heart_beat_with_time_stamp(hoNDArray<float>& cpt_time_stamp, hoNDArray<int>& ind_hb, std::vector<size_t>& start_e1_hb, std::vector<size_t>& end_e1_hb, std::vector<size_t>& start_n_hb, std::vector<size_t>& end_n_hb ) { try { size_t E1 = cpt_time_stamp.get_size(0); size_t N = cpt_time_stamp.get_size(1); size_t e1, n, ind, ii; size_t num_acq_read_outs = 0; for ( n=0; n<N; n++ ) { for ( e1=0; e1<E1; e1++ ) { if ( cpt_time_stamp(e1, n) >= 0 ) { num_acq_read_outs++; } } } ind_hb.create(E1, N); Gadgetron::clear(ind_hb); // -------------------------------------------------------- // cpt time stamps // -------------------------------------------------------- std::vector<float> acquired_cpt(num_acq_read_outs); std::vector<size_t> ind_acquired_cpt(num_acq_read_outs); ind = 0; for ( n=0; n<N; n++ ) { for ( e1=0; e1<E1; e1++ ) { if ( cpt_time_stamp(e1, n) > -1 ) { acquired_cpt[ind] = cpt_time_stamp(e1, n); ind_acquired_cpt[ind] = e1 + n*E1; ind++; } } } // -------------------------------------------------------- // find the number of heart beats // -------------------------------------------------------- size_t numOfHB = 0; // store the line indexes for every heart beat std::vector<size_t> ind_HB_start, ind_HB_end; ind_HB_start.push_back(0); for ( ind=1; ind<num_acq_read_outs; ind++ ) { if ( acquired_cpt[ind] < acquired_cpt[ind-1] ) { // find a new heart beat numOfHB++; size_t end_ind_prev_HB = ind_acquired_cpt[ind-1]; size_t start_ind_curr_HB = ind_acquired_cpt[ind]; // if there is a gap between end and start ind, fill the gap if ( end_ind_prev_HB+1 != start_ind_curr_HB ) { long long gap = start_ind_curr_HB - end_ind_prev_HB - 1; if ( gap % 2 == 0 ) { end_ind_prev_HB += gap; } else { end_ind_prev_HB += gap; } if ( end_ind_prev_HB+1 != start_ind_curr_HB ) { GWARN_STREAM("end_ind_prev_HB+1 ~= start_ind_curr_HB : " << end_ind_prev_HB << " " << start_ind_curr_HB); } } ind_HB_end.push_back( end_ind_prev_HB ); ind_HB_start.push_back( start_ind_curr_HB ); } } ind_HB_end.push_back( E1*N-1 ); numOfHB = ind_HB_end.size(); // -------------------------------------------------------- // fill the start and end indexes // -------------------------------------------------------- start_e1_hb.resize(numOfHB, 0); end_e1_hb.resize(numOfHB, 0); start_n_hb.resize(numOfHB, 0); end_n_hb.resize(numOfHB, 0); std::vector<size_t> start, end; for ( ii=0; ii<numOfHB; ii++ ) { start_n_hb[ii] = ind_HB_start[ii] / E1; start_e1_hb[ii] = ind_HB_start[ii] - start_n_hb[ii] * E1; end_n_hb[ii] = ind_HB_end[ii] / E1; end_e1_hb[ii] = ind_HB_end[ii] - end_n_hb[ii]*E1; for (ind=ind_HB_start[ii]; ind<=ind_HB_end[ii]; ind++) { ind_hb(ind) = ii; } } } catch(...) { GADGET_THROW("Exceptions happened in detect_heart_beat_with_time_stamp(...) ... "); } }
void GenericReconCartesianGrappaGadget::prepare_down_stream_coil_compression_ref_data( const hoNDArray<std::complex<float> > &ref_src, hoNDArray<std::complex<float> > &ref_coil_map, hoNDArray<std::complex<float> > &ref_dst, size_t e) { if (!downstream_coil_compression.value()) { GDEBUG_CONDITION_STREAM(verbose.value(), "Downstream coil compression is not prescribed ... "); ref_dst = ref_src; return; } if (downstream_coil_compression_thres.value() < 0 && downstream_coil_compression_num_modesKept.value() == 0) { GDEBUG_CONDITION_STREAM(verbose.value(), "Downstream coil compression is prescribed to use all input channels ... "); ref_dst = ref_src; return; } // determine how many channels to use size_t RO = ref_src.get_size(0); size_t E1 = ref_src.get_size(1); size_t E2 = ref_src.get_size(2); size_t CHA = ref_src.get_size(3); size_t N = ref_src.get_size(4); size_t S = ref_src.get_size(5); size_t SLC = ref_src.get_size(6); size_t recon_RO = ref_coil_map.get_size(0); size_t recon_E1 = ref_coil_map.get_size(1); size_t recon_E2 = ref_coil_map.get_size(2); std::complex<float> *pRef = const_cast< std::complex<float> * >(ref_src.begin()); size_t dstCHA = CHA; if (downstream_coil_compression_num_modesKept.value() > 0 && downstream_coil_compression_num_modesKept.value() <= CHA) { dstCHA = downstream_coil_compression_num_modesKept.value(); } else { std::vector<float> E(CHA, 0); long long cha; #pragma omp parallel default(none) private(cha) shared(RO, E1, E2, CHA, pRef, E) { hoNDArray<std::complex<float> > dataCha; #pragma omp for for (cha = 0; cha < (long long) CHA; cha++) { dataCha.create(RO, E1, E2, pRef + cha * RO * E1 * E2); float v = Gadgetron::nrm2(dataCha); E[cha] = v * v; } } for (cha = 1; cha < (long long) CHA; cha++) { if (std::abs(E[cha]) < downstream_coil_compression_thres.value() * std::abs(E[0])) { break; } } dstCHA = cha; } GDEBUG_CONDITION_STREAM(verbose.value(), "Downstream coil compression is prescribed to use " << dstCHA << " out of " << CHA << " channels ..."); if (dstCHA < CHA) { ref_dst.create(RO, E1, E2, dstCHA, N, S, SLC); hoNDArray<std::complex<float> > ref_coil_map_dst; ref_coil_map_dst.create(recon_RO, recon_E1, recon_E2, dstCHA, N, S, SLC); size_t slc, s, n; for (slc = 0; slc < SLC; slc++) { for (s = 0; s < S; s++) { for (n = 0; n < N; n++) { std::complex<float> *pDst = &(ref_dst(0, 0, 0, 0, n, s, slc)); const std::complex<float> *pSrc = &(ref_src(0, 0, 0, 0, n, s, slc)); memcpy(pDst, pSrc, sizeof(std::complex<float>) * RO * E1 * E2 * dstCHA); pDst = &(ref_coil_map_dst(0, 0, 0, 0, n, s, slc)); pSrc = &(ref_coil_map(0, 0, 0, 0, n, s, slc)); memcpy(pDst, pSrc, sizeof(std::complex<float>) * recon_RO * recon_E1 * recon_E2 * dstCHA); } } } ref_coil_map = ref_coil_map_dst; } else { ref_dst = ref_src; } }
void GenericReconCartesianNonLinearSpirit2DTGadget::perform_nonlinear_spirit_unwrapping(hoNDArray< std::complex<float> >& kspace, hoNDArray< std::complex<float> >& kerIm, hoNDArray< std::complex<float> >& ref2DT, hoNDArray< std::complex<float> >& coilMap2DT, hoNDArray< std::complex<float> >& res, size_t e) { try { bool print_iter = this->spirit_print_iter.value(); size_t RO = kspace.get_size(0); size_t E1 = kspace.get_size(1); size_t E2 = kspace.get_size(2); size_t CHA = kspace.get_size(3); size_t N = kspace.get_size(4); size_t S = kspace.get_size(5); size_t SLC = kspace.get_size(6); size_t ref_N = kerIm.get_size(4); size_t ref_S = kerIm.get_size(5); hoNDArray< std::complex<float> > kspaceLinear(kspace); res = kspace; // detect whether random sampling is used bool use_random_sampling = false; std::vector<long long> sampled_step_size; long long n, e1; for (n=0; n<(long long)N; n++) { long long prev_sampled_line = -1; for (e1=0; e1<(long long)E1; e1++) { if(std::abs(kspace(RO/2, e1, 0, 0, 0, 0, 0))>0 && std::abs(kspace(RO/2, e1, 0, CHA-1, 0, 0, 0))>0) { if(prev_sampled_line>0) { sampled_step_size.push_back(e1 - prev_sampled_line); } prev_sampled_line = e1; } } } if(sampled_step_size.size()>4) { size_t s; for (s=2; s<sampled_step_size.size()-1; s++) { if(sampled_step_size[s]!=sampled_step_size[s-1]) { use_random_sampling = true; break; } } } if(use_random_sampling) { GDEBUG_STREAM("SPIRIT Non linear, random sampling is detected ... "); } Gadgetron::GadgetronTimer timer(false); // compute linear solution as the initialization if(use_random_sampling) { if (this->perform_timing.value()) timer.start("SPIRIT Non linear, perform linear spirit recon ... "); this->perform_spirit_unwrapping(kspace, kerIm, kspaceLinear); if (this->perform_timing.value()) timer.stop(); } else { if (this->perform_timing.value()) timer.start("SPIRIT Non linear, perform linear recon ... "); size_t ref2DT_RO = ref2DT.get_size(0); size_t ref2DT_E1 = ref2DT.get_size(1); // mean over N hoNDArray< std::complex<float> > meanKSpace; Gadgetron::sum_over_dimension(ref2DT, meanKSpace, 4); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(meanKSpace, debug_folder_full_path_ + "spirit_nl_2DT_meanKSpace"); } hoNDArray< std::complex<float> > acsSrc(ref2DT_RO, ref2DT_E1, CHA, meanKSpace.begin()); hoNDArray< std::complex<float> > acsDst(ref2DT_RO, ref2DT_E1, CHA, meanKSpace.begin()); double grappa_reg_lamda = 0.0005; size_t kRO = 5; size_t kE1 = 4; hoNDArray< std::complex<float> > convKer; hoNDArray< std::complex<float> > kIm(RO, E1, CHA, CHA); Gadgetron::grappa2d_calib_convolution_kernel(acsSrc, acsDst, (size_t)this->acceFactorE1_[e], grappa_reg_lamda, kRO, kE1, convKer); Gadgetron::grappa2d_image_domain_kernel(convKer, RO, E1, kIm); // if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(kIm, debug_folder_full_path_ + "spirit_nl_2DT_kIm"); Gadgetron::hoNDFFT<float>::instance()->ifft2c(kspace, complex_im_recon_buf_); // if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(complex_im_recon_buf_, debug_folder_full_path_ + "spirit_nl_2DT_aliasedImage"); hoNDArray< std::complex<float> > resKSpace(RO, E1, CHA, N); hoNDArray< std::complex<float> > aliasedImage(RO, E1, CHA, N, complex_im_recon_buf_.begin()); Gadgetron::grappa2d_image_domain_unwrapping_aliased_image(aliasedImage, kIm, resKSpace); // if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(resKSpace, debug_folder_full_path_ + "spirit_nl_2DT_linearImage"); Gadgetron::hoNDFFT<float>::instance()->fft2c(resKSpace); memcpy(kspaceLinear.begin(), resKSpace.begin(), resKSpace.get_number_of_bytes()); if (this->perform_timing.value()) timer.stop(); } // if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(kspaceLinear, debug_folder_full_path_ + "spirit_nl_2DT_kspaceLinear"); // perform nonlinear reconstruction { boost::shared_ptr< hoNDArray< std::complex<float> > > coilMap; bool hasCoilMap = false; if (coilMap2DT.get_size(0) == RO && coilMap2DT.get_size(1) == E1 && coilMap2DT.get_size(3)==CHA) { if (ref_N < N) { coilMap = boost::shared_ptr< hoNDArray< std::complex<float> > >(new hoNDArray< std::complex<float> >(RO, E1, CHA, coilMap2DT.begin())); } else { coilMap = boost::shared_ptr< hoNDArray< std::complex<float> > >(new hoNDArray< std::complex<float> >(RO, E1, CHA, ref_N, coilMap2DT.begin())); } hasCoilMap = true; } boost::shared_ptr<hoNDArray< std::complex<float> > > ker(new hoNDArray< std::complex<float> >(RO, E1, CHA, CHA, ref_N, kerIm.begin())); boost::shared_ptr<hoNDArray< std::complex<float> > > acq(new hoNDArray< std::complex<float> >(RO, E1, CHA, N, kspace.begin())); hoNDArray< std::complex<float> > kspaceInitial(RO, E1, CHA, N, kspaceLinear.begin()); hoNDArray< std::complex<float> > res2DT(RO, E1, CHA, N, res.begin()); if (this->spirit_data_fidelity_lamda.value() > 0) { GDEBUG_STREAM("Start the NL SPIRIT data fidelity iteration - regularization strength : " << this->spirit_image_reg_lamda.value() << " - number of iteration : " << this->spirit_nl_iter_max.value() << " - proximity across cha : " << this->spirit_reg_proximity_across_cha.value() << " - redundant dimension weighting ratio : " << this->spirit_reg_N_weighting_ratio.value() << " - using coil sen map : " << this->spirit_reg_use_coil_sen_map.value() << " - iter thres : " << this->spirit_nl_iter_thres.value()); typedef hoGdSolver< hoNDArray< std::complex<float> >, hoWavelet2DTOperator< std::complex<float> > > SolverType; SolverType solver; solver.iterations_ = this->spirit_nl_iter_max.value(); solver.set_output_mode(this->spirit_print_iter.value() ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); solver.grad_thres_ = this->spirit_nl_iter_thres.value(); solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda.value(); boost::shared_ptr< hoNDArray< std::complex<float> > > x0 = boost::make_shared< hoNDArray< std::complex<float> > >(kspaceInitial); solver.set_x0(x0); // parallel imaging term std::vector<size_t> dims; acq->get_dimensions(dims); hoSPIRIT2DTDataFidelityOperator< std::complex<float> > spirit(&dims); spirit.set_forward_kernel(*ker, false); spirit.set_acquired_points(*acq); // image reg term hoWavelet2DTOperator< std::complex<float> > wav3DOperator(&dims); wav3DOperator.set_acquired_points(*acq); wav3DOperator.scale_factor_first_dimension_ = this->spirit_reg_RO_weighting_ratio.value(); wav3DOperator.scale_factor_second_dimension_ = this->spirit_reg_E1_weighting_ratio.value(); wav3DOperator.scale_factor_third_dimension_ = this->spirit_reg_N_weighting_ratio.value(); wav3DOperator.with_approx_coeff_ = !this->spirit_reg_keep_approx_coeff.value(); wav3DOperator.change_coeffcients_third_dimension_boundary_ = !this->spirit_reg_keep_redundant_dimension_coeff.value(); wav3DOperator.proximity_across_cha_ = this->spirit_reg_proximity_across_cha.value(); wav3DOperator.no_null_space_ = true; wav3DOperator.input_in_kspace_ = true; if (this->spirit_reg_use_coil_sen_map.value() && hasCoilMap) { wav3DOperator.coil_map_ = *coilMap; } // set operators solver.oper_system_ = &spirit; solver.oper_reg_ = &wav3DOperator; if (this->perform_timing.value()) timer.start("NonLinear SPIRIT solver for 2DT with data fidelity ... "); solver.solve(*acq, res2DT); if (this->perform_timing.value()) timer.stop(); // if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_data_fidelity_res"); } else { GDEBUG_STREAM("Start the NL SPIRIT iteration with regularization strength : " << this->spirit_image_reg_lamda.value() << " - number of iteration : " << this->spirit_nl_iter_max.value() << " - proximity across cha : " << this->spirit_reg_proximity_across_cha.value() << " - redundant dimension weighting ratio : " << this->spirit_reg_N_weighting_ratio.value() << " - using coil sen map : " << this->spirit_reg_use_coil_sen_map.value() << " - iter thres : " << this->spirit_nl_iter_thres.value()); typedef hoGdSolver< hoNDArray< std::complex<float> >, hoWavelet2DTOperator< std::complex<float> > > SolverType; SolverType solver; solver.iterations_ = this->spirit_nl_iter_max.value(); solver.set_output_mode(this->spirit_print_iter.value() ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); solver.grad_thres_ = this->spirit_nl_iter_thres.value(); solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda.value(); boost::shared_ptr< hoNDArray< std::complex<float> > > x0 = boost::make_shared< hoNDArray< std::complex<float> > >(kspaceInitial); solver.set_x0(x0); // parallel imaging term std::vector<size_t> dims; acq->get_dimensions(dims); hoSPIRIT2DTOperator< std::complex<float> > spirit(&dims); spirit.set_forward_kernel(*ker, false); spirit.set_acquired_points(*acq); spirit.no_null_space_ = true; spirit.use_non_centered_fft_ = false; // image reg term std::vector<size_t> dim; acq->get_dimensions(dim); hoWavelet2DTOperator< std::complex<float> > wav3DOperator(&dim); wav3DOperator.set_acquired_points(*acq); wav3DOperator.scale_factor_first_dimension_ = this->spirit_reg_RO_weighting_ratio.value(); wav3DOperator.scale_factor_second_dimension_ = this->spirit_reg_E1_weighting_ratio.value(); wav3DOperator.scale_factor_third_dimension_ = this->spirit_reg_N_weighting_ratio.value(); wav3DOperator.with_approx_coeff_ = !this->spirit_reg_keep_approx_coeff.value(); wav3DOperator.change_coeffcients_third_dimension_boundary_ = !this->spirit_reg_keep_redundant_dimension_coeff.value(); wav3DOperator.proximity_across_cha_ = this->spirit_reg_proximity_across_cha.value(); wav3DOperator.no_null_space_ = true; wav3DOperator.input_in_kspace_ = true; if (this->spirit_reg_use_coil_sen_map.value() && hasCoilMap) { wav3DOperator.coil_map_ = *coilMap; } // set operators solver.oper_system_ = &spirit; solver.oper_reg_ = &wav3DOperator; // set call back solverCallBack cb; cb.solver_ = &solver; solver.call_back_ = &cb; hoNDArray< std::complex<float> > b(kspaceInitial); Gadgetron::clear(b); if (this->perform_timing.value()) timer.start("NonLinear SPIRIT solver for 2DT ... "); solver.solve(b, res2DT); if (this->perform_timing.value()) timer.stop(); // if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_res"); spirit.restore_acquired_kspace(kspace, res2DT); // if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_res_restored"); } } } catch (...) { GADGET_THROW("Errors happened in GenericReconCartesianNonLinearSpirit2DTGadget::perform_nonlinear_spirit_unwrapping(...) ... "); } }
void grappa2d_unmixing_coeff(const hoNDArray<T>& kerIm, const hoNDArray<T>& coilMap, size_t acceFactorE1, hoNDArray<T>& unmixCoeff, hoNDArray< typename realType<T>::Type >& gFactor) { try { typedef typename realType<T>::Type value_type; size_t RO = kerIm.get_size(0); size_t E1 = kerIm.get_size(1); size_t srcCHA = kerIm.get_size(2); size_t dstCHA = kerIm.get_size(3); GADGET_CHECK_THROW(acceFactorE1 >= 1); GADGET_CHECK_THROW(coilMap.get_size(0) == RO); GADGET_CHECK_THROW(coilMap.get_size(1) == E1); GADGET_CHECK_THROW(coilMap.get_size(2) == dstCHA); std::vector<size_t> dimUnmixing(3); dimUnmixing[0] = RO; dimUnmixing[1] = E1; dimUnmixing[2] = srcCHA; if (!unmixCoeff.dimensions_equal(&dimUnmixing)) { unmixCoeff.create(RO, E1, srcCHA); } Gadgetron::clear(&unmixCoeff); std::vector<size_t> dimGFactor(2); dimGFactor[0] = RO; dimGFactor[1] = E1; if (!gFactor.dimensions_equal(&dimGFactor)) { gFactor.create(RO, E1); } Gadgetron::clear(&gFactor); int src; T* pKerIm = const_cast<T*>(kerIm.begin()); T* pCoilMap = const_cast<T*>(coilMap.begin()); T* pCoeff = unmixCoeff.begin(); std::vector<size_t> dim(2); dim[0] = RO; dim[1] = E1; #pragma omp parallel default(none) private(src) shared(RO, E1, srcCHA, dstCHA, pKerIm, pCoilMap, pCoeff, dim) { hoNDArray<T> coeff2D, coeffTmp(&dim); hoNDArray<T> coilMap2D; hoNDArray<T> kerIm2D; #pragma omp for for (src = 0; src<(int)srcCHA; src++) { coeff2D.create(&dim, pCoeff + src*RO*E1); for (size_t dst = 0; dst<dstCHA; dst++) { kerIm2D.create(&dim, pKerIm + src*RO*E1 + dst*RO*E1*srcCHA); coilMap2D.create(&dim, pCoilMap + dst*RO*E1); Gadgetron::multiplyConj(kerIm2D, coilMap2D, coeffTmp); Gadgetron::add(coeff2D, coeffTmp, coeff2D); } } } hoNDArray<T> conjUnmixCoeff(unmixCoeff); Gadgetron::multiplyConj(unmixCoeff, conjUnmixCoeff, conjUnmixCoeff); // Gadgetron::sumOverLastDimension(conjUnmixCoeff, gFactor); hoNDArray<T> gFactorBuf(RO, E1, 1); Gadgetron::sum_over_dimension(conjUnmixCoeff, gFactorBuf, 2); Gadgetron::sqrt(gFactorBuf, gFactorBuf); Gadgetron::scal((value_type)(1.0 / acceFactorE1), gFactorBuf); Gadgetron::complex_to_real(gFactorBuf, gFactor); } catch (...) { GADGET_THROW("Errors in grappa2d_unmixing_coeff(const hoNDArray<T>& kerIm, const hoNDArray<T>& coilMap, hoNDArray<T>& unmixCoeff, hoNDArray<T>& gFactor) ... "); } }
void grappa2d_calib(const hoNDArray<T>& acsSrc, const hoNDArray<T>& acsDst, double thres, size_t kRO, const std::vector<int>& kE1, const std::vector<int>& oE1, size_t startRO, size_t endRO, size_t startE1, size_t endE1, hoNDArray<T>& ker) { try { GADGET_CHECK_THROW(acsSrc.get_size(0)==acsDst.get_size(0)); GADGET_CHECK_THROW(acsSrc.get_size(1)==acsDst.get_size(1)); GADGET_CHECK_THROW(acsSrc.get_size(2)>=acsDst.get_size(2)); size_t RO = acsSrc.get_size(0); size_t E1 = acsSrc.get_size(1); size_t srcCHA = acsSrc.get_size(2); size_t dstCHA = acsDst.get_size(2); const T* pSrc = acsSrc.begin(); const T* pDst = acsDst.begin(); long long kROhalf = kRO/2; if ( 2*kROhalf == kRO ) { GWARN_STREAM("grappa<T>::calib(...) - 2*kROhalf == kRO " << kRO); } kRO = 2*kROhalf + 1; size_t kNE1 = kE1.size(); size_t oNE1 = oE1.size(); /// allocate kernel ker.create(kRO, kNE1, srcCHA, dstCHA, oNE1); /// loop over the calibration region and assemble the equation /// Ax = b size_t sRO = startRO + kROhalf; size_t eRO = endRO - kROhalf; size_t sE1 = std::abs(kE1[0]) + startE1; size_t eE1 = endE1 - kE1[kNE1-1]; size_t lenRO = eRO - sRO + 1; size_t rowA = (eE1-sE1+1)*lenRO; size_t colA = kRO*kNE1*srcCHA; size_t colB = dstCHA*oNE1; hoMatrix<T> A; hoMatrix<T> B; hoMatrix<T> x( colA, colB ); hoNDArray<T> A_mem(rowA, colA); A.createMatrix( rowA, colA, A_mem.begin() ); T* pA = A.begin(); hoNDArray<T> B_mem(rowA, colB); B.createMatrix( A.rows(), colB, B_mem.begin() ); T* pB = B.begin(); long long e1; for ( e1=(long long)sE1; e1<=(long long)eE1; e1++ ) { for ( long long ro=sRO; ro<=(long long)eRO; ro++ ) { long long rInd = (e1-sE1)*lenRO+ro-kROhalf; size_t src, dst, ke1, oe1; long long kro; /// fill matrix A size_t col = 0; size_t offset = 0; for ( src=0; src<srcCHA; src++ ) { for ( ke1=0; ke1<kNE1; ke1++ ) { offset = src*RO*E1 + (e1+kE1[ke1])*RO; for ( kro=-kROhalf; kro<=kROhalf; kro++ ) { /// A(rInd, col++) = acsSrc(ro+kro, e1+kE1[ke1], src); pA[rInd + col*rowA] = pSrc[ro+kro+offset]; col++; } } } /// fill matrix B col = 0; for ( oe1=0; oe1<oNE1; oe1++ ) { for ( dst=0; dst<dstCHA; dst++ ) { B(rInd, col++) = acsDst(ro, e1+oE1[oe1], dst); } } } } SolveLinearSystem_Tikhonov(A, B, x, thres); memcpy(ker.begin(), x.begin(), ker.get_number_of_bytes()); } catch(...) { GADGET_THROW("Errors in grappa2d_calib(...) ... "); } return; }
template<class T> void asum(const hoNDArray<T>& x, typename realType<T>::Type& r) { asum(x.get_number_of_elements(), x.begin(), r); }
bool plotNoiseStandardDeviation(const hoNDArray< std::complex<T> >& m, const std::vector<std::string>& coilStrings, const std::string& xlabel, const std::string& ylabel, const std::string& title, size_t xsize, size_t ysize, bool trueColor, hoNDArray<float>& plotIm) { try { size_t CHA = m.get_size(0); GADGET_CHECK_RETURN_FALSE(coilStrings.size() == CHA); hoNDArray<double> xd, yd, yd2; xd.create(CHA); yd.create(CHA); size_t c; for (c = 0; c < CHA; c++) { xd(c) = c+1; yd(c) = std::sqrt( std::abs(m(c, c)) ); } double maxY = Gadgetron::max(&yd); yd2 = yd; std::sort(yd2.begin(), yd2.end()); double medY = yd2(CHA / 2); // increase dot line to be 1 sigma ~= 33% double medRange = 0.33; if (maxY < medY*(1 + medRange)) { maxY = medY*(1 + medRange); } hoNDArray<unsigned char> im; im.create(3, xsize, ysize); Gadgetron::clear(im); plsdev("mem"); plsmem(im.get_size(1), im.get_size(2), im.begin()); plinit(); plfont(2); pladv(0); plvpor(0.15, 0.75, 0.1, 0.8); plwind(0, CHA+1, 0, maxY*1.05); plcol0(15); plbox("bcnst", 0.0, 0, "bcnstv", 0.0, 0); std::string gly; getPlotGlyph(0, gly); // circle plstring(CHA, xd.begin(), yd.begin(), gly.c_str()); // draw the median line pllsty(1); double px[2], py[2]; px[0] = 0; px[1] = CHA+1; py[0] = medY; py[1] = medY; plline(2, px, py); pllsty(2); py[0] = medY*(1 - medRange); py[1] = medY*(1 - medRange); plline(2, px, py); py[0] = medY*(1 + medRange); py[1] = medY*(1 + medRange); plline(2, px, py); plmtex("b", 3.2, 0.5, 0.5, xlabel.c_str()); plmtex("t", 2.0, 0.5, 0.5, title.c_str()); plmtex("l", 5.0, 0.5, 0.5, ylabel.c_str()); // draw the legend std::vector<PLINT> opt_array(CHA), text_colors(CHA), line_colors(CHA), line_styles(CHA), symbol_numbers(CHA), symbol_colors(CHA); std::vector<PLFLT> symbol_scales(CHA), line_widths(CHA), box_scales(CHA, 1); std::vector<const char*> symbols(CHA); PLFLT legend_width, legend_height; std::vector<const char*> legend_text(CHA); std::vector<std::string> legends(CHA); size_t n; for (n = 0; n < CHA; n++) { opt_array[n] = PL_LEGEND_SYMBOL; text_colors[n] = 15; line_colors[n] = 15; line_styles[n] = (n % 8 + 1); line_widths[n] = 0.2; symbol_colors[n] = 15; symbol_scales[n] = 0.75; symbol_numbers[n] = 1; symbols[n] = gly.c_str(); std::ostringstream ostr; ostr << n+1 << ":" << coilStrings[n]; legends[n] = ostr.str(); legend_text[n] = legends[n].c_str(); } pllegend(&legend_width, &legend_height, PL_LEGEND_BACKGROUND, PL_POSITION_OUTSIDE | PL_POSITION_RIGHT, 0.02, // x 0.0, // y 0.05, // plot_width 0, // bg_color 15, // bb_color 1, // bb_style 0, // nrow 0, // ncolumn CHA, // nlegend &opt_array[0], 0.05, // text_offset 0.5, // text_scale 1.0, // text_spacing 0.5, // text_justification &text_colors[0], (const char **)(&legend_text[0]), NULL, // box_colors NULL, // box_patterns &box_scales[0], // box_scales NULL, // box_line_widths &line_colors[0], &line_styles[0], &line_widths[0], &symbol_colors[0], &symbol_scales[0], &symbol_numbers[0], (const char **)(&symbols[0]) ); plend(); outputPlotIm(im, trueColor, plotIm); } catch (...) { GERROR_STREAM("Errors happened in plotNoiseStandardDeviation(...) ... "); return false; } return true; }
void norm2(const hoNDArray<T>& x, typename realType<T>::Type& r) { norm2(x.get_number_of_elements(), x.begin(), r); }
void GenericReconCartesianNonLinearSpirit2DTGadget::perform_nonlinear_spirit_unwrapping(hoNDArray< std::complex<float> >& kspace, hoNDArray< std::complex<float> >& kerIm, hoNDArray< std::complex<float> >& ref2DT, hoNDArray< std::complex<float> >& coilMap2DT, hoNDArray< std::complex<float> >& res, size_t e) { try { bool print_iter = this->spirit_print_iter.value(); size_t RO = kspace.get_size(0); size_t E1 = kspace.get_size(1); size_t E2 = kspace.get_size(2); size_t CHA = kspace.get_size(3); size_t N = kspace.get_size(4); size_t S = kspace.get_size(5); size_t SLC = kspace.get_size(6); size_t ref_N = kerIm.get_size(4); size_t ref_S = kerIm.get_size(5); hoNDArray< std::complex<float> > kspaceLinear(kspace); res = kspace; // detect whether random sampling is used bool use_random_sampling = false; std::vector<long long> sampled_step_size; long long n, e1; for (n=0; n<(long long)N; n++) { long long prev_sampled_line = -1; for (e1=0; e1<(long long)E1; e1++) { if(std::abs(kspace(RO/2, e1, 0, 0, 0, 0, 0))>0 && std::abs(kspace(RO/2, e1, 0, CHA-1, 0, 0, 0))>0) { if(prev_sampled_line>0) { sampled_step_size.push_back(e1 - prev_sampled_line); } prev_sampled_line = e1; } } } if(sampled_step_size.size()>4) { size_t s; for (s=2; s<sampled_step_size.size()-1; s++) { if(sampled_step_size[s]!=sampled_step_size[s-1]) { use_random_sampling = true; break; } } } if(use_random_sampling) { GDEBUG_STREAM("SPIRIT Non linear, random sampling is detected ... "); } Gadgetron::GadgetronTimer timer(false); boost::shared_ptr< hoNDArray< std::complex<float> > > coilMap; bool hasCoilMap = false; if (coilMap2DT.get_size(0) == RO && coilMap2DT.get_size(1) == E1 && coilMap2DT.get_size(3)==CHA) { if (ref_N < N) { coilMap = boost::shared_ptr< hoNDArray< std::complex<float> > >(new hoNDArray< std::complex<float> >(RO, E1, CHA, coilMap2DT.begin())); } else { coilMap = boost::shared_ptr< hoNDArray< std::complex<float> > >(new hoNDArray< std::complex<float> >(RO, E1, CHA, ref_N, coilMap2DT.begin())); } hasCoilMap = true; } hoNDArray<float> gFactor; float gfactorMedian = 0; float smallest_eigen_value(0); // ----------------------------------------------------- // estimate gfactor // ----------------------------------------------------- // mean over N hoNDArray< std::complex<float> > meanKSpace; if(calib_mode_[e]==ISMRMRD_interleaved) { Gadgetron::compute_averaged_data_N_S(kspace, true, true, true, meanKSpace); } else { Gadgetron::compute_averaged_data_N_S(ref2DT, true, true, true, meanKSpace); } if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(meanKSpace, debug_folder_full_path_ + "spirit_nl_2DT_meanKSpace"); } hoNDArray< std::complex<float> > acsSrc(meanKSpace.get_size(0), meanKSpace.get_size(1), CHA, meanKSpace.begin()); hoNDArray< std::complex<float> > acsDst(meanKSpace.get_size(0), meanKSpace.get_size(1), CHA, meanKSpace.begin()); double grappa_reg_lamda = 0.0005; size_t kRO = 5; size_t kE1 = 4; hoNDArray< std::complex<float> > convKer; hoNDArray< std::complex<float> > kIm(RO, E1, CHA, CHA); Gadgetron::grappa2d_calib_convolution_kernel(acsSrc, acsDst, (size_t)this->acceFactorE1_[e], grappa_reg_lamda, kRO, kE1, convKer); Gadgetron::grappa2d_image_domain_kernel(convKer, RO, E1, kIm); hoNDArray< std::complex<float> > unmixC; if(hasCoilMap) { Gadgetron::grappa2d_unmixing_coeff(kIm, *coilMap, (size_t)acceFactorE1_[e], unmixC, gFactor); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array(gFactor, debug_folder_full_path_ + "spirit_nl_2DT_gFactor"); hoNDArray<float> gfactorSorted(gFactor); std::sort(gfactorSorted.begin(), gfactorSorted.begin()+RO*E1); gfactorMedian = gFactor((RO*E1 / 2)); GDEBUG_STREAM("SPIRIT Non linear, the median gfactor is found to be : " << gfactorMedian); } if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(kIm, debug_folder_full_path_ + "spirit_nl_2DT_kIm"); hoNDArray< std::complex<float> > complexIm; // compute linear solution as the initialization if(use_random_sampling) { if (this->perform_timing.value()) timer.start("SPIRIT Non linear, perform linear spirit recon ... "); this->perform_spirit_unwrapping(kspace, kerIm, kspaceLinear); if (this->perform_timing.value()) timer.stop(); } else { if (this->perform_timing.value()) timer.start("SPIRIT Non linear, perform linear recon ... "); //size_t ref2DT_RO = ref2DT.get_size(0); //size_t ref2DT_E1 = ref2DT.get_size(1); //// mean over N //hoNDArray< std::complex<float> > meanKSpace; //Gadgetron::sum_over_dimension(ref2DT, meanKSpace, 4); //if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(meanKSpace, debug_folder_full_path_ + "spirit_nl_2DT_meanKSpace"); } //hoNDArray< std::complex<float> > acsSrc(ref2DT_RO, ref2DT_E1, CHA, meanKSpace.begin()); //hoNDArray< std::complex<float> > acsDst(ref2DT_RO, ref2DT_E1, CHA, meanKSpace.begin()); //double grappa_reg_lamda = 0.0005; //size_t kRO = 5; //size_t kE1 = 4; //hoNDArray< std::complex<float> > convKer; //hoNDArray< std::complex<float> > kIm(RO, E1, CHA, CHA); //Gadgetron::grappa2d_calib_convolution_kernel(acsSrc, acsDst, (size_t)this->acceFactorE1_[e], grappa_reg_lamda, kRO, kE1, convKer); //Gadgetron::grappa2d_image_domain_kernel(convKer, RO, E1, kIm); //if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(kIm, debug_folder_full_path_ + "spirit_nl_2DT_kIm"); Gadgetron::hoNDFFT<float>::instance()->ifft2c(kspace, complex_im_recon_buf_); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(complex_im_recon_buf_, debug_folder_full_path_ + "spirit_nl_2DT_aliasedImage"); hoNDArray< std::complex<float> > resKSpace(RO, E1, CHA, N); hoNDArray< std::complex<float> > aliasedImage(RO, E1, CHA, N, complex_im_recon_buf_.begin()); Gadgetron::grappa2d_image_domain_unwrapping_aliased_image(aliasedImage, kIm, resKSpace); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(resKSpace, debug_folder_full_path_ + "spirit_nl_2DT_linearImage"); Gadgetron::hoNDFFT<float>::instance()->fft2c(resKSpace); memcpy(kspaceLinear.begin(), resKSpace.begin(), resKSpace.get_number_of_bytes()); Gadgetron::apply_unmix_coeff_aliased_image(aliasedImage, unmixC, complexIm); if (this->perform_timing.value()) timer.stop(); } if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(kspaceLinear, debug_folder_full_path_ + "spirit_nl_2DT_kspaceLinear"); if(hasCoilMap) { if(N>=spirit_reg_minimal_num_images_for_noise_floor.value()) { // estimate the noise level if(use_random_sampling) { Gadgetron::hoNDFFT<float>::instance()->ifft2c(kspaceLinear, complex_im_recon_buf_); hoNDArray< std::complex<float> > complexLinearImage(RO, E1, CHA, N, complex_im_recon_buf_.begin()); Gadgetron::coil_combine(complexLinearImage, *coilMap, 2, complexIm); } if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(complexIm, debug_folder_full_path_ + "spirit_nl_2DT_linearImage_complexIm"); // if N is sufficiently large, we can estimate the noise floor by the smallest eigen value hoMatrix< std::complex<float> > data; data.createMatrix(RO*E1, N, complexIm.begin(), false); hoNDArray< std::complex<float> > eigenVectors, eigenValues, eigenVectorsPruned; // compute eigen hoNDKLT< std::complex<float> > klt; klt.prepare(data, (size_t)1, (size_t)0); klt.eigen_value(eigenValues); if (this->verbose.value()) { GDEBUG_STREAM("SPIRIT Non linear, computes eigen values for all 2D kspaces ... "); eigenValues.print(std::cout); for (size_t i = 0; i<eigenValues.get_size(0); i++) { GDEBUG_STREAM(i << " = " << eigenValues(i)); } } smallest_eigen_value = std::sqrt( std::abs(eigenValues(N - 1).real()) / (RO*E1) ); GDEBUG_STREAM("SPIRIT Non linear, the smallest eigen value is : " << smallest_eigen_value); } } // perform nonlinear reconstruction { boost::shared_ptr<hoNDArray< std::complex<float> > > ker(new hoNDArray< std::complex<float> >(RO, E1, CHA, CHA, ref_N, kerIm.begin())); boost::shared_ptr<hoNDArray< std::complex<float> > > acq(new hoNDArray< std::complex<float> >(RO, E1, CHA, N, kspace.begin())); hoNDArray< std::complex<float> > kspaceInitial(RO, E1, CHA, N, kspaceLinear.begin()); hoNDArray< std::complex<float> > res2DT(RO, E1, CHA, N, res.begin()); if (this->spirit_data_fidelity_lamda.value() > 0) { GDEBUG_STREAM("Start the NL SPIRIT data fidelity iteration - regularization strength : " << this->spirit_image_reg_lamda.value() << " - number of iteration : " << this->spirit_nl_iter_max.value() << " - proximity across cha : " << this->spirit_reg_proximity_across_cha.value() << " - redundant dimension weighting ratio : " << this->spirit_reg_N_weighting_ratio.value() << " - using coil sen map : " << this->spirit_reg_use_coil_sen_map.value() << " - iter thres : " << this->spirit_nl_iter_thres.value() << " - wavelet name : " << this->spirit_reg_name.value() ); typedef hoGdSolver< hoNDArray< std::complex<float> >, hoWavelet2DTOperator< std::complex<float> > > SolverType; SolverType solver; solver.iterations_ = this->spirit_nl_iter_max.value(); solver.set_output_mode(this->spirit_print_iter.value() ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); solver.grad_thres_ = this->spirit_nl_iter_thres.value(); if(spirit_reg_estimate_noise_floor.value() && std::abs(smallest_eigen_value)>0) { solver.scale_factor_ = smallest_eigen_value; solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda.value() * gfactorMedian; GDEBUG_STREAM("SPIRIT Non linear, eigen value is used to derive the regularization strength : " << solver.proximal_strength_ratio_ << " - smallest eigen value : " << solver.scale_factor_); } else { solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda.value(); } boost::shared_ptr< hoNDArray< std::complex<float> > > x0 = boost::make_shared< hoNDArray< std::complex<float> > >(kspaceInitial); solver.set_x0(x0); // parallel imaging term std::vector<size_t> dims; acq->get_dimensions(dims); hoSPIRIT2DTDataFidelityOperator< std::complex<float> > spirit(&dims); spirit.set_forward_kernel(*ker, false); spirit.set_acquired_points(*acq); // image reg term hoWavelet2DTOperator< std::complex<float> > wav3DOperator(&dims); wav3DOperator.set_acquired_points(*acq); wav3DOperator.scale_factor_first_dimension_ = this->spirit_reg_RO_weighting_ratio.value(); wav3DOperator.scale_factor_second_dimension_ = this->spirit_reg_E1_weighting_ratio.value(); wav3DOperator.scale_factor_third_dimension_ = this->spirit_reg_N_weighting_ratio.value(); wav3DOperator.with_approx_coeff_ = !this->spirit_reg_keep_approx_coeff.value(); wav3DOperator.change_coeffcients_third_dimension_boundary_ = !this->spirit_reg_keep_redundant_dimension_coeff.value(); wav3DOperator.proximity_across_cha_ = this->spirit_reg_proximity_across_cha.value(); wav3DOperator.no_null_space_ = true; wav3DOperator.input_in_kspace_ = true; wav3DOperator.select_wavelet(this->spirit_reg_name.value()); if (this->spirit_reg_use_coil_sen_map.value() && hasCoilMap) { wav3DOperator.coil_map_ = *coilMap; } // set operators solver.oper_system_ = &spirit; solver.oper_reg_ = &wav3DOperator; if (this->perform_timing.value()) timer.start("NonLinear SPIRIT solver for 2DT with data fidelity ... "); solver.solve(*acq, res2DT); if (this->perform_timing.value()) timer.stop(); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_data_fidelity_res"); } else { GDEBUG_STREAM("Start the NL SPIRIT iteration with regularization strength : "<< this->spirit_image_reg_lamda.value() << " - number of iteration : " << this->spirit_nl_iter_max.value() << " - proximity across cha : " << this->spirit_reg_proximity_across_cha.value() << " - redundant dimension weighting ratio : " << this->spirit_reg_N_weighting_ratio.value() << " - using coil sen map : " << this->spirit_reg_use_coil_sen_map.value() << " - iter thres : " << this->spirit_nl_iter_thres.value() << " - wavelet name : " << this->spirit_reg_name.value() ); typedef hoGdSolver< hoNDArray< std::complex<float> >, hoWavelet2DTOperator< std::complex<float> > > SolverType; SolverType solver; solver.iterations_ = this->spirit_nl_iter_max.value(); solver.set_output_mode(this->spirit_print_iter.value() ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); solver.grad_thres_ = this->spirit_nl_iter_thres.value(); if(spirit_reg_estimate_noise_floor.value() && std::abs(smallest_eigen_value)>0) { solver.scale_factor_ = smallest_eigen_value; solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda.value() * gfactorMedian; GDEBUG_STREAM("SPIRIT Non linear, eigen value is used to derive the regularization strength : " << solver.proximal_strength_ratio_ << " - smallest eigen value : " << solver.scale_factor_); } else { solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda.value(); } boost::shared_ptr< hoNDArray< std::complex<float> > > x0 = boost::make_shared< hoNDArray< std::complex<float> > >(kspaceInitial); solver.set_x0(x0); // parallel imaging term std::vector<size_t> dims; acq->get_dimensions(dims); hoSPIRIT2DTOperator< std::complex<float> > spirit(&dims); spirit.set_forward_kernel(*ker, false); spirit.set_acquired_points(*acq); spirit.no_null_space_ = true; spirit.use_non_centered_fft_ = false; // image reg term std::vector<size_t> dim; acq->get_dimensions(dim); hoWavelet2DTOperator< std::complex<float> > wav3DOperator(&dim); wav3DOperator.set_acquired_points(*acq); wav3DOperator.scale_factor_first_dimension_ = this->spirit_reg_RO_weighting_ratio.value(); wav3DOperator.scale_factor_second_dimension_ = this->spirit_reg_E1_weighting_ratio.value(); wav3DOperator.scale_factor_third_dimension_ = this->spirit_reg_N_weighting_ratio.value(); wav3DOperator.with_approx_coeff_ = !this->spirit_reg_keep_approx_coeff.value(); wav3DOperator.change_coeffcients_third_dimension_boundary_ = !this->spirit_reg_keep_redundant_dimension_coeff.value(); wav3DOperator.proximity_across_cha_ = this->spirit_reg_proximity_across_cha.value(); wav3DOperator.no_null_space_ = true; wav3DOperator.input_in_kspace_ = true; wav3DOperator.select_wavelet(this->spirit_reg_name.value()); if (this->spirit_reg_use_coil_sen_map.value() && hasCoilMap) { wav3DOperator.coil_map_ = *coilMap; } // set operators solver.oper_system_ = &spirit; solver.oper_reg_ = &wav3DOperator; // set call back solverCallBack cb; cb.solver_ = &solver; solver.call_back_ = &cb; hoNDArray< std::complex<float> > b(kspaceInitial); Gadgetron::clear(b); if (this->perform_timing.value()) timer.start("NonLinear SPIRIT solver for 2DT ... "); solver.solve(b, res2DT); if (this->perform_timing.value()) timer.stop(); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_res"); spirit.restore_acquired_kspace(kspace, res2DT); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_res_restored"); } } } catch (...) { GADGET_THROW("Errors happened in GenericReconCartesianNonLinearSpirit2DTGadget::perform_nonlinear_spirit_unwrapping(...) ... "); } }
// C = A*B bool GeneralMatrixProduct(hoNDArray<float>& C, const hoNDArray<float>& A, bool transA, const hoNDArray<float>& B, bool transB) { try { typedef float T; size_t M = A.get_size(0); size_t K = A.get_size(1); if ( transA ) { M = A.get_size(1); K = A.get_size(0); } size_t K2 = B.get_size(0); size_t N = B.get_size(1); if ( transB ) { K2 = B.get_size(1); N = B.get_size(0); } GADGET_CHECK_RETURN_FALSE(K==K2); if ( (C.get_size(0)!=M) || (C.get_size(1)!=N) ) { C.create(M, N); } const T* pA = A.begin(); const T* pB = B.begin(); T* pC = C.begin(); size_t m, n, k; if ( !transA && !transB ) { for ( m=0; m<M; m++ ) { for ( n=0; n<N; n++ ) { pC[m+n*M] = 0; for ( k=0; k<K; k++ ) { pC[m+n*M] += pA[m+k*M]*pB[k+n*K]; } } } } if ( transA && !transB ) { for ( m=0; m<M; m++ ) { for ( n=0; n<N; n++ ) { pC[m+n*M] = 0; for ( k=0; k<K; k++ ) { pC[m+n*M] += pA[k+m*K]*pB[k+n*K]; } } } } if ( !transA && transB ) { for ( m=0; m<M; m++ ) { for ( n=0; n<N; n++ ) { pC[m+n*M] = 0; for ( k=0; k<K; k++ ) { pC[m+n*M] += pA[m+k*M]*pB[n+k*K]; } } } } if ( transA && transB ) { for ( m=0; m<M; m++ ) { for ( n=0; n<N; n++ ) { pC[m+n*M] = 0; for ( k=0; k<K; k++ ) { pC[m+n*M] += pA[k+m*K]*pB[n+k*K]; } } } } } catch(...) { GERROR_STREAM("Errors in GeneralMatrixProduct(hoNDArray<float>& C, const hoNDArray<float>& A, bool transA, const hoNDArray<float>& B, bool transB) ..."); return false; } return true; }