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) ... "); } }
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 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); } }
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 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; }
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_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(...) ... "); } }
// 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; }