bool getISMRMRMetaValues(const ISMRMRD::MetaContainer& attrib, const std::string& name, std::vector<std::string>& v) { try { size_t num = attrib.length(name.c_str()); if ( num == 0 ) { v.clear(); GWARN_STREAM("getISMRMRMetaValues, can not find field : " << name); return true; } v.resize(num); size_t ii; for ( ii=0; ii<num; ii++ ) { v[ii] = std::string( attrib.as_str(name.c_str(), ii) ); } } catch(...) { GERROR_STREAM("Error happened in getISMRMRMetaValues(const ISMRMRD::MetaContainer& attrib, const std::string& name, std::vector<std::string>& v) ... "); return false; } return true; }
bool appendISMRMRMetaValues(ISMRMRD::MetaContainer& attrib, const std::string& name, const std::vector<std::string>& v) { try { size_t num = v.size(); if ( num == 0 ) { GWARN_STREAM("appendISMRMRMetaValues, input vector is empty ... " << name); return true; } attrib.append(name.c_str(), v[0].c_str()); size_t ii; for ( ii=1; ii<v.size(); ii++ ) { attrib.append(name.c_str(), v[ii].c_str()); } } catch(...) { GERROR_STREAM("Error happened in appendISMRMRMetaValues(ISMRMRD::MetaContainer& attrib, const std::string& name, const std::vector<std::string>& v) ... "); return false; } return true; }
size_t MultiChannelCartesianGrappaReconGadget::compute_image_number(ISMRMRD::ImageHeader& imheader, size_t encoding, size_t CHA, size_t cha, size_t E2) { if (encoding >= meas_max_idx_.size()) { GWARN_STREAM("encoding >= meas_max_idx_.size()"); encoding = 0; } size_t SET = meas_max_idx_[encoding].set + 1; size_t REP = meas_max_idx_[encoding].repetition + 1; size_t PHS = meas_max_idx_[encoding].phase + 1; size_t SLC = meas_max_idx_[encoding].slice + 1; size_t CON = meas_max_idx_[encoding].contrast + 1; if (E2 == 0) E2 = 1; size_t imageNum = imheader.average*REP*SET*PHS*CON*SLC*E2*CHA + imheader.repetition*SET*PHS*CON*SLC*E2*CHA + imheader.set*PHS*CON*SLC*E2*CHA + imheader.phase*CON*SLC*E2*CHA + imheader.contrast*SLC*E2*CHA + imheader.slice*E2*CHA + cha + 1; return imageNum; }
int GenericReconEigenChannelGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1) { if (perform_timing.value()) { gt_timer_.start("GenericReconEigenChannelGadget::process"); } process_called_times_++; IsmrmrdReconData* recon_bit_ = m1->getObjectPtr(); if (recon_bit_->rbit_.size() > num_encoding_spaces_) { GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_); } // for every encoding space, prepare the recon_bit_->rbit_[e].ref_ size_t e, n, s, slc; for (e = 0; e < recon_bit_->rbit_.size(); e++) { auto & rbit = recon_bit_->rbit_[e]; std::stringstream os; os << "_encoding_" << e; hoNDArray< std::complex<float> >& data = recon_bit_->rbit_[e].data_.data_; size_t RO = data.get_size(0); size_t E1 = data.get_size(1); size_t E2 = data.get_size(2); size_t CHA = data.get_size(3); size_t N = data.get_size(4); size_t S = data.get_size(5); size_t SLC = data.get_size(6); GDEBUG_CONDITION_STREAM(verbose.value(), "GenericReconEigenChannelGadget - incoming data array : [RO E1 E2 CHA N S SLC] - [" << RO << " " << E1 << " " << E2 << " " << CHA << " " << N << " " << S << " " << SLC << "]"); // whether it is needed to update coefficients bool recompute_coeff = false; if ( (KLT_[e].size()!=SLC) || update_eigen_channel_coefficients.value() ) { recompute_coeff = true; } else { if(KLT_[e].size() == SLC) { for (slc = 0; slc < SLC; slc++) { if (KLT_[e][slc].size() != S) { recompute_coeff = true; break; } else { for (s = 0; s < S; s++) { if (KLT_[e][slc][s].size() != N) { recompute_coeff = true; break; } } } } } } if(recompute_coeff) { bool average_N = average_all_ref_N.value(); bool average_S = average_all_ref_S.value(); if(rbit.ref_) { // use ref to compute coefficients Gadgetron::compute_eigen_channel_coefficients(rbit.ref_->data_, average_N, average_S, (calib_mode_[e] == Gadgetron::ISMRMRD_interleaved), N, S, upstream_coil_compression_thres.value(), upstream_coil_compression_num_modesKept.value(), KLT_[e]); } else { // use data to compute coefficients Gadgetron::compute_eigen_channel_coefficients(rbit.data_.data_, average_N, average_S, (calib_mode_[e] == Gadgetron::ISMRMRD_interleaved), N, S, upstream_coil_compression_thres.value(), upstream_coil_compression_num_modesKept.value(), KLT_[e]); } if (verbose.value()) { hoNDArray< std::complex<float> > E; for (slc = 0; slc < SLC; slc++) { for (s = 0; s < S; s++) { for (n = 0; n < N; n++) { KLT_[e][slc][s][n].eigen_value(E); GDEBUG_STREAM("Number of modes kept: " << KLT_[e][slc][s][n].output_length() << "; Eigen value, slc - " << slc << ", S - " << s << ", N - " << n << " : ["); for (size_t c = 0; c < E.get_size(0); c++) { GDEBUG_STREAM(" " << E(c)); } GDEBUG_STREAM("]"); } } } } } /*if (!debug_folder_full_path_.empty()) { gt_exporter_.exportArrayComplex(rbit.data_.data_, debug_folder_full_path_ + "data_before_KLT" + os.str()); }*/ // apply KL coefficients Gadgetron::apply_eigen_channel_coefficients(KLT_[e], rbit.data_.data_); /*if (!debug_folder_full_path_.empty()) { gt_exporter_.exportArrayComplex(rbit.data_.data_, debug_folder_full_path_ + "data_after_KLT" + os.str()); }*/ if (rbit.ref_) { /*if (!debug_folder_full_path_.empty()) { gt_exporter_.exportArrayComplex(rbit.ref_->data_, debug_folder_full_path_ + "ref_before_KLT" + os.str()); }*/ Gadgetron::apply_eigen_channel_coefficients(KLT_[e], rbit.ref_->data_); /*if (!debug_folder_full_path_.empty()) { gt_exporter_.exportArrayComplex(rbit.ref_->data_, debug_folder_full_path_ + "ref_after_KLT" + os.str()); }*/ } } if (perform_timing.value()) { gt_timer_.stop(); } if (this->next()->putq(m1) < 0) { GERROR_STREAM("Put IsmrmrdReconData to Q failed ... "); return GADGET_FAIL; } return GADGET_OK; }
int GenericReconCartesianGrappaGadget::process(Gadgetron::GadgetContainerMessage<IsmrmrdReconData> *m1) { if (perform_timing.value()) { gt_timer_local_.start("GenericReconCartesianGrappaGadget::process"); } process_called_times_++; IsmrmrdReconData *recon_bit_ = m1->getObjectPtr(); if (recon_bit_->rbit_.size() > num_encoding_spaces_) { GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_); } GadgetContainerMessage< std::vector<ISMRMRD::Waveform> > * wav = AsContainerMessage< std::vector<ISMRMRD::Waveform> >(m1->cont()); if (wav) { if (verbose.value()) { GDEBUG_STREAM("Incoming recon_bit with " << wav->getObjectPtr()->size() << " wave form samples "); } } // for every encoding space for (size_t e = 0; e < recon_bit_->rbit_.size(); e++) { std::stringstream os; os << "_encoding_" << e << "_" << process_called_times_; GDEBUG_CONDITION_STREAM(verbose.value(), "Calling " << process_called_times_ << " , encoding space : " << e); GDEBUG_CONDITION_STREAM(verbose.value(), "======================================================================"); // --------------------------------------------------------------- // export incoming data if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_, debug_folder_full_path_ + "data" + os.str()); } if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_) { if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0) { gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_), debug_folder_full_path_ + "data_traj" + os.str()); } } // --------------------------------------------------------------- if (recon_bit_->rbit_[e].ref_) { if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_bit_->rbit_[e].ref_->data_, debug_folder_full_path_ + "ref" + os.str()); } if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].ref_->trajectory_) { if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0) { gt_exporter_.export_array(*(recon_bit_->rbit_[e].ref_->trajectory_), debug_folder_full_path_ + "ref_traj" + os.str()); } } // --------------------------------------------------------------- // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::make_ref_coil_map"); } this->make_ref_coil_map(*recon_bit_->rbit_[e].ref_, *recon_bit_->rbit_[e].data_.data_.get_dimensions(), recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, e); if (perform_timing.value()) { gt_timer_.stop(); } // ---------------------------------------------------------- // export prepared ref for calibration and coil map if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_, debug_folder_full_path_ + "ref_calib" + os.str()); } if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_, debug_folder_full_path_ + "ref_coil_map" + os.str()); } // --------------------------------------------------------------- // after this step, the recon_obj_[e].ref_calib_dst_ and recon_obj_[e].ref_coil_map_ are modified if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::prepare_down_stream_coil_compression_ref_data"); } this->prepare_down_stream_coil_compression_ref_data(recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, recon_obj_[e].ref_calib_dst_, e); if (perform_timing.value()) { gt_timer_.stop(); } if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_dst_, debug_folder_full_path_ + "ref_calib_dst" + os.str()); } if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_, debug_folder_full_path_ + "ref_coil_map_dst" + os.str()); } // --------------------------------------------------------------- // after this step, coil map is computed and stored in recon_obj_[e].coil_map_ if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_coil_map_estimation"); } this->perform_coil_map_estimation(recon_obj_[e].ref_coil_map_, recon_obj_[e].coil_map_, e); if (perform_timing.value()) { gt_timer_.stop(); } // --------------------------------------------------------------- // after this step, recon_obj_[e].kernel_, recon_obj_[e].kernelIm_, recon_obj_[e].unmixing_coeff_ are filled // gfactor is computed too if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_calib"); } this->perform_calib(recon_bit_->rbit_[e], recon_obj_[e], e); if (perform_timing.value()) { gt_timer_.stop(); } // --------------------------------------------------------------- recon_bit_->rbit_[e].ref_->clear(); recon_bit_->rbit_[e].ref_ = boost::none; } if (recon_bit_->rbit_[e].data_.data_.get_number_of_elements() > 0) { if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_, debug_folder_full_path_ + "data_before_unwrapping" + os.str()); } if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_) { if (recon_bit_->rbit_[e].data_.trajectory_->get_number_of_elements() > 0) { gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_), debug_folder_full_path_ + "data_before_unwrapping_traj" + os.str()); } } // --------------------------------------------------------------- if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_unwrapping"); } this->perform_unwrapping(recon_bit_->rbit_[e], recon_obj_[e], e); if (perform_timing.value()) { gt_timer_.stop(); } // --------------------------------------------------------------- if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::compute_image_header"); } this->compute_image_header(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e); if (perform_timing.value()) { gt_timer_.stop(); } // --------------------------------------------------------------- // pass down waveform if(wav) recon_obj_[e].recon_res_.waveform_ = *wav->getObjectPtr(); recon_obj_[e].recon_res_.acq_headers_ = recon_bit_->rbit_[e].data_.headers_; // --------------------------------------------------------------- if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].recon_res_.data_, debug_folder_full_path_ + "recon_res" + os.str()); } if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::send_out_image_array"); } this->send_out_image_array(recon_obj_[e].recon_res_, e, image_series.value() + ((int) e + 1), GADGETRON_IMAGE_REGULAR); if (perform_timing.value()) { gt_timer_.stop(); } // --------------------------------------------------------------- if (send_out_gfactor.value() && recon_obj_[e].gfactor_.get_number_of_elements() > 0 && (acceFactorE1_[e] * acceFactorE2_[e] > 1)) { IsmrmrdImageArray res; Gadgetron::real_to_complex(recon_obj_[e].gfactor_, res.data_); res.headers_ = recon_obj_[e].recon_res_.headers_; res.meta_ = recon_obj_[e].recon_res_.meta_; if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::send_out_image_array, gfactor"); } this->send_out_image_array(res, e, image_series.value() + 10 * ((int) e + 2), GADGETRON_IMAGE_GFACTOR); if (perform_timing.value()) { gt_timer_.stop(); } } // --------------------------------------------------------------- if (send_out_snr_map.value()) { hoNDArray<std::complex<float> > snr_map; if (calib_mode_[e] == Gadgetron::ISMRMRD_noacceleration) { snr_map = recon_obj_[e].recon_res_.data_; } else { if (recon_obj_[e].gfactor_.get_number_of_elements() > 0) { if (perform_timing.value()) { gt_timer_.start("compute SNR map array"); } this->compute_snr_map(recon_obj_[e], snr_map); if (perform_timing.value()) { gt_timer_.stop(); } } } if (snr_map.get_number_of_elements() > 0) { if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(snr_map, debug_folder_full_path_ + "snr_map" + os.str()); } if (perform_timing.value()) { gt_timer_.start("send out gfactor array, snr map"); } IsmrmrdImageArray res; res.data_ = snr_map; res.headers_ = recon_obj_[e].recon_res_.headers_; res.meta_ = recon_obj_[e].recon_res_.meta_; res.acq_headers_ = recon_bit_->rbit_[e].data_.headers_; this->send_out_image_array(res, e, image_series.value() + 100 * ((int) e + 3), GADGETRON_IMAGE_SNR_MAP); if (perform_timing.value()) { gt_timer_.stop(); } } } } recon_obj_[e].recon_res_.data_.clear(); recon_obj_[e].gfactor_.clear(); recon_obj_[e].recon_res_.headers_.clear(); recon_obj_[e].recon_res_.meta_.clear(); } m1->release(); if (perform_timing.value()) { gt_timer_local_.stop(); } return GADGET_OK; }
void BucketToBufferGadget::stuff(std::vector<IsmrmrdAcquisitionData>::iterator it, IsmrmrdDataBuffered & dataBuffer, ISMRMRD::Encoding encoding, IsmrmrdAcquisitionBucketStats & stats, bool forref) { // The acquisition header and data ISMRMRD::AcquisitionHeader & acqhdr = *it->head_->getObjectPtr(); hoNDArray< std::complex<float> > & acqdata = *it->data_->getObjectPtr(); // we make one for the trajectory down below if we need it uint16_t NE0 = (uint16_t)dataBuffer.data_.get_size(0); uint16_t NE1 = (uint16_t)dataBuffer.data_.get_size(1); uint16_t NE2 = (uint16_t)dataBuffer.data_.get_size(2); uint16_t NCHA = (uint16_t)dataBuffer.data_.get_size(3); uint16_t NN = (uint16_t)dataBuffer.data_.get_size(4); uint16_t NS = (uint16_t)dataBuffer.data_.get_size(5); uint16_t NLOC = (uint16_t)dataBuffer.data_.get_size(6); size_t slice_loc; if (split_slices_ || NLOC==1) { slice_loc = 0; } else { slice_loc = acqhdr.idx.slice; } //Stuff the data uint16_t npts_to_copy = acqhdr.number_of_samples - acqhdr.discard_pre - acqhdr.discard_post; long long offset; if (encoding.trajectory == ISMRMRD::TrajectoryType::CARTESIAN || encoding.trajectory == ISMRMRD::TrajectoryType::EPI) { if ((acqhdr.number_of_samples == dataBuffer.data_.get_size(0)) && (acqhdr.center_sample == acqhdr.number_of_samples/2)) // acq has been corrected for center , e.g. by asymmetric handling { offset = acqhdr.discard_pre; } else { offset = (long long)dataBuffer.sampling_.sampling_limits_[0].center_ - (long long)acqhdr.center_sample; } } else { //TODO what about EPI with asymmetric readouts? //TODO any other sort of trajectory? offset = 0; } long long roffset = (long long) dataBuffer.data_.get_size(0) - npts_to_copy - offset; //GDEBUG_STREAM("Num_samp: "<< acqhdr.number_of_samples << ", pre: " << acqhdr.discard_pre << ", post" << acqhdr.discard_post << std::endl); //std::cout << "Sampling limits: " // << " min: " << dataBuffer.sampling_.sampling_limits_[0].min_ // << " max: " << dataBuffer.sampling_.sampling_limits_[0].max_ // << " center: " << dataBuffer.sampling_.sampling_limits_[0].center_ // << std::endl; //GDEBUG_STREAM("npts_to_copy = " << npts_to_copy << std::endl); //GDEBUG_STREAM("offset = " << offset << std::endl); //GDEBUG_STREAM("loffset = " << roffset << std::endl); if ((offset < 0) | (roffset < 0) ) { throw std::runtime_error("Acquired reference data does not fit into the reference data buffer.\n"); } std::complex<float> *dataptr; uint16_t NUsed = (uint16_t)getN(acqhdr.idx); if (NUsed >= NN) NUsed = NN - 1; uint16_t SUsed = (uint16_t)getS(acqhdr.idx); if (SUsed >= NS) SUsed = NS - 1; int16_t e1 = (int16_t)acqhdr.idx.kspace_encode_step_1; int16_t e2 = (int16_t)acqhdr.idx.kspace_encode_step_2; bool is_cartesian_sampling = (encoding.trajectory == ISMRMRD::TrajectoryType::CARTESIAN); bool is_epi_sampling = (encoding.trajectory == ISMRMRD::TrajectoryType::EPI); if(is_cartesian_sampling || is_epi_sampling) { if (!forref || (forref && (encoding.parallelImaging.get().calibrationMode.get() == "embedded"))) { // compute the center offset for E1 and E2 int16_t space_matrix_offset_E1 = 0; if (encoding.encodingLimits.kspace_encoding_step_1.is_present()) { space_matrix_offset_E1 = (int16_t)encoding.encodedSpace.matrixSize.y / 2 - (int16_t)encoding.encodingLimits.kspace_encoding_step_1->center; } int16_t space_matrix_offset_E2 = 0; if (encoding.encodingLimits.kspace_encoding_step_2.is_present() && encoding.encodedSpace.matrixSize.z > 1) { space_matrix_offset_E2 = (int16_t)encoding.encodedSpace.matrixSize.z / 2 - (int16_t)encoding.encodingLimits.kspace_encoding_step_2->center; } // compute the used e1 and e2 indices and make sure they are in the valid range e1 = (int16_t)acqhdr.idx.kspace_encode_step_1 + space_matrix_offset_E1; e2 = (int16_t)acqhdr.idx.kspace_encode_step_2 + space_matrix_offset_E2; } // for external or separate mode, it is possible the starting numbers of ref lines are not zero, therefore it is needed to subtract the staring ref line number // because the ref array size is set up by the actual number of lines acquired // only assumption for external or separate ref line mode is that all ref lines are numbered sequentially // the acquisition order of ref line can be arbitrary if (forref && ( (encoding.parallelImaging.get().calibrationMode.get() == "separate") || (encoding.parallelImaging.get().calibrationMode.get() == "external") ) ) { if(*stats.kspace_encode_step_1.begin()>0) { e1 = acqhdr.idx.kspace_encode_step_1 - *stats.kspace_encode_step_1.begin(); } if(*stats.kspace_encode_step_2.begin()>0) { e2 = acqhdr.idx.kspace_encode_step_2 - *stats.kspace_encode_step_2.begin(); } } if (e1 < 0 || e1 >= (int16_t)NE1) { // if the incoming line is outside the encoding limits, something is wrong GADGET_CHECK_THROW(acqhdr.idx.kspace_encode_step_1>=encoding.encodingLimits.kspace_encoding_step_1->minimum && acqhdr.idx.kspace_encode_step_1 <= encoding.encodingLimits.kspace_encoding_step_1->maximum); // if the incoming line is inside encoding limits but outside the encoded matrix, do not include the data GWARN_STREAM("incoming readout " << acqhdr.scan_counter << " is inside the encoding limits, but outside the encoded matrix for kspace_encode_step_1 : " << e1 << " out of " << NE1); return; } if (e2 < 0 || e2 >= (int16_t)NE2) { GADGET_CHECK_THROW(acqhdr.idx.kspace_encode_step_2 >= encoding.encodingLimits.kspace_encoding_step_2->minimum && acqhdr.idx.kspace_encode_step_2 <= encoding.encodingLimits.kspace_encoding_step_2->maximum); GWARN_STREAM("incoming readout " << acqhdr.scan_counter << " is inside the encoding limits, but outside the encoded matrix for kspace_encode_step_2 : " << e2 << " out of " << NE2); return; } } std::complex<float>* pData = &dataBuffer.data_(offset, e1, e2, 0, NUsed, SUsed, slice_loc); for (uint16_t cha = 0; cha < NCHA; cha++) { dataptr = pData + cha*NE0*NE1*NE2; memcpy(dataptr, &acqdata(acqhdr.discard_pre, cha), sizeof(std::complex<float>)*npts_to_copy); } dataBuffer.headers_(e1, e2, NUsed, SUsed, slice_loc) = acqhdr; if (acqhdr.trajectory_dimensions > 0) { hoNDArray< float > & acqtraj = *it->traj_->getObjectPtr(); // TODO do we need to check this? float * trajptr; trajptr = &(*dataBuffer.trajectory_)(0, offset, e1, e2, NUsed, SUsed, slice_loc); memcpy(trajptr, &acqtraj(0, acqhdr.discard_pre), sizeof(float)*npts_to_copy*acqhdr.trajectory_dimensions); } }
int MultiChannelCartesianGrappaReconGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1) { process_called_times_++; IsmrmrdReconData* recon_bit_ = m1->getObjectPtr(); if (recon_bit_->rbit_.size() > num_encoding_spaces_) { GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_); } // for every encoding space for (size_t e = 0; e < recon_bit_->rbit_.size(); e++) { std::stringstream os; os << "_encoding_" << e; GDEBUG_CONDITION_STREAM(verbose.value(), "Calling " << process_called_times_ << " , encoding space : " << e); GDEBUG_CONDITION_STREAM(verbose.value(), "======================================================================"); // --------------------------------------------------------------- if (recon_bit_->rbit_[e].ref_) { // --------------------------------------------------------------- // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set this->make_ref_coil_map(*recon_bit_->rbit_[e].ref_,*recon_bit_->rbit_[e].data_.data_.get_dimensions(), recon_obj_[e], e); // after this step, coil map is computed and stored in recon_obj_[e].coil_map_ if(!flatmap.value()) this->perform_coil_map_estimation(recon_bit_->rbit_[e], recon_obj_[e], e); else { recon_obj_[e].coil_map_=recon_obj_[e].ref_coil_map_; recon_obj_[e].coil_map_.fill(1);//create(*recon_bit_->rbit_[e].data_.data_.get_dimensions()); } // after this step, recon_obj_[e].kernel_, recon_obj_[e].kernelIm_, recon_obj_[e].unmixing_coeff_ are filled // gfactor is computed too this->perform_calib(recon_bit_->rbit_[e], recon_obj_[e], e); // --------------------------------------------------------------- recon_bit_->rbit_[e].ref_ = boost::none; } if (recon_bit_->rbit_[e].data_.data_.get_number_of_elements() > 0) { // --------------------------------------------------------------- this->perform_unwrapping(recon_bit_->rbit_[e], recon_obj_[e], e); // --------------------------------------------------------------- this->compute_image_header(recon_bit_->rbit_[e], recon_obj_[e], e); // --------------------------------------------------------------- this->send_out_image_array(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e, image_series.value() + ((int)e + 1), GADGETRON_IMAGE_REGULAR); } recon_obj_[e].recon_res_.data_.clear(); recon_obj_[e].gfactor_.clear(); recon_obj_[e].recon_res_.headers_.clear(); recon_obj_[e].recon_res_.meta_.clear(); } m1->release(); return GADGET_OK; }
int GenericReconCartesianReferencePrepGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1) { if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianReferencePrepGadget::process"); } process_called_times_++; IsmrmrdReconData* recon_bit_ = m1->getObjectPtr(); if (recon_bit_->rbit_.size() > num_encoding_spaces_) { GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_); } // for every encoding space, prepare the recon_bit_->rbit_[e].ref_ size_t e; for (e = 0; e < recon_bit_->rbit_.size(); e++) { auto & rbit = recon_bit_->rbit_[e]; std::stringstream os; os << "_encoding_" << e; // ----------------------------------------- // no acceleration mode // check the availability of ref data // ----------------------------------------- if (calib_mode_[e] == Gadgetron::ISMRMRD_noacceleration) { if (prepare_ref_always_no_acceleration.value() || !ref_prepared_[e]) { // if no ref data is set, make copy the ref point from the data if (!rbit.ref_) { rbit.ref_ = rbit.data_; ref_prepared_[e] = true; } } else { if (ref_prepared_[e]) { if (rbit.ref_) { // remove the ref rbit.ref_ = boost::none; } } continue; } } if (!rbit.ref_) continue; // useful variables hoNDArray< std::complex<float> >& ref = (*rbit.ref_).data_; SamplingLimit sampling_limits[3]; for (int i = 0; i < 3; i++) sampling_limits[i] = (*rbit.ref_).sampling_.sampling_limits_[i]; size_t RO = ref.get_size(0); size_t E1 = ref.get_size(1); size_t E2 = ref.get_size(2); size_t CHA = ref.get_size(3); size_t N = ref.get_size(4); size_t S = ref.get_size(5); size_t SLC = ref.get_size(6); // stored the ref data ready for calibration hoNDArray< std::complex<float> > ref_calib; // ----------------------------------------- // 1) average the ref according to the input parameters; // if interleaved mode, sampling times for every E1/E2 location is detected and line by line averaging is performed // this is required when irregular cartesian sampling is used or number of frames cannot be divided in full by acceleration factor // 2) detect the sampled region and crop the ref data if needed // 3) update the sampling_limits // ----------------------------------------- hoNDArray< std::complex<float> > ref_recon_buf; // step 1 bool count_sampling_freq = (calib_mode_[e] == ISMRMRD_interleaved); GADGET_CHECK_EXCEPTION_RETURN(Gadgetron::compute_averaged_data_N_S(ref, average_all_ref_N.value(), average_all_ref_S.value(), count_sampling_freq, ref_calib), GADGET_FAIL); // step 2, detect sampled region in ref, along E1 and E2 size_t start_E1(0), end_E1(0); auto t = Gadgetron::detect_sampled_region_E1(ref); start_E1 = std::get<0>(t); end_E1 = std::get<1>(t); size_t start_E2(0), end_E2(0); if (E2 > 1) { auto t = Gadgetron::detect_sampled_region_E2(ref); start_E2 = std::get<0>(t); end_E2 = std::get<1>(t); } // crop the ref_calib, along RO, E1 and E2 vector_td<size_t, 3> crop_offset; crop_offset[0] = sampling_limits[0].min_; crop_offset[1] = start_E1; crop_offset[2] = start_E2; vector_td<size_t, 3> crop_size; crop_size[0] = sampling_limits[0].max_ - sampling_limits[0].min_ + 1; crop_size[1] = end_E1 - start_E1 + 1; crop_size[2] = end_E2 - start_E2 + 1; if(crop_size[0]> (ref_calib.get_size(0)-crop_offset[0])) { crop_size[0] = ref_calib.get_size(0) - crop_offset[0]; } Gadgetron::crop(crop_offset, crop_size, &ref_calib, &ref_recon_buf); ref_calib = ref_recon_buf; // step 3, update the sampling limits sampling_limits[0].center_ = (uint16_t)(RO/2); if ( (calib_mode_[e] == Gadgetron::ISMRMRD_interleaved) || (calib_mode_[e] == Gadgetron::ISMRMRD_noacceleration) ) { // need to keep the ref kspace center information sampling_limits[1].min_ = (uint16_t)(start_E1); sampling_limits[1].max_ = (uint16_t)(end_E1); sampling_limits[2].min_ = (uint16_t)(start_E2); sampling_limits[2].max_ = (uint16_t)(end_E2); sampling_limits[1].center_ = (uint16_t)(E1 / 2); sampling_limits[2].center_ = (uint16_t)(E2 / 2); } else { // sepearate, embedded mode, the ref center is the kspace center sampling_limits[1].min_ = 0; sampling_limits[1].max_ = (uint16_t)(end_E1 - start_E1); sampling_limits[2].min_ = 0; sampling_limits[2].max_ = (uint16_t)(end_E2 - start_E2); sampling_limits[1].center_ = (sampling_limits[1].max_ + 1) / 2; sampling_limits[2].center_ = (sampling_limits[2].max_ + 1) / 2; } if(sampling_limits[0].max_>=RO) { sampling_limits[0].max_ = RO - 1; } ref = ref_calib; ref_prepared_[e] = true; for (int i = 0; i < 3; i++) (*rbit.ref_).sampling_.sampling_limits_[i] = sampling_limits[i]; } if (this->next()->putq(m1) < 0) { GERROR_STREAM("Put IsmrmrdReconData to Q failed ... "); return GADGET_FAIL; } if (perform_timing.value()) { gt_timer_.stop(); } return GADGET_OK; }
int GenericReconCartesianFFTGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1) { if (perform_timing.value()) { gt_timer_local_.start("GenericReconCartesianFFTGadget::process"); } process_called_times_++; IsmrmrdReconData* recon_bit_ = m1->getObjectPtr(); if (recon_bit_->rbit_.size() > num_encoding_spaces_) { GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_); } // for every encoding space for (size_t e = 0; e < recon_bit_->rbit_.size(); e++) { std::stringstream os; os << "_encoding_" << e; GDEBUG_CONDITION_STREAM(verbose.value(), "Calling " << process_called_times_ << " , encoding space : " << e); GDEBUG_CONDITION_STREAM(verbose.value(), "======================================================================"); // --------------------------------------------------------------- // export incoming data if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_, debug_folder_full_path_ + "data" + os.str()); } if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_) { if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0) { gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_), debug_folder_full_path_ + "data_traj" + os.str()); } } // --------------------------------------------------------------- if (recon_bit_->rbit_[e].ref_) { if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_bit_->rbit_[e].ref_->data_, debug_folder_full_path_ + "ref" + os.str()); } if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].ref_->trajectory_) { if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0) { gt_exporter_.export_array(*(recon_bit_->rbit_[e].ref_->trajectory_), debug_folder_full_path_ + "ref_traj" + os.str()); } } // --------------------------------------------------------------- // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::make_ref_coil_map"); } this->make_ref_coil_map(*recon_bit_->rbit_[e].ref_,*recon_bit_->rbit_[e].data_.data_.get_dimensions(), recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, e); if (perform_timing.value()) { gt_timer_.stop(); } // ---------------------------------------------------------- // export prepared ref for calibration and coil map if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_, debug_folder_full_path_ + "ref_calib" + os.str()); } if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_, debug_folder_full_path_ + "ref_coil_map" + os.str()); } // --------------------------------------------------------------- recon_bit_->rbit_[e].ref_ = boost::none; } if (recon_bit_->rbit_[e].data_.data_.get_number_of_elements() > 0) { if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_, debug_folder_full_path_ + "data_before_unwrapping" + os.str()); } if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_) { if (recon_bit_->rbit_[e].data_.trajectory_->get_number_of_elements() > 0) { gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_), debug_folder_full_path_ + "data_before_unwrapping_traj" + os.str()); } } // --------------------------------------------------------------- if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::perform_fft_combine"); } this->perform_fft_combine(recon_bit_->rbit_[e], recon_obj_[e], e); if (perform_timing.value()) { gt_timer_.stop(); } // --------------------------------------------------------------- if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::compute_image_header"); } this->compute_image_header(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e); if (perform_timing.value()) { gt_timer_.stop(); } // --------------------------------------------------------------- if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].recon_res_.data_, debug_folder_full_path_ + "recon_res" + os.str()); } if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::send_out_image_array"); } this->send_out_image_array(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e, image_series.value() + ((int)e + 1), GADGETRON_IMAGE_REGULAR); if (perform_timing.value()) { gt_timer_.stop(); } } recon_obj_[e].recon_res_.data_.clear(); recon_obj_[e].recon_res_.headers_.clear(); recon_obj_[e].recon_res_.meta_.clear(); } m1->release(); if (perform_timing.value()) { gt_timer_local_.stop(); } return GADGET_OK; }
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_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(...) ... "); } }