From a99bb36670836965366bfd9b3fb155e7f41953dd Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 4 Jun 2018 10:24:53 +0100 Subject: [PATCH 001/274] first_commitment --- src/IO/InterfileHeader.cxx | 91 ++++++++++--- src/IO/interfile.cxx | 61 +++++++-- src/buildblock/KeyParser.cxx | 18 ++- src/include/stir/ExamInfo.h | 40 ++++-- src/include/stir/ExamInfo.inl | 75 ++++++++-- src/include/stir/IO/InterfileHeader.h | 11 +- src/include/stir/KeyParser.h | 6 +- src/include/stir/scatter/ScatterSimulation.h | 4 +- src/scatter_buildblock/ScatterSimulation.cxx | 27 ++++ .../scatter_detection_modelling.cxx | 14 +- ...scatter_estimate_for_one_scatter_point.cxx | 128 ++++++++++++++---- .../single_scatter_estimate.cxx | 21 ++- 12 files changed, 411 insertions(+), 85 deletions(-) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index f4d519dc8d..c1a6f537d6 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -94,6 +94,7 @@ void MinimalInterfileHeader::set_imaging_modality() InterfileHeader::InterfileHeader() : MinimalInterfileHeader() { + number_format_values.push_back("bit"); number_format_values.push_back("ascii"); number_format_values.push_back("signed integer"); @@ -145,6 +146,11 @@ InterfileHeader::InterfileHeader() matrix_labels.resize(num_dimensions); matrix_size.resize(num_dimensions); pixel_sizes.resize(num_dimensions, 1.); + num_energy_windows = 1; + lower_en_window_thres.resize(num_energy_windows); + upper_en_window_thres.resize(num_energy_windows); + lower_en_window_thres[0]=-1.F; + upper_en_window_thres[0]=-1.F; num_time_frames = 1; image_scaling_factors.resize(num_time_frames); for (int i=0; i 0 && lower_en_window_thres > 0 ) - { - exam_info_sptr->set_high_energy_thres(upper_en_window_thres); - exam_info_sptr->set_low_energy_thres(lower_en_window_thres); - } + + + //set the lower and the higher energy thresholds for all the energy windows available. Default: 1. + for (int i = 0; i < num_energy_windows; ++i) + { + if (upper_en_window_thres[i] > 0 && lower_en_window_thres[i] > 0 ) + { + exam_info_sptr->set_high_energy_thres(upper_en_window_thres[i],i); + exam_info_sptr->set_low_energy_thres(lower_en_window_thres[i],i); + } + } + + +//set the number of energy windows and pair + + + + exam_info_sptr->set_energy_window_pair(energy_window_pair,num_energy_windows); + exam_info_sptr->set_num_energy_windows(num_energy_windows); + + exam_info_sptr->time_frame_definitions = - TimeFrameDefinitions(image_relative_start_times, image_durations); + TimeFrameDefinitions(image_relative_start_times, image_durations); return false; @@ -363,6 +395,27 @@ void InterfileHeader::read_matrix_info() } + +void InterfileHeader::read_num_energy_windows() +{ + set_variable(); + + upper_en_window_thres.resize(num_energy_windows); + lower_en_window_thres.resize(num_energy_windows); + +} + + +void InterfileHeader::en_window_pair_set() +{ + + energy_window_pair.resize(2); + set_variable(); + +} + + + void InterfileHeader::set_type_of_data() { set_variable(); @@ -390,7 +443,7 @@ void InterfileHeader::set_type_of_data() KeyArgument::NONE, &KeyParser::do_nothing); // TODO rename keyword add_key("data offset in bytes", - KeyArgument::ULONG, &data_offset_each_dataset); + KeyArgument::ULONG, &data_offset_each_dataset); } else if (type_of_data == "Tomographic") @@ -451,6 +504,8 @@ bool InterfileImageHeader::post_processing() if (InterfileHeader::post_processing() == true) return true; + + if (PET_data_type_values[PET_data_type_index] != "Image") { warning("Interfile error: expecting an image\n"); return true; } @@ -590,6 +645,9 @@ void InterfilePDFSHeader::resize_segments_and_set() } + + + int InterfilePDFSHeader::find_storage_order() { @@ -1269,12 +1327,11 @@ bool InterfilePDFSHeader::post_processing() scanner_ptr_from_file->parameter_info().c_str()); } - + // float azimuthal_angle_sampling =_PI/num_views; - - - - + + + if (is_arccorrected) { if (effective_central_bin_size_in_cm <= 0) diff --git a/src/IO/interfile.cxx b/src/IO/interfile.cxx index 08501d1d05..5e40f5a4c8 100644 --- a/src/IO/interfile.cxx +++ b/src/IO/interfile.cxx @@ -1006,6 +1006,51 @@ write_basic_interfile_PDFS_header(const string& header_file_name, output_header << scanner.parameter_info(); + + //Write the number of energy windows available + + if (exam_info_ptr->get_num_energy_windows() > 0) + { + output_header <<"number of energy windows := " << + pdfs.get_exam_info_ptr()->get_num_energy_windows() << '\n'; + } + + else + { + // need to write this anyway to allow vectored keys below + output_header <<"number of energy windows := 1"; + } + + // Write energy window lower and upper thresholds for all the energy windows available, if they are not -1 + + + + for (unsigned int num_windows=0; num_windows<=exam_info_ptr->get_num_energy_windows()-1; ++num_windows) + { + + if (pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows) > 0 && + pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows) >= 0) + { + output_header << "energy window lower level [" << num_windows +1 << "] := " << + pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows) << '\n'; + output_header << "energy window upper level [" << num_windows +1<< "] := " << + pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows) << '\n'; + } + + } + + + //just for en_win>1 + + +if (pdfs.get_exam_info_ptr()->get_num_energy_windows() > 1) +{ + output_header << "energy window pair :="<<" {"<< pdfs.get_exam_info_ptr()->get_energy_window_pair().first << + ',' << pdfs.get_exam_info_ptr()->get_energy_window_pair().second <<"}\n"; + +} + + output_header << "effective central bin size (cm) := " << proj_data_info_ptr->get_sampling_in_s(Bin(0,0,0,0))/10. << endl; @@ -1016,6 +1061,7 @@ write_basic_interfile_PDFS_header(const string& header_file_name, } + // write time frame info // TODO this is according to the proposed interfile standard for PET. Interfile 3.3 is different { @@ -1040,17 +1086,10 @@ write_basic_interfile_PDFS_header(const string& header_file_name, output_header << "number of time frames := 1\n"; } } - // Write energy window lower and upper thresholds, if they are not -1 - { - if (pdfs.get_exam_info_ptr()->get_high_energy_thres() > 0 && - pdfs.get_exam_info_ptr()->get_low_energy_thres() >= 0) - { - output_header << "energy window lower level := " << - pdfs.get_exam_info_ptr()->get_low_energy_thres() << '\n'; - output_header << "energy window upper level := " << - pdfs.get_exam_info_ptr()->get_high_energy_thres() << '\n'; - } - } + + + + if (pdfs.get_scale_factor()!=1.F) output_header <<"image scaling factor[1] := " <is_vector.is_false()) + error(boost::format("Error parsing keyword %1%: should not be vectored"), keyword); + if (current_index == 0 && current->is_vector.is_true()) + error(boost::format("Error parsing keyword %1%: should be vectored"), keyword); +#endif switch(current->type) // depending on the par_type, gets the correct value from the line { // and sets the right temporary variable case KeyArgument::NONE : diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index 0af07936d3..b1f38a16ed 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -57,9 +57,19 @@ public : ExamInfo() : start_time_in_secs_since_1970(0.) { - low_energy_thres = -1.f; - up_energy_thres = -1.f; - } + + num_windows = 1; + low_energy_thres.resize(num_windows); + up_energy_thres.resize(num_windows); + en_win_pair.resize(2); + low_energy_thres[0]=-1.F; + up_energy_thres[0]=-1.F; + en_win_pair[0]=-1.F; + en_win_pair[1]=-1.F; + + } + + std::string originating_system; @@ -74,17 +84,24 @@ public : //! \name Functions that return info related on the acquisition settings //@{ //! Get the low energy boundary - inline float get_low_energy_thres() const; + inline float get_low_energy_thres(int en_window = 0) const; //! Get the high energy boundary - inline float get_high_energy_thres() const; + inline float get_high_energy_thres(int en_window = 0) const; + //! Get the number of energy windows + inline int get_num_energy_windows() const; + inline std::pair get_energy_window_pair() const; //@} + //! \name Functions that set values related on the acquisition settings //@{ //! Set the low energy boundary - inline void set_low_energy_thres(float new_val); + inline void set_low_energy_thres(float new_val,int en_window = 0); //! Set the high energy boundary - inline void set_high_energy_thres(float new_val); + inline void set_high_energy_thres(float new_val,int en_window = 0); + //! Set the number of energy windows + inline void set_num_energy_windows(int n_win); + inline void set_energy_window_pair(std::vector val,int n_win); //@} //! Standard trick for a 'virtual copy-constructor' @@ -104,7 +121,9 @@ public : //! The units are keV //! This parameter was initially introduced for scatter simulation. //! If scatter simulation is not needed, can default to -1 - float low_energy_thres; + + int num_windows; + std::vector low_energy_thres; //! //! \brief up_energy_thres @@ -113,7 +132,10 @@ public : //! The units are keV //! This parameter was initially introduced for scatter simulation //! If scatter simulation is not needed, can default to -1 - float up_energy_thres; + std::vector up_energy_thres; + + std::vector en_win_pair; + }; END_NAMESPACE_STIR diff --git a/src/include/stir/ExamInfo.inl b/src/include/stir/ExamInfo.inl index 28fb784fbe..8e92fb2bcc 100644 --- a/src/include/stir/ExamInfo.inl +++ b/src/include/stir/ExamInfo.inl @@ -39,27 +39,86 @@ create_shared_clone() const } void -ExamInfo::set_low_energy_thres(float new_val) +ExamInfo::set_low_energy_thres(float new_val,int en_window) { - low_energy_thres = new_val; + low_energy_thres[en_window] = new_val; } void -ExamInfo::set_high_energy_thres(float new_val) +ExamInfo::set_high_energy_thres(float new_val,int en_window) { - up_energy_thres = new_val; + up_energy_thres[en_window] = new_val; } +void +ExamInfo::set_num_energy_windows(int n_win) +{ + num_windows = n_win; +} + + +void +ExamInfo::set_energy_window_pair(std::vector val,int n_win) +{ + + + en_win_pair=val; + + for (int i = 0 ; i <= 1 ; ++i) + { + if (en_win_pair[i] >= n_win) + error("The selected pair (%d) exceeds the number of energy windows (%d): it needs to be set to supported value",en_win_pair[i],n_win); + } + +} + + +//Get the lower energy boundary for all the energy windows. en_window is set to 0 by default +//So that it will work also in the case of 1 energy window + float -ExamInfo::get_low_energy_thres() const +ExamInfo::get_low_energy_thres(int en_window) const { - return low_energy_thres; + return low_energy_thres[en_window]; } +//Get the high energy boundary for all the energy windows. en_window is set to 0 by default +//So that it will work also in the case of 1 energy window + float -ExamInfo::get_high_energy_thres() const +ExamInfo::get_high_energy_thres(int en_window) const +{ + + return up_energy_thres[en_window]; + +} + +//Get the number of energy windows +int +ExamInfo::get_num_energy_windows() const { - return up_energy_thres; + + return num_windows; + + } +std::pair +ExamInfo::get_energy_window_pair() const +{ + +std::pair pair; +pair.first = 0; +pair.second = 0; + + +pair.first=en_win_pair[0]; +pair.second=en_win_pair[1]; + + return pair; + +} + + + END_NAMESPACE_STIR diff --git a/src/include/stir/IO/InterfileHeader.h b/src/include/stir/IO/InterfileHeader.h index 2a0882b536..940fdad36e 100644 --- a/src/include/stir/IO/InterfileHeader.h +++ b/src/include/stir/IO/InterfileHeader.h @@ -123,6 +123,8 @@ class InterfileHeader : public MinimalInterfileHeader protected: virtual void read_matrix_info(); + virtual void read_num_energy_windows(); + virtual void en_window_pair_set(); void read_frames_info(); public : @@ -146,6 +148,7 @@ public : ByteOrder file_byte_order; int num_dimensions; + int num_energy_windows; std::vector matrix_labels; std::vector > matrix_size; std::vector pixel_sizes; @@ -156,12 +159,14 @@ public : //! //! \brief lower_en_window_thres //! \details Low energy window limit - float lower_en_window_thres; + std::vector lower_en_window_thres; //! //! \brief upper_en_window_thres //! \details High energy window limit - float upper_en_window_thres; + std::vector upper_en_window_thres; + + std::vector energy_window_pair; // end acquisition parameters protected: @@ -209,7 +214,7 @@ class InterfilePDFSHeader : public InterfileHeader std::vector segment_sequence; std::vector min_ring_difference; - std::vector max_ring_difference; + std::vector max_ring_difference; std::vector num_rings_per_segment; std::vector applied_corrections; diff --git a/src/include/stir/KeyParser.h b/src/include/stir/KeyParser.h index 9d4ee03316..a073fc41fd 100644 --- a/src/include/stir/KeyParser.h +++ b/src/include/stir/KeyParser.h @@ -85,6 +85,10 @@ class map_element { public : KeyArgument::type type; +#if 0 + trilian is_vectored; +#endif + void (KeyParser::*p_object_member)(); // pointer to a member function //TODO void (*p_object_member)(); void *p_object_variable; // pointer to a variable @@ -96,7 +100,7 @@ public : map_element(); map_element(KeyArgument::type t, void (KeyParser::*pom)(), - void* pov= 0, const ASCIIlist_type *list_of_valid_keywords = 0); + void* pov= 0, const ASCIIlist_type *list_of_valid_keywords = 0/*, trilian is_vectored = trilian ::unknwon*/); map_element(void (KeyParser::*pom)(), Object** pov, Parser *); diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index b15de36606..397d8f02d0 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -251,7 +251,7 @@ class ScatterSimulation : public RegisteredObject, * @{ */ - float detection_efficiency(const float energy) const; + float detection_efficiency(const float energy, int en_window = 0) const; //! maximum angle to consider above which detection after Compton scatter is considered too small @@ -276,7 +276,7 @@ class ScatterSimulation : public RegisteredObject, //! average detection efficiency of unscattered counts double detection_efficiency_no_scatter(const unsigned det_num_A, - const unsigned det_num_B) const; + const unsigned det_num_B, int en_window) const; // next needs to be mutable because find_in_detection_points_vector is const mutable std::vector > detection_points_vector; diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 08379e0a7c..61cd789b28 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -61,6 +61,25 @@ process_data() { // this is usefull in the scatter estimation process. this->output_proj_data_sptr->fill(0.f); + //show energy window information + + std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + +if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) +{ + std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + +} + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + std::cerr << "energy window lower level"<<"["<proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + } } @@ -136,6 +158,8 @@ process_data() return Succeeded::no; } + + std::cerr << "TOTAL SCATTER:= " << total_scatter << '\n'; return Succeeded::yes; } @@ -182,6 +206,9 @@ process_data_for_view_segment_num(const ViewSegmentNumbers& vs_num) viewgram[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(scatter_ratio); total_scatter += scatter_ratio; + + + } // end loop over bins if (this->output_proj_data_sptr->set_viewgram(viewgram) == Succeeded::no) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index d74f8ed061..c7583d04e4 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -97,7 +97,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy) const +detection_efficiency(const float energy,int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -107,8 +107,8 @@ detection_efficiency(const float energy) const // sigma_times_sqrt2= sqrt(2) * sigma // resolution proportional to FWHM const float efficiency = - 0.5f*( erf((this->template_exam_info_sptr->get_high_energy_thres()-energy)/sigma_times_sqrt2) - - erf((this->template_exam_info_sptr->get_low_energy_thres()-energy)/sigma_times_sqrt2 )); + 0.5f*( erf((this->template_exam_info_sptr->get_high_energy_thres(en_window)-energy)/sigma_times_sqrt2) + - erf((this->template_exam_info_sptr->get_low_energy_thres(en_window)-energy)/sigma_times_sqrt2 )); /* Maximum efficiency is 1.*/ return efficiency; } @@ -134,13 +134,13 @@ energy_lower_limit(const float low, const float approx, const float resolution_a double ScatterSimulation:: detection_efficiency_no_scatter(const unsigned det_num_A, - const unsigned det_num_B) const + const unsigned det_num_B, int en_window) const { // TODO: slightly dangerous to use a static here // it would give wrong results when the energy_thresholds are changed... static const float detector_efficiency_no_scatter = - detection_efficiency(511.F) > 0 - ? detection_efficiency(511.F) + detection_efficiency(511.F, en_window) > 0 + ? detection_efficiency(511.F, en_window) : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F); const CartesianCoordinate3D& detector_coord_A = @@ -163,7 +163,7 @@ detection_efficiency_no_scatter(const unsigned det_num_A, return 1./( 0.75/2./_PI * rAB_squared - /detector_efficiency_no_scatter/ + /pow(detector_efficiency_no_scatter,2.0)/ (cos_incident_angle_A* cos_incident_angle_B)); } diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 1ac0d150e6..12cd6874dc 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -51,7 +51,33 @@ SingleScatterSimulation:: const unsigned det_num_A, const unsigned det_num_B) { - static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(), + + + + + // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. + + int low = 0; + + // TODO: check that the selected windows don't overcome the max num windows + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + + { + + int first_window=this->template_exam_info_sptr->get_energy_window_pair().first-1; + int second_window=this->template_exam_info_sptr->get_energy_window_pair().second-1; + + if(this->template_exam_info_sptr->get_low_energy_thres(first_window) <= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) + + { + low = first_window; + } + + + } + + static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), 2.f, this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); @@ -74,10 +100,59 @@ SingleScatterSimulation:: const float new_energy = photon_energy_after_Compton_scatter_511keV(costheta); - const float detection_efficiency_scatter = - detection_efficiency(new_energy); - if (detection_efficiency_scatter==0) - return 0; + + + +// The detection efficiency varies with respect to the energy window. +//The code can now compute the scatter for a combination of two windows X and Y +//Default: one window -> The code will combine the window with itself + +std::vectordetection_efficiency_scattered; +std::vectordetection_efficiency_unscattered; + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + detection_efficiency_scattered.push_back(0); + detection_efficiency_unscattered.push_back(0); + + } + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); + detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); + + if (detection_efficiency_scattered[i]==0) + return 0; + if (detection_efficiency_unscattered[i]==0) + return 0; + } + + + //compute the probability of detection for two given energy windows X and Y + + int index0 = 0; + int index1 = 0; + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + //TODO: check if the values are insered correctly (i.e. index<=num_windows) + + /*if (this->template_exam_info_sptr->get_energy_window_pair().first!=-1 && + this->template_exam_info_sptr->get_energy_window_pair().second!=-1) + {*/ + index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; + index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; + + } + + //Set the probability of detection for one energy window (Default) + + float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; + float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; + + const float emiss_to_detA = cached_integral_over_activity_image_between_scattpoint_det @@ -107,6 +182,17 @@ SingleScatterSimulation:: const float scatter_point_mu= scatt_points_vector[scatter_point_num].mu_value; + const CartesianCoordinate3D + detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); + const CartesianCoordinate3D + detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); + const float cos_incident_angle_AS = static_cast( + cos_angle(scatter_point - detector_coord_A, + detA_to_ring_center)) ; + const float cos_incident_angle_BS = static_cast( + cos_angle(scatter_point - detector_coord_B, + detB_to_ring_center)) ; + #ifndef NDEBUG { // check if mu-value ok @@ -125,27 +211,19 @@ SingleScatterSimulation:: float scatter_ratio=0 ; - scatter_ratio= - (emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *detection_efficiency_scatter; - - const CartesianCoordinate3D - detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); - const CartesianCoordinate3D - detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); - const float cos_incident_angle_AS = static_cast( - cos_angle(scatter_point - detector_coord_A, - detA_to_ring_center)) ; - const float cos_incident_angle_BS = static_cast( - cos_angle(scatter_point - detector_coord_B, - detB_to_ring_center)) ; - - return scatter_ratio*cos_incident_angle_AS*cos_incident_angle_BS*dif_Compton_cross_section_value; + scatter_ratio= + (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value; + + + return scatter_ratio; } diff --git a/src/scatter_buildblock/single_scatter_estimate.cxx b/src/scatter_buildblock/single_scatter_estimate.cxx index c2beacfe2d..5319ebf58b 100644 --- a/src/scatter_buildblock/single_scatter_estimate.cxx +++ b/src/scatter_buildblock/single_scatter_estimate.cxx @@ -78,8 +78,27 @@ actual_scatter_estimate(double& scatter_ratio_singles, // is an approximation for the integral over the scatter point. // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code + + + // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window + //TODO: check that the selected windows don't overcome the max number of windows +// TODO: add error if there is one window + + int index = 0; + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + //search for the photopeak window (max window) + index = 0 ; + + // } +} + + + //find the highest window with a for loop + const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * + 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index) * scatter_volume/total_Compton_cross_section_511keV; scatter_ratio_singles *= common_factor; From 4ca9b77a81cfbdfa82684346d761c7a2421da03f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 4 Jun 2018 15:17:13 +0100 Subject: [PATCH 002/274] second_commitment --- src/IO/InterfileHeader.cxx | 52 +++++++++++++------ src/include/stir/ExamInfo.inl | 10 ++-- .../single_scatter_estimate.cxx | 26 ++++++---- src/scatter_utilities/simulate_scatter.cxx | 4 +- src/utilities/list_projdata_info.cxx | 1 + 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index c1a6f537d6..fb4c5eca17 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -250,7 +250,6 @@ InterfileHeader::InterfileHeader() bool InterfileHeader::post_processing() { - if(type_of_data_index<0) { warning("Interfile Warning: 'type_of_data' keyword required"); @@ -359,23 +358,39 @@ bool InterfileHeader::post_processing() //set the lower and the higher energy thresholds for all the energy windows available. Default: 1. - for (int i = 0; i < num_energy_windows; ++i) - { - if (upper_en_window_thres[i] > 0 && lower_en_window_thres[i] > 0 ) - { - exam_info_sptr->set_high_energy_thres(upper_en_window_thres[i],i); - exam_info_sptr->set_low_energy_thres(lower_en_window_thres[i],i); - } - } + //set the number of energy windows and pair + + exam_info_sptr->set_num_energy_windows(num_energy_windows); -//set the number of energy windows and pair + if (energy_window_pair.size() > 0) { + if (energy_window_pair.size() != 2) + error("should have two."); + if (energy_window_pair[0] < 0) + error("first window should be >= 0."); + if (energy_window_pair[1] < 0) + error("second window should be >= 0."); + if (energy_window_pair[0] > num_energy_windows) + error("The selected window %d exceeds the number of energy windows %d.\n",energy_window_pair[0],num_energy_windows); + if (energy_window_pair[1] > num_energy_windows) + error("The selected window %d exceeds the number of energy windows %d.\n",energy_window_pair[1],num_energy_windows); + exam_info_sptr->set_energy_window_pair(energy_window_pair,num_energy_windows); + } + + //set the high and low energy window threshold + + for (int i = 0; i < num_energy_windows; ++i) + { - exam_info_sptr->set_energy_window_pair(energy_window_pair,num_energy_windows); - exam_info_sptr->set_num_energy_windows(num_energy_windows); + if (upper_en_window_thres[i] >0 && lower_en_window_thres[i] >0) + { + exam_info_sptr->set_high_energy_thres(upper_en_window_thres[i],i); + exam_info_sptr->set_low_energy_thres(lower_en_window_thres[i],i); + } + } exam_info_sptr->time_frame_definitions = @@ -398,10 +413,13 @@ void InterfileHeader::read_matrix_info() void InterfileHeader::read_num_energy_windows() { + + set_variable(); - upper_en_window_thres.resize(num_energy_windows); - lower_en_window_thres.resize(num_energy_windows); + upper_en_window_thres.resize(num_energy_windows,-1.); + lower_en_window_thres.resize(num_energy_windows,-1.); + } @@ -412,6 +430,10 @@ void InterfileHeader::en_window_pair_set() energy_window_pair.resize(2); set_variable(); + /*std::cerr << "\nI'm here2\n"; + std::cerr << "\nenergywindow pair size = " << energy_window_pair.size() << "\n"; + for (int i=0; i val,int n_win) { - en_win_pair=val; - for (int i = 0 ; i <= 1 ; ++i) - { - if (en_win_pair[i] >= n_win) - error("The selected pair (%d) exceeds the number of energy windows (%d): it needs to be set to supported value",en_win_pair[i],n_win); - } + en_win_pair=val; } @@ -80,6 +77,7 @@ float ExamInfo::get_low_energy_thres(int en_window) const { return low_energy_thres[en_window]; + } //Get the high energy boundary for all the energy windows. en_window is set to 0 by default diff --git a/src/scatter_buildblock/single_scatter_estimate.cxx b/src/scatter_buildblock/single_scatter_estimate.cxx index 5319ebf58b..7fb1d0bb08 100644 --- a/src/scatter_buildblock/single_scatter_estimate.cxx +++ b/src/scatter_buildblock/single_scatter_estimate.cxx @@ -81,25 +81,29 @@ actual_scatter_estimate(double& scatter_ratio_singles, // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window - //TODO: check that the selected windows don't overcome the max number of windows -// TODO: add error if there is one window + //find the window that contains 511 keV - int index = 0; + int index = 0; //default for one energy window if (this->template_exam_info_sptr->get_num_energy_windows()>1) { - //search for the photopeak window (max window) - index = 0 ; + for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) + { + if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) - // } -} + { + + index = i; + } + } + } - //find the highest window with a for loop +//normalisation factor between trues and scattered counts - const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index) * - scatter_volume/total_Compton_cross_section_511keV; + const double common_factor = + 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index) * + scatter_volume/total_Compton_cross_section_511keV; scatter_ratio_singles *= common_factor; } diff --git a/src/scatter_utilities/simulate_scatter.cxx b/src/scatter_utilities/simulate_scatter.cxx index df9b772406..8455588143 100644 --- a/src/scatter_utilities/simulate_scatter.cxx +++ b/src/scatter_utilities/simulate_scatter.cxx @@ -81,14 +81,12 @@ int main(int argc, const char *argv[]) if (argc!=2) print_usage_and_exit(); - shared_ptr < ScatterSimulation > simulation_method_sptr; - KeyParser parser; parser.add_start_key("Scatter Simulation"); parser.add_stop_key("End Scatter Simulation"); - parser.add_parsing_key("Simulation method", &simulation_method_sptr); + parser.add_parsing_key("Simulation method", &simulation_method_sptr);; parser.parse(argv[1]); if(simulation_method_sptr->process_data() == stir::Succeeded::yes) diff --git a/src/utilities/list_projdata_info.cxx b/src/utilities/list_projdata_info.cxx index 305d57268d..0791bb174f 100644 --- a/src/utilities/list_projdata_info.cxx +++ b/src/utilities/list_projdata_info.cxx @@ -139,6 +139,7 @@ int main(int argc, char *argv[]) << exam_info.time_frame_definitions.get_duration(1) << ")\n"; } + } if (print_geom) std::cout << proj_data_sptr->get_proj_data_info_ptr()->parameter_info() << std::endl; From bf273ee46e429c06af10f13345de4ecc89ef4acc Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 4 Jun 2018 15:17:57 +0100 Subject: [PATCH 003/274] second_commit --- src/include/stir/IO/InterfileHeaderSiemens.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/stir/IO/InterfileHeaderSiemens.h b/src/include/stir/IO/InterfileHeaderSiemens.h index dfa690b413..1911225d1a 100644 --- a/src/include/stir/IO/InterfileHeaderSiemens.h +++ b/src/include/stir/IO/InterfileHeaderSiemens.h @@ -100,6 +100,7 @@ class InterfileImageHeader : public InterfileHeaderSiemens protected: virtual void read_matrix_info(); + virtual void read_energy_window_info(); //! Returns false if OK, true if not. virtual bool post_processing(); From 40de52ddb686d1da7c7e478c0f1307ebb6d710fe Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 7 Jun 2018 10:58:03 +0100 Subject: [PATCH 004/274] first_commit --- src/IO/InterfileHeader.cxx | 5 +--- src/IO/interfile.cxx | 10 +++++++- src/buildblock/ProjData.cxx | 5 +++- src/buildblock/ProjDataFromStream.cxx | 4 ++++ src/buildblock/interpolate_projdata.cxx | 24 +++++++++++++++---- src/include/stir/interpolate_projdata.h | 8 +++---- src/scatter_buildblock/ScatterEstimation.cxx | 22 +++++++++++++++-- src/scatter_buildblock/ScatterSimulation.cxx | 4 ++-- .../upsample_and_fit_scatter_estimate.cxx | 3 +++ src/scatter_utilities/estimate_scatter.cxx | 4 ++-- 10 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index fb4c5eca17..2097ce526e 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -430,10 +430,7 @@ void InterfileHeader::en_window_pair_set() energy_window_pair.resize(2); set_variable(); - /*std::cerr << "\nI'm here2\n"; - std::cerr << "\nenergywindow pair size = " << energy_window_pair.size() << "\n"; - for (int i=0; iget_num_energy_windows() > 1) + //output_header << "energy resolution :="<< pdfs.get_proj_data_info_ptr()->get_scanner_ptr()->get_energy_resolution()<< "\n"; + //output_header << "Reference energy (in keV) :="<< pdfs.get_proj_data_info_ptr()->get_scanner_ptr()->get_reference_energy()<< "\n"; + + // write time frame info // TODO this is according to the proposed interfile standard for PET. Interfile 3.3 is different { diff --git a/src/buildblock/ProjData.cxx b/src/buildblock/ProjData.cxx index 386a821b50..ebcfdb8e51 100644 --- a/src/buildblock/ProjData.cxx +++ b/src/buildblock/ProjData.cxx @@ -96,6 +96,8 @@ ProjData:: read_from_file(const string& filename, const std::ios::openmode openmode) { + + std::string actual_filename = filename; // parse filename to see if it's like filename,options { @@ -109,7 +111,6 @@ read_from_file(const string& filename, fstream * input = new fstream(actual_filename.c_str(), openmode | ios::binary); if (! *input) error("ProjData::read_from_file: error opening file %s", actual_filename.c_str()); - const FileSignature file_signature(actual_filename); const char * signature = file_signature.get_signature(); @@ -184,7 +185,9 @@ read_from_file(const string& filename, #ifndef NDEBUG warning("ProjData::read_from_file trying to read %s as Interfile", filename.c_str()); #endif + shared_ptr ptr(read_interfile_PDFS(filename, openmode)); + if (!is_null_ptr(ptr)) return ptr; } diff --git a/src/buildblock/ProjDataFromStream.cxx b/src/buildblock/ProjDataFromStream.cxx index ee270ab6d1..f20d5ab28e 100644 --- a/src/buildblock/ProjDataFromStream.cxx +++ b/src/buildblock/ProjDataFromStream.cxx @@ -698,6 +698,8 @@ ProjDataFromStream::get_offset_segment(const int segment_num) const SegmentBySinogram ProjDataFromStream::get_segment_by_sinogram(const int segment_num) const { + + if(is_null_ptr(sino_stream)) { error("ProjDataFromStream::get_segment_by_sinogram: stream ptr is 0\n"); @@ -728,6 +730,7 @@ ProjDataFromStream::get_segment_by_sinogram(const int segment_num) const succeeded = read_data(*sino_stream, segment, on_disk_data_type, scale, on_disk_byte_order); } } // end of critical section + if (succeeded == Succeeded::no) error("ProjDataFromStream: error reading data\n"); if(scale != 1) @@ -764,6 +767,7 @@ ProjDataFromStream::get_segment_by_view(const int segment_num) const #ifdef STIR_OPENMP #pragma omp critical(PROJDATAFROMSTREAMIO) #endif + { sino_stream->seekg(segment_offset, ios::beg); if (! *sino_stream) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 7a1fef3245..8222c7b32a 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -153,10 +153,12 @@ namespace detail_interpolate_projdata make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, const SegmentBySinogram& in_segment) { + SegmentBySinogram out_segment = non_interleaved_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); make_non_interleaved_segment(out_segment, in_segment); + return out_segment; } @@ -165,19 +167,24 @@ namespace detail_interpolate_projdata using namespace detail_interpolate_projdata; -Succeeded +Succeeded interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, const BSpline::BSplineType these_types, const bool remove_interleaving, const bool use_view_offset) { + BasicCoordinate<3, BSpline::BSplineType> these_types_3; + these_types_3[1]=these_types_3[2]=these_types_3[3]=these_types; + interpolate_projdata(proj_data_out,proj_data_in,these_types_3, remove_interleaving, use_view_offset); + + return Succeeded::yes; } -Succeeded +Succeeded interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, const BasicCoordinate<3, BSpline::BSplineType> & these_types, @@ -185,6 +192,8 @@ interpolate_projdata(ProjData& proj_data_out, const bool use_view_offset) { + + if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); @@ -210,8 +219,9 @@ interpolate_projdata(ProjData& proj_data_out, BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); + BasicCoordinate<3, double> offset, step ; - + // find relation between out_index and in_index such that they correspond to the same physical position // out_index * m_zoom + m_offset = in_index const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); @@ -253,7 +263,10 @@ interpolate_projdata(ProjData& proj_data_out, // initialise interpolator if (remove_interleaving) + { + + shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_in_info); @@ -261,6 +274,7 @@ interpolate_projdata(ProjData& proj_data_out, make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) @@ -294,11 +308,13 @@ interpolate_projdata(ProjData& proj_data_out, proj_data_interpolator.set_coef(extended); } - // now do interpolation + // now do interpolation + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; return Succeeded::yes; diff --git a/src/include/stir/interpolate_projdata.h b/src/include/stir/interpolate_projdata.h index 0355557bac..c74125dbc7 100644 --- a/src/include/stir/interpolate_projdata.h +++ b/src/include/stir/interpolate_projdata.h @@ -57,18 +57,18 @@ template class SegmentBySinogram; the input sinogram. */ //@{ -Succeeded +Succeeded interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, const BSpline::BSplineType spline_type, const bool remove_interleaving = false, - const bool use_view_offset = false); -Succeeded + const bool use_view_offset = false); +Succeeded interpolate_projdata(ProjData& proj_data_out, const ProjData& proj_data_in, const BasicCoordinate<3, BSpline::BSplineType> & spline_type, const bool remove_interleaving = false, - const bool use_view_offset = false); + const bool use_view_offset = false); //@} END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/ScatterEstimation.cxx b/src/scatter_buildblock/ScatterEstimation.cxx index f75db02894..478c57009c 100644 --- a/src/scatter_buildblock/ScatterEstimation.cxx +++ b/src/scatter_buildblock/ScatterEstimation.cxx @@ -150,10 +150,12 @@ initialise_keymap() &this->initial_activity_image_filename); // RECONSTRUCTION RELATED - this->parser.add_key("reconstruction parameter template file", - &this->recon_template_par_filename); this->parser.add_parsing_key("reconstruction method", &this->reconstruction_template_sptr); + + this->parser.add_key("reconstruction parameter template file", + &this->recon_template_par_filename); + // END RECONSTRUCTION RELATED this->parser.add_key("number of scatter iterations", @@ -227,6 +229,7 @@ post_processing() else { KeyParser local_parser; + local_parser.add_start_key("Reconstruction"); local_parser.add_stop_key("End Reconstruction"); local_parser.add_parsing_key("reconstruction method", &this->reconstruction_template_sptr); @@ -236,6 +239,8 @@ post_processing() %this->recon_template_par_filename); return true; } + //std::cerr << "print"<< local_parser.parameter_info()<< '\n'; + } info("ScatterEstimation: Loading attenuation image..."); @@ -571,6 +576,8 @@ set_up() return Succeeded::no; } + + AnalyticReconstruction* tmp_analytic = dynamic_cast(this->reconstruction_template_sptr.get()); IterativeReconstruction >* tmp_iterative = @@ -735,6 +742,7 @@ set_up_iterative(IterativeReconstruction > * iterat this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone(), this->atten_coeff_filename, std::ios::in | std::ios::out | std::ios::trunc)); + else atten_projdata_3d_sptr.reset(new ProjDataInMemory(this->input_projdata_sptr->get_exam_info_sptr(), this->input_projdata_sptr->get_proj_data_info_sptr()->create_shared_clone())); @@ -757,6 +765,8 @@ set_up_iterative(IterativeReconstruction > * iterat // Check if it is a BinNormFromProjData -- it should but you never know // Take the projdata + + shared_ptr atten_projdata_3d_sptr = dynamic_cast (this->multiplicative_binnorm_3d_sptr->get_second_norm().get())->get_norm_proj_data_sptr(); @@ -976,6 +986,7 @@ process_data() info("ScatterEstimation: Scatter simulation in progress..."); this->scatter_simulation_sptr->process_data(); + info("ScatterEstimation: Scatter simulation in progress..."); if(this->run_debug_mode) // Write unscaled scatter sinogram @@ -994,6 +1005,8 @@ process_data() local_min_scale_value = this->min_scale_value; } + + upsample_and_fit_scatter_estimate(*scaled_est_projdata_2d_sptr, *data_to_fit_projdata_2d_sptr, *unscaled_est_projdata_2d_sptr, *this->multiplicative_binnorm_2d_sptr->get_first_norm(), @@ -1001,6 +1014,7 @@ process_data() local_max_scale_value, this->half_filter_width, spline_type, true); + if(this->run_debug_mode) { std::stringstream convert; // stream used for the conversion @@ -1010,6 +1024,7 @@ process_data() dynamic_cast (scaled_est_projdata_2d_sptr.get())->write_to_file(tmp.get_string()); } + if (this->export_scatter_estimates_of_each_iteration || i_scat_iter == this->num_scatter_iterations -1 ) { @@ -1061,6 +1076,7 @@ process_data() this->multiplicative_binnorm_3d_sptr->apply(*temp_projdata_3d, start_time, end_time); } + this->back_projdata_2d_sptr->fill(*scaled_est_projdata_2d_sptr); add_proj_data(*back_projdata_2d_sptr, *this->add_projdata_2d_sptr); this->multiplicative_binnorm_2d_sptr->apply(*back_projdata_2d_sptr, start_time, end_time); @@ -1070,12 +1086,14 @@ process_data() reconstruct_analytic(i_scat_iter, this->current_activity_image_lowres_sptr); + // Reset to the additive factor // this->scaled_est_projdata_sptr->fill(*this->back_projdata_sptr); // scaled_est_projdata_2d_sptr->fill(0.0f); } + info("ScatterEstimation: Scatter Estimation finished !!!"); return Succeeded::yes; diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 61cd789b28..5acde9e035 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -208,7 +208,6 @@ process_data_for_view_segment_num(const ViewSegmentNumbers& vs_num) total_scatter += scatter_ratio; - } // end loop over bins if (this->output_proj_data_sptr->set_viewgram(viewgram) == Succeeded::no) @@ -306,7 +305,8 @@ post_processing() if ((zoom_xy!=1 || zoom_z != 1) && this->density_image_filename.size()>0) { - this->set_density_image_for_scatter_points_sptr(downsample_image(this->density_image_sptr)); + + this->set_density_image_for_scatter_points_sptr(downsample_image(this->density_image_sptr)); if(this->density_image_for_scatter_points_output_filename.size()>0) OutputFileFormat >::default_sptr()-> diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 9339ccc8ab..2ac495f164 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -63,11 +63,14 @@ upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), interpolated_direct_scatter_proj_data_info_sptr); + interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); + const TimeFrameDefinitions& time_frame_defs = emission_proj_data.get_exam_info_sptr()->time_frame_definitions; diff --git a/src/scatter_utilities/estimate_scatter.cxx b/src/scatter_utilities/estimate_scatter.cxx index 30aee0a817..cbc8db5332 100644 --- a/src/scatter_utilities/estimate_scatter.cxx +++ b/src/scatter_utilities/estimate_scatter.cxx @@ -54,7 +54,7 @@ static void print_usage_and_exit() "zoom xy := 0.3\n" "zoom z := 1.0\n" "input file := \n" - "recompute attenuation projdata := 0\n" + "recompute 5attenuation projdata := 0\n" "αttenuation projdata filename := \n" "attenuation image filename := \n" @@ -91,7 +91,7 @@ static void print_usage_and_exit() "; export 2d projdata := \n" "; ScatterSimulation Stuff \n" - "scatter simulation parameter file :=\n" + "scatter simulation parameters file :=\n" "; Override the values set in the scatter simulation parameteres file\n" "override initial activity image := \n" From bf88632e5454a7dbf094afcfebbdd9d6491ed9b5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 7 Jun 2018 16:04:23 +0100 Subject: [PATCH 005/274] gradient --- .../SingleScatterLikelihoodAndGradient.h | 102 ++++++ src/scatter_buildblock/CMakeLists.txt | 4 + src/scatter_buildblock/L_G_Simulation.cxx | 234 +++++++++++++ src/scatter_buildblock/L_G_estimate.cxx | 85 +++++ .../L_G_estimate_for_one_scatter_point.cxx | 309 ++++++++++++++++++ .../SingleScatterLikelihoodAndGradient.cxx | 46 +++ ...scatter_estimate_for_one_scatter_point.cxx | 45 ++- .../single_scatter_estimate.cxx | 41 +-- .../single_scatter_integrals.cxx | 109 +++++- src/swig/CMakeLists.txt | 2 +- src/swig/stir.i | 26 ++ 11 files changed, 958 insertions(+), 45 deletions(-) create mode 100644 src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h create mode 100644 src/scatter_buildblock/L_G_Simulation.cxx create mode 100644 src/scatter_buildblock/L_G_estimate.cxx create mode 100644 src/scatter_buildblock/L_G_estimate_for_one_scatter_point.cxx create mode 100644 src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h new file mode 100644 index 0000000000..b9a0ef188f --- /dev/null +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2016 University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +/*! + \file + \ingroup scatter + \brief Definition of class stir::SingleScatterLikelihoodAndGradient + + \author Ludovica Brusaferri +*/ + +#ifndef __stir_scatter_SingleScatterLikelihoodAndGradient_H__ +#define __stir_scatter_SingleScatterLikelihoodAndGradient_H__ + +#include "stir/Succeeded.h" +#include "stir/scatter/ScatterSimulation.h" +#include "stir/scatter/SingleScatterSimulation.h" +#include "stir/RegisteredParsingObject.h" + + +START_NAMESPACE_STIR + +class SingleScatterLikelihoodAndGradient : public + RegisteredParsingObject< + SingleScatterLikelihoodAndGradient, + SingleScatterSimulation, + SingleScatterSimulation > +{ +private: + typedef RegisteredParsingObject< + SingleScatterLikelihoodAndGradient, + SingleScatterSimulation, + SingleScatterSimulation > base_type; +public: + + //! Name which will be used when parsing a ScatterSimulation object + static const char * const registered_name; + + //! Default constructor + SingleScatterLikelihoodAndGradient(); + + //! Constructor with initialisation from parameter file + explicit + SingleScatterLikelihoodAndGradient(const std::string& parameter_filename); + + virtual ~SingleScatterLikelihoodAndGradient(); + + + + virtual double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image,const float scale_factor = 1, bool isgradient = true); + + protected: + + void + line_contribution(VoxelsOnCartesianGrid& gradient_image,const float scale, + const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord, + const float C); + + void + s_contribution(VoxelsOnCartesianGrid& gradient_image, + const CartesianCoordinate3D& scatter_point, + const float D); + float + L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, + const std::size_t scatter_point_num, + const unsigned det_num_A, + const unsigned det_num_B); + + virtual double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin); + + virtual void + actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, + double& scatter_ratio_singles, + const unsigned det_num_A, + const unsigned det_num_B ) = 0; + + + virtual double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float scale_factor, bool isgradient); + + virtual double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float scale_factor, bool isgradient); + + + +}; + +END_NAMESPACE_STIR + +#endif diff --git a/src/scatter_buildblock/CMakeLists.txt b/src/scatter_buildblock/CMakeLists.txt index 1c44eba864..f6e9e7560d 100644 --- a/src/scatter_buildblock/CMakeLists.txt +++ b/src/scatter_buildblock/CMakeLists.txt @@ -17,6 +17,10 @@ set(${dir_LIB_SOURCES} CreateTailMaskFromACFs ScatterSimulation SingleScatterSimulation + SingleScatterLikelihoodAndGradient + L_G_estimate_for_one_scatter_point + L_G_estimate + L_G_simulation ) #$(dir)_REGISTRY_SOURCES:= scatter_buildblock_registries diff --git a/src/scatter_buildblock/L_G_Simulation.cxx b/src/scatter_buildblock/L_G_Simulation.cxx new file mode 100644 index 0000000000..73083ef8eb --- /dev/null +++ b/src/scatter_buildblock/L_G_Simulation.cxx @@ -0,0 +1,234 @@ +/* + Copyright (C) 2004 - 2009 Hammersmith Imanet Ltd + Copyright (C) 2013 - 2016 University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details + */ +/*! + \file + \ingroup scatter + \brief Definition of class stir::ScatterEstimationByBin. + + \author Nikos Efthimiou + \author Kris Thielemans + */ +#include "stir/scatter/ScatterSimulation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/ViewSegmentNumbers.h" +#include "stir/Bin.h" + +#include "stir/Viewgram.h" +#include "stir/is_null_ptr.h" +#include "stir/IO/read_from_file.h" +#include "stir/IO/write_to_file.h" +#include "stir/info.h" +#include "stir/error.h" +#include +#include + +#include "stir/zoom.h" +#include "stir/SSRB.h" + +#include "stir/stir_math.h" +#include "stir/zoom.h" +#include "stir/NumericInfo.h" + +START_NAMESPACE_STIR + + + +double +SingleScatterLikelihoodAndGradient:: +L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float scale_factor, bool isgradient) +{ + // this is usefull in the scatter estimation process. + this->output_proj_data_sptr->fill(0.f); + //show energy window information + + std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + + if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) + { + std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + + } + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + std::cerr << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + float sum = 0 ; + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,scale_factor,isgradient); + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + + } + } + + if (detection_points_vector.size() != static_cast(total_detectors)) + { + warning("Expected num detectors: %d, but found %d\n", + total_detectors, detection_points_vector.size()); + return Succeeded::no; + } + + + std::cerr << "LIKELIHOOD:= " << sum << '\n'; + return Succeeded::yes; +} + +double +SingleScatterLikelihoodAndGradient:: +L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float scale_factor, bool isgradient) +{ + Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); + + double sum = L_G_for_viewgram(viewgram,v_est,gradient_image, scale_factor, isgradient); + + return sum; + +} +double +SingleScatterLikelihoodAndGradient:: +L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float scale_factor, bool isgradient) +{ + + const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); + + // First construct a vector of all bins that we'll process. + // The reason for making this list before the actual calculation is that we can then parallelise over all bins + // without having to think about double loops. + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } + // now compute scatter for all bins + + double sum =0; + + + VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); + +#ifdef STIR_OPENMP +#pragma omp parallel for reduction(+:total_scatter) schedule(dynamic) +#endif + + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { + //creates a template image to fill + tmp_gradient_image.fill(0); + + const Bin bin = all_bins[i]; + + //forward model + const double y = L_G_estimate(tmp_gradient_image,bin); + + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(scale_factor*y); + + + sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-0.000000000000000000001; + + + if (isgradient) + gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)-1); + + + } + + return sum; +} + + +END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/L_G_estimate.cxx b/src/scatter_buildblock/L_G_estimate.cxx new file mode 100644 index 0000000000..69b52a6151 --- /dev/null +++ b/src/scatter_buildblock/L_G_estimate.cxx @@ -0,0 +1,85 @@ + +// +// +/*Copyright (C) 2004- 2009, Hammersmith Imanet + Copyright (C) 2016, UCL + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details + */ +/*! + \file + \ingroup scatter + \brief Implementations of stir::ScatterEstimationByBin::scatter_estimate and stir::ScatterEstimationByBin::single_scatter_estimate + + \author Nikos Efthimiou + \author Charalampos Tsoumpas + \author Pablo Aguiar + \author Kris Thielemans + + */ +#include "stir/scatter/SingleScatterSimulation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/scatter/ScatterEstimation.h" + +using namespace std; +START_NAMESPACE_STIR + +double +SingleScatterLikelihoodAndGradient:: +L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin) +{ + double scatter_ratio_singles = 0; + unsigned det_num_B=0; + unsigned det_num_A=0; + + this->find_detectors(det_num_A, det_num_B,bin); + + this->actual_L_G_estimate(gradient_image_bin, scatter_ratio_singles, + det_num_A, + det_num_B); + + return scatter_ratio_singles; +} + +void +SingleScatterLikelihoodAndGradient:: +actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, + double& scatter_ratio_singles, + const unsigned det_num_A, + const unsigned det_num_B ) +{ + + + + scatter_ratio_singles = 0; + + for(std::size_t scatter_point_num =0; + scatter_point_num < this->scatt_points_vector.size(); + ++scatter_point_num) + { + + + + + scatter_ratio_singles += + L_G_for_one_scatter_point(gradient_image_bin, + scatter_point_num, + det_num_A, det_num_B); + + } + +} + + +END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/L_G_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/L_G_estimate_for_one_scatter_point.cxx new file mode 100644 index 0000000000..4107048ecb --- /dev/null +++ b/src/scatter_buildblock/L_G_estimate_for_one_scatter_point.cxx @@ -0,0 +1,309 @@ +// +// +/* + Copyright (C) 2004- 2009-11-03, Hammersmith Imanet + Copyright (C) 2011-07-01 - 2011, Kris Thielemans + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details + */ +/*! + \file + \ingroup scatter + \brief Implementation of stir::ScatterEstimationByBin::single_scatter_estimate_for_one_scatter_point + + \author Charalampos Tsoumpas + \author Pablo Aguiar + \author Kris Thielemans + + + */ +#include "stir/scatter/SingleScatterSimulation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/scatter/ScatterSimulation.h" +#ifndef NDEBUG +// currently necessary for assert below +#include "stir/VoxelsOnCartesianGrid.h" +#endif + +#include "stir/round.h" +#include +using namespace std; +START_NAMESPACE_STIR + +static const float total_Compton_cross_section_511keV = +ScatterSimulation:: +total_Compton_cross_section(511.F); + +float +SingleScatterLikelihoodAndGradient:: +L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, + const std::size_t scatter_point_num, + const unsigned det_num_A, + const unsigned det_num_B) +{ + + // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. + + int low = 0; + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + + { + + int first_window=this->template_exam_info_sptr->get_energy_window_pair().first-1; + int second_window=this->template_exam_info_sptr->get_energy_window_pair().second-1; + + if(this->template_exam_info_sptr->get_low_energy_thres(first_window) <= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) + + { + low = first_window; + } + + } + + static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), + 2.f, + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); + + //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); + + const CartesianCoordinate3D& scatter_point = + this->scatt_points_vector[scatter_point_num].coord; + const CartesianCoordinate3D& detector_coord_A = + this->detection_points_vector[det_num_A]; + const CartesianCoordinate3D& detector_coord_B = + this->detection_points_vector[det_num_B]; + // note: costheta is -cos_angle such that it is 1 for zero scatter angle + const float costheta = static_cast( + -cos_angle(detector_coord_A - scatter_point, + detector_coord_B - scatter_point)); + // note: costheta is identical for scatter to A or scatter to B + // Hence, the Compton_cross_section and energy are identical for both cases as well. + if(max_single_scatter_cos_angle>costheta) + return 0; + const float new_energy = + photon_energy_after_Compton_scatter_511keV(costheta); + + // The detection efficiency varies with respect to the energy window. + //The code can now compute the scatter for a combination of two windows X and Y + //Default: one window -> The code will combine the window with itself + + std::vectordetection_efficiency_scattered; + std::vectordetection_efficiency_unscattered; + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + detection_efficiency_scattered.push_back(0); + detection_efficiency_unscattered.push_back(0); + + } + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); + detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); + + if (detection_efficiency_scattered[i]==0) + return 0; + if (detection_efficiency_unscattered[i]==0) + return 0; + } + + //compute the probability of detection for two given energy windows X and Y + + int index0 = 0; + int index1 = 0; + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + + index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; + index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; + + } + + float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; + float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; + + const float emiss_to_detA = + cached_integral_over_activity_image_between_scattpoint_det + (static_cast (scatter_point_num), + det_num_A); + const float emiss_to_detB = + cached_integral_over_activity_image_between_scattpoint_det + (static_cast (scatter_point_num), + det_num_B); + if (emiss_to_detA==0 && emiss_to_detB==0) + return 0; + const float atten_to_detA = + cached_exp_integral_over_attenuation_image_between_scattpoint_det + (scatter_point_num, + det_num_A); + const float atten_to_detB = + cached_exp_integral_over_attenuation_image_between_scattpoint_det + (scatter_point_num, + det_num_B); + + const float dif_Compton_cross_section_value = + dif_Compton_cross_section(costheta, 511.F); + + const float rA_squared=static_cast(norm_squared(scatter_point-detector_coord_A)); + const float rB_squared=static_cast(norm_squared(scatter_point-detector_coord_B)); + + const float scatter_point_mu= + scatt_points_vector[scatter_point_num].mu_value; + + const CartesianCoordinate3D + detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); + const CartesianCoordinate3D + detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); + const float cos_incident_angle_AS = static_cast( + cos_angle(scatter_point - detector_coord_A, + detA_to_ring_center)); + const float cos_incident_angle_BS = static_cast( + cos_angle(scatter_point - detector_coord_B, + detB_to_ring_center)); + +#ifndef NDEBUG + { + // check if mu-value ok + // currently terribly shift needed as in sample_scatter_points (TODO) + const VoxelsOnCartesianGrid& image = + dynamic_cast&>(*this->density_image_for_scatter_points_sptr); + const CartesianCoordinate3D voxel_size = image.get_voxel_size(); + const float z_to_middle = + (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; + CartesianCoordinate3D shifted=scatter_point; + shifted.z() += z_to_middle; + assert(scatter_point_mu== + (*this->density_image_for_scatter_points_sptr)[this->density_image_for_scatter_points_sptr->get_indices_closest_to_physical_coordinates(shifted)]); + } +#endif + +#ifndef NEWSCALE + /* projectors work in pixel units, so convert attenuation data + from cm^-1 to pixel_units^-1 */ + const float rescale = + dynamic_cast &>(*density_image_sptr). + get_grid_spacing()[3]/10; +#else + const float rescale = + 0.1F; +#endif + + + //normalisation + + + // we will divide by the effiency of the detector pair for unscattered photons + // (computed with the same detection model as used in the scatter code) + // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. + + // there is a scatter_volume factor for every scatter point, as the sum over scatter points + // is an approximation for the integral over the scatter point. + + // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code + + + // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window + //find the window that contains 511 keV + + int index_photopeak = 0; //default for one energy window + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) + { + if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) + + { + + index_photopeak = i; + } + + } + } + + //normalisation factor between trues and scattered counts + + const double common_factor = + 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index_photopeak) * + scatter_volume/total_Compton_cross_section_511keV; + + + // Single ScatterForward Model + + float scatter_ratio=0; + + scatter_ratio= + (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + /*Single Scatter Forward model Jacobian: + * The derivative is given by three term, respectively in [A,S], [B,S] and [S] */ + + float contribution_AS = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* + total_Compton_cross_section_relative_to_511keV(new_energy)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + float contribution_BS = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* + (total_Compton_cross_section_relative_to_511keV(new_energy)) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + float contribution_S = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + //Fill gradient image along [A,S], [B,S] and in [S] + + line_contribution(gradient,rescale,scatter_point, + detector_coord_B,contribution_BS); + + line_contribution(gradient,rescale,scatter_point, + detector_coord_A,contribution_AS); + + s_contribution(gradient,scatter_point, + contribution_S); + + return scatter_ratio; + +} + +END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx new file mode 100644 index 0000000000..f2198ba7ea --- /dev/null +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -0,0 +1,46 @@ +/* + Copyright (C) 2016 University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" + +START_NAMESPACE_STIR + +const char * const +SingleScatterLikelihoodAndGradient::registered_name = + "Single Scatter Likelihood And Gradient"; + + +SingleScatterLikelihoodAndGradient:: +SingleScatterLikelihoodAndGradient() : + base_type() +{ + this->set_defaults(); +} + +SingleScatterLikelihoodAndGradient:: +SingleScatterLikelihoodAndGradient(const std::string& parameter_filename) +{ + this->initialise(parameter_filename); +} + +SingleScatterLikelihoodAndGradient:: +~SingleScatterLikelihoodAndGradient() +{} + + + +END_NAMESPACE_STIR + diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 12cd6874dc..d9d9bf6d11 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -130,7 +130,8 @@ std::vectordetection_efficiency_unscattered; } - //compute the probability of detection for two given energy windows X and Y + +//Set the probability of detection for one energy window (Default) int index0 = 0; int index1 = 0; @@ -147,8 +148,8 @@ std::vectordetection_efficiency_unscattered; } - //Set the probability of detection for one energy window (Default) + //compute the probability of detection for two given energy windows X and Y float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; @@ -209,6 +210,43 @@ std::vectordetection_efficiency_unscattered; } #endif + + // we will divide by the effiency of the detector pair for unscattered photons + // (computed with the same detection model as used in the scatter code) + // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. + + // there is a scatter_volume factor for every scatter point, as the sum over scatter points + // is an approximation for the integral over the scatter point. + + // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code + + + // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window + //find the window that contains 511 keV + + int index_photopeak = 0; //default for one energy window + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) + { + if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) + + { + + index_photopeak = i; + } + + } + } + + //normalisation factor between trues and scattered counts + + const double common_factor = + 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index_photopeak) * + scatter_volume/total_Compton_cross_section_511keV; + + float scatter_ratio=0 ; @@ -220,7 +258,8 @@ std::vectordetection_efficiency_unscattered; *scatter_point_mu *cos_incident_angle_AS *cos_incident_angle_BS - *dif_Compton_cross_section_value; + *dif_Compton_cross_section_value + *common_factor; return scatter_ratio; diff --git a/src/scatter_buildblock/single_scatter_estimate.cxx b/src/scatter_buildblock/single_scatter_estimate.cxx index 7fb1d0bb08..9b97a6997a 100644 --- a/src/scatter_buildblock/single_scatter_estimate.cxx +++ b/src/scatter_buildblock/single_scatter_estimate.cxx @@ -31,9 +31,7 @@ #include "stir/scatter/ScatterEstimation.h" using namespace std; START_NAMESPACE_STIR -static const float total_Compton_cross_section_511keV = -ScatterSimulation:: - total_Compton_cross_section(511.F); + double @@ -69,43 +67,6 @@ actual_scatter_estimate(double& scatter_ratio_singles, det_num_A, det_num_B); } - - // we will divide by the effiency of the detector pair for unscattered photons - // (computed with the same detection model as used in the scatter code) - // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. - - // there is a scatter_volume factor for every scatter point, as the sum over scatter points - // is an approximation for the integral over the scatter point. - - // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code - - - // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window - //find the window that contains 511 keV - - int index = 0; //default for one energy window - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) - { - if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) - - { - - index = i; - } - - } - } - -//normalisation factor between trues and scattered counts - - const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index) * - scatter_volume/total_Compton_cross_section_511keV; - - scatter_ratio_singles *= common_factor; } END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/single_scatter_integrals.cxx b/src/scatter_buildblock/single_scatter_integrals.cxx index 843f692068..d271634b2a 100644 --- a/src/scatter_buildblock/single_scatter_integrals.cxx +++ b/src/scatter_buildblock/single_scatter_integrals.cxx @@ -31,6 +31,7 @@ */ #include "stir/scatter/ScatterSimulation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" #include "stir/VoxelsOnCartesianGrid.h" #include "stir/recon_buildblock/ProjMatrixElemsForOneBin.h" #include "stir/recon_buildblock/RayTraceVoxelsOnCartesianGrid.h" @@ -141,6 +142,112 @@ integral_between_2_points(const DiscretisedDensity<3,float>& density, } } return sum; -} +} + + +void +SingleScatterLikelihoodAndGradient:: +line_contribution(VoxelsOnCartesianGrid& gradient_image,const float rescale, + const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord, + const float C) +{ + + + const DiscretisedDensity<3,float>& density=*density_image_sptr; + const VoxelsOnCartesianGrid& image = + dynamic_cast& > + (density); + + const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); + + CartesianCoordinate3D origin = + image.get_origin(); + const float z_to_middle = + (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; + origin.z() -= z_to_middle; + /* TODO replace with image.get_index_coordinates_for_physical_coordinates */ + ProjMatrixElemsForOneBin lor; + RayTraceVoxelsOnCartesianGrid(lor, + (scatter_point-origin)/voxel_size, // should be in voxel units + (detector_coord-origin)/voxel_size, // should be in voxel units + voxel_size, //should be in mm +#ifdef NEWSCALE + 1.F // normalise to mm +#else + 1/voxel_size.x() // normalise to some kind of 'pixel units' +#endif + ); + lor.sort(); + + + //VoxelsOnCartesianGrid gradient_image(image); + //gradient_image.fill(0.F); + { + ProjMatrixElemsForOneBin::iterator element_ptr =lor.begin() ; + bool we_have_been_within_the_image = false; + while (element_ptr != lor.end()) + { + const BasicCoordinate<3,int> coords = element_ptr->get_coords(); + if (coords[1] >= image.get_min_index() && + coords[1] <= image.get_max_index() && + coords[2] >= image[coords[1]].get_min_index() && + coords[2] <= image[coords[1]].get_max_index() && + coords[3] >= image[coords[1]][coords[2]].get_min_index() && + coords[3] <= image[coords[1]][coords[2]].get_max_index()) + { + we_have_been_within_the_image = true; + //gradient_image[coords] += -C*element_ptr->get_value() + gradient_image[coords] += -C*rescale*element_ptr->get_value(); + } + else if (we_have_been_within_the_image) + { + // we jump out of the loop as we are now at the other side of + // the image + // break; + } + ++element_ptr; + } + } + +} + + + +void +SingleScatterLikelihoodAndGradient:: +s_contribution(VoxelsOnCartesianGrid& gradient_image, +const CartesianCoordinate3D& scatter_point, + const float D) + +{ + +const DiscretisedDensity<3,float>& density=*density_image_sptr; +const VoxelsOnCartesianGrid& image = + dynamic_cast& > + (density); + +const CartesianCoordinate3D voxel_size = image.get_grid_spacing(); + +CartesianCoordinate3D origin = + image.get_origin(); + +const float z_to_middle = + (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; + origin.z() -= z_to_middle; + +CartesianCoordinate3D coord = + (scatter_point-origin)/voxel_size; // voxel units + + +const BasicCoordinate<3,int> coords=round(coord); + + +gradient_image[coords] += D; + + + +} + END_NAMESPACE_STIR diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt index 09bdafd986..95ac694476 100644 --- a/src/swig/CMakeLists.txt +++ b/src/swig/CMakeLists.txt @@ -136,4 +136,4 @@ if (BUILD_SWIG_MATLAB) file(GLOB SwigMatlabFiles "${CMAKE_CURRENT_BINARY_DIR}/Swig*.m") INSTALL(FILES ${SwigMatlabFiles} DESTINATION ${MATLAB_DEST}) -endif (BUILD_SWIG_MATLAB) +endif (BUILD_SWIG_MATLAB) \ No newline at end of file diff --git a/src/swig/stir.i b/src/swig/stir.i index a090d55eb8..3e39e23649 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -93,6 +93,9 @@ #include #include #include + +#include "stir/scatter/ScatterSimulation.h" +#include "stir/scatter/SingleScatterSimulation.h" // TODO need this (bug in swig) // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace @@ -1599,3 +1602,26 @@ namespace stir { stir::RegisteredParsingObject; %include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" + + +//scatter +%shared_ptr(stir::ScatterSimulation); +%shared_ptr(stir::RegisteredParsingObject< + stir::SingleScatterSimulation, + stir::ScatterSimulation, + stir::ScatterSimulation + >); +%shared_ptr(stir::SingleScatterSimulation); + + + +%include "stir/scatter/ScatterSimulation.h" + + +%template (internalRPSingleScatterSimulation) stir::RegisteredParsingObject< +stir::SingleScatterSimulation, +stir::ScatterSimulation, +stir::ScatterSimulation +>; + +%include "stir/scatter/SingleScatterSimulation.h" From 50398fbe212dd4b06df292a39b5f21393c59c446 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 7 Jun 2018 16:08:19 +0100 Subject: [PATCH 006/274] gradient2 --- src/scatter_buildblock/CMakeLists.txt | 6 +++--- .../{L_G_Simulation.cxx => LikelihoodAndGradient.cxx} | 0 .../{L_G_estimate.cxx => LikelihoodAndGradientEstimate.cxx} | 0 ... => LikelihoodAndGradientEstimateForOneScatterPoint.cxx} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/scatter_buildblock/{L_G_Simulation.cxx => LikelihoodAndGradient.cxx} (100%) rename src/scatter_buildblock/{L_G_estimate.cxx => LikelihoodAndGradientEstimate.cxx} (100%) rename src/scatter_buildblock/{L_G_estimate_for_one_scatter_point.cxx => LikelihoodAndGradientEstimateForOneScatterPoint.cxx} (100%) diff --git a/src/scatter_buildblock/CMakeLists.txt b/src/scatter_buildblock/CMakeLists.txt index f6e9e7560d..bdc2692efe 100644 --- a/src/scatter_buildblock/CMakeLists.txt +++ b/src/scatter_buildblock/CMakeLists.txt @@ -18,9 +18,9 @@ set(${dir_LIB_SOURCES} ScatterSimulation SingleScatterSimulation SingleScatterLikelihoodAndGradient - L_G_estimate_for_one_scatter_point - L_G_estimate - L_G_simulation + LikelihoodAndGradientEstimateForOneScatterPoint + LikelihoodAndGradientEstimate + LikelihoodAndGradient ) #$(dir)_REGISTRY_SOURCES:= scatter_buildblock_registries diff --git a/src/scatter_buildblock/L_G_Simulation.cxx b/src/scatter_buildblock/LikelihoodAndGradient.cxx similarity index 100% rename from src/scatter_buildblock/L_G_Simulation.cxx rename to src/scatter_buildblock/LikelihoodAndGradient.cxx diff --git a/src/scatter_buildblock/L_G_estimate.cxx b/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx similarity index 100% rename from src/scatter_buildblock/L_G_estimate.cxx rename to src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx diff --git a/src/scatter_buildblock/L_G_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx similarity index 100% rename from src/scatter_buildblock/L_G_estimate_for_one_scatter_point.cxx rename to src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx From bbd0c0f7ef8fe94dd34d36341355783c718fd9a9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 7 Jun 2018 17:08:10 +0100 Subject: [PATCH 007/274] changes_swig --- src/swig/CMakeLists.txt | 27 +++++++-------------------- src/swig/stir.i | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt index 95ac694476..bfbb50bee3 100644 --- a/src/swig/CMakeLists.txt +++ b/src/swig/CMakeLists.txt @@ -20,7 +20,7 @@ set(dir swig) if(BUILD_SWIG_PYTHON OR BUILD_SWIG_OCTAVE OR BUILD_SWIG_MATLAB) - FIND_PACKAGE(SWIG 3.0 REQUIRED) + FIND_PACKAGE(SWIG REQUIRED) INCLUDE("${SWIG_USE_FILE}") SET(CMAKE_SWIG_FLAGS -DSTART_NAMESPACE_STIR=\"namespace stir {\" -DEND_NAMESPACE_STIR=\"}\") @@ -32,10 +32,9 @@ endif() if(BUILD_SWIG_PYTHON) - # find Python interpreter. Needed for tests, and best to enforce consistency anyway. - find_package(PythonInterp) # find libraries and include files # TODO would be better to use target_include_directories + FIND_PACKAGE(PythonLibs REQUIRED) INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) FIND_PACKAGE(Numpy REQUIRED) @@ -44,11 +43,7 @@ if(BUILD_SWIG_PYTHON) # TODO -builtin option only appropriate for python # while the next statement sets it for all modules called stir SET(SWIG_MODULE_stir_EXTRA_FLAGS -builtin) - if (CMAKE_VERSION VERSION_LESS "3.8") - SWIG_ADD_MODULE(stir python stir.i ${STIR_REGISTRIES}) - else() - SWIG_ADD_LIBRARY(stir LANGUAGE python TYPE MODULE SOURCES stir.i ${STIR_REGISTRIES}) - endif() + SWIG_ADD_MODULE(stir python stir.i ${STIR_REGISTRIES}) SWIG_LINK_LIBRARIES(stir ${STIR_LIBRARIES} ${PYTHON_LIBRARIES}) SET_TARGET_PROPERTIES(${SWIG_MODULE_stir_REAL_NAME} PROPERTIES LINK_FLAGS "${OpenMP_EXE_LINKER_FLAGS}") @@ -91,11 +86,7 @@ if (BUILD_SWIG_OCTAVE) SET(OCTAVE_PREFIX "") SET(SWIG_MODULE_stiroct_EXTRA_FLAGS -module stiroct) - if (CMAKE_VERSION VERSION_LESS "3.8") - SWIG_ADD_MODULE(stiroct octave stir.i ${STIR_REGISTRIES}) - else() - SWIG_ADD_LIBRARY(stiroct LANGUAGE octave TYPE MODULE SOURCES stir.i ${STIR_REGISTRIES}) - endif() + SWIG_ADD_MODULE(stiroct octave stir.i ${STIR_REGISTRIES}) SET_TARGET_PROPERTIES(${SWIG_MODULE_stiroct_REAL_NAME} PROPERTIES SUFFIX ${OCTAVE_SUFFIX} PREFIX "${OCTAVE_PREFIX}") SWIG_LINK_LIBRARIES(stiroct ${STIR_LIBRARIES} ${OCTAVE_LIBRARIES}) @@ -113,12 +104,8 @@ endif (BUILD_SWIG_OCTAVE) if (BUILD_SWIG_MATLAB) set(module_name stir) - SET(SWIG_MODULE_stirMATLAB_EXTRA_FLAGS -module ${module_name} ) - if (CMAKE_VERSION VERSION_LESS "3.8") - SWIG_ADD_MODULE(stirMATLAB matlab stir.i ${STIR_REGISTRIES}) - else() - SWIG_ADD_LIBRARY(stirMATLAB LANGUAGE matlab TYPE MODULE SOURCES stir.i ${STIR_REGISTRIES}) - endif() + SET(SWIG_MODULE_stirMATLAB_EXTRA_FLAGS -module ${module_name}) + SWIG_ADD_MODULE(stirMATLAB matlab stir.i ${STIR_REGISTRIES}) SET_TARGET_PROPERTIES(${SWIG_MODULE_stirMATLAB_REAL_NAME} PROPERTIES SUFFIX "_wrap.${MATLAB_MEX_EXT}" PREFIX "${MATLAB_PREFIX}" LINK_FLAGS "${MATLAB_CXXLINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}" @@ -136,4 +123,4 @@ if (BUILD_SWIG_MATLAB) file(GLOB SwigMatlabFiles "${CMAKE_CURRENT_BINARY_DIR}/Swig*.m") INSTALL(FILES ${SwigMatlabFiles} DESTINATION ${MATLAB_DEST}) -endif (BUILD_SWIG_MATLAB) \ No newline at end of file +endif (BUILD_SWIG_MATLAB) diff --git a/src/swig/stir.i b/src/swig/stir.i index 3e39e23649..60e1a867a3 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -96,6 +96,7 @@ #include "stir/scatter/ScatterSimulation.h" #include "stir/scatter/SingleScatterSimulation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" // TODO need this (bug in swig) // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace @@ -1606,6 +1607,7 @@ namespace stir { //scatter %shared_ptr(stir::ScatterSimulation); + %shared_ptr(stir::RegisteredParsingObject< stir::SingleScatterSimulation, stir::ScatterSimulation, @@ -1614,6 +1616,13 @@ namespace stir { %shared_ptr(stir::SingleScatterSimulation); +%shared_ptr(stir::RegisteredParsingObject< + stir::SingleScatterLikelihoodAndGradient, + stir::SingleScatterSimulation, + stir::SingleScatterSimulation + >); +%shared_ptr(stir::SingleScatterSimulation); +%shared_ptr(stir::SingleScatterLikelihoodAndGradient); %include "stir/scatter/ScatterSimulation.h" @@ -1624,4 +1633,13 @@ stir::ScatterSimulation, stir::ScatterSimulation >; + +%template (internalRPSingleScatterSimulation) stir::RegisteredParsingObject< +stir::SingleScatterLikelihoodAndGradient, +stir::SingleScatterSimulation, +stir::SingleScatterSimulation +>; + + %include "stir/scatter/SingleScatterSimulation.h" +%include "stir/scatter/SingleScatterLikelihoodAndGradient.h" From 7e5ee98915fc0e2f0f2e6b37498be4f2899b3b6d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 8 Jun 2018 11:41:07 +0100 Subject: [PATCH 008/274] gradient_code --- src/include/stir/scatter/ScatterSimulation.h | 4 +- .../SingleScatterLikelihoodAndGradient.h | 12 +- .../LikelihoodAndGradient.cxx | 16 +- .../LikelihoodAndGradientEstimate.cxx | 8 +- ...dAndGradientEstimateForOneScatterPoint.cxx | 6 +- src/swig/CMakeLists.txt | 27 +- src/swig/Makefile | 2 +- src/swig/pyfragments.swg | 296 +-- src/swig/stir.i | 2102 +++++++++-------- src/swig/stirextra.py | 18 +- 10 files changed, 1255 insertions(+), 1236 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 397d8f02d0..5e9b287083 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -157,8 +157,8 @@ class ScatterSimulation : public RegisteredObject, Currently always uses Interfile output. \warning If the specified file already exists it will be erased. */ - void set_proj_data_from_file(const std::string& filename, - shared_ptr& _this_projdata); + //void set_proj_data_from_file(const std::string& filename, + // shared_ptr& _this_projdata); void set_density_image_sptr(const shared_ptr >&); diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index b9a0ef188f..4eb74a2103 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -37,13 +37,13 @@ class SingleScatterLikelihoodAndGradient : public RegisteredParsingObject< SingleScatterLikelihoodAndGradient, SingleScatterSimulation, - SingleScatterSimulation > + SingleScatterSimulation> { private: typedef RegisteredParsingObject< SingleScatterLikelihoodAndGradient, SingleScatterSimulation, - SingleScatterSimulation > base_type; + SingleScatterSimulation> base_type; public: //! Name which will be used when parsing a ScatterSimulation object @@ -60,7 +60,7 @@ class SingleScatterLikelihoodAndGradient : public - virtual double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image,const float scale_factor = 1, bool isgradient = true); + virtual double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float scale , bool isgradient = true); protected: @@ -78,15 +78,15 @@ class SingleScatterLikelihoodAndGradient : public L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, const std::size_t scatter_point_num, const unsigned det_num_A, - const unsigned det_num_B); + const unsigned det_num_B, bool isgradient); - virtual double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin); + virtual double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool isgradient); virtual void actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, double& scatter_ratio_singles, const unsigned det_num_A, - const unsigned det_num_B ) = 0; + const unsigned det_num_B, bool isgradient); virtual double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float scale_factor, bool isgradient); diff --git a/src/scatter_buildblock/LikelihoodAndGradient.cxx b/src/scatter_buildblock/LikelihoodAndGradient.cxx index 73083ef8eb..b7049a2316 100644 --- a/src/scatter_buildblock/LikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/LikelihoodAndGradient.cxx @@ -50,12 +50,12 @@ START_NAMESPACE_STIR double SingleScatterLikelihoodAndGradient:: -L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float scale_factor, bool isgradient) +L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale, bool isgradient) { // this is usefull in the scatter estimation process. this->output_proj_data_sptr->fill(0.f); //show energy window information - + std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && @@ -133,7 +133,7 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const ++vs_num.view_num()) { info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,scale_factor,isgradient); + sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,isgradient); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); @@ -158,19 +158,19 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const double SingleScatterLikelihoodAndGradient:: -L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float scale_factor, bool isgradient) +L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool isgradient) { Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); - double sum = L_G_for_viewgram(viewgram,v_est,gradient_image, scale_factor, isgradient); + double sum = L_G_for_viewgram(viewgram,v_est,gradient_image, rescale, isgradient); return sum; } double SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float scale_factor, bool isgradient) +L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool isgradient) { const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); @@ -213,9 +213,9 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes const Bin bin = all_bins[i]; //forward model - const double y = L_G_estimate(tmp_gradient_image,bin); + const double y = L_G_estimate(tmp_gradient_image,bin,isgradient); - v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(scale_factor*y); + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-0.000000000000000000001; diff --git a/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx b/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx index 69b52a6151..6914fdeadd 100644 --- a/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx +++ b/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx @@ -37,7 +37,7 @@ START_NAMESPACE_STIR double SingleScatterLikelihoodAndGradient:: -L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin) +L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool isgradient) { double scatter_ratio_singles = 0; unsigned det_num_B=0; @@ -47,7 +47,7 @@ L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin) this->actual_L_G_estimate(gradient_image_bin, scatter_ratio_singles, det_num_A, - det_num_B); + det_num_B, isgradient); return scatter_ratio_singles; } @@ -57,7 +57,7 @@ SingleScatterLikelihoodAndGradient:: actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, double& scatter_ratio_singles, const unsigned det_num_A, - const unsigned det_num_B ) + const unsigned det_num_B, bool isgradient) { @@ -75,7 +75,7 @@ actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, scatter_ratio_singles += L_G_for_one_scatter_point(gradient_image_bin, scatter_point_num, - det_num_A, det_num_B); + det_num_A, det_num_B, isgradient); } diff --git a/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx b/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx index 4107048ecb..85a2638ef2 100644 --- a/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx +++ b/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx @@ -50,7 +50,7 @@ SingleScatterLikelihoodAndGradient:: L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, const std::size_t scatter_point_num, const unsigned det_num_A, - const unsigned det_num_B) + const unsigned det_num_B, bool isgradient) { // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. @@ -293,6 +293,9 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, //Fill gradient image along [A,S], [B,S] and in [S] + if (isgradient) + + { line_contribution(gradient,rescale,scatter_point, detector_coord_B,contribution_BS); @@ -302,6 +305,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, s_contribution(gradient,scatter_point, contribution_S); + } return scatter_ratio; } diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt index bfbb50bee3..95ac694476 100644 --- a/src/swig/CMakeLists.txt +++ b/src/swig/CMakeLists.txt @@ -20,7 +20,7 @@ set(dir swig) if(BUILD_SWIG_PYTHON OR BUILD_SWIG_OCTAVE OR BUILD_SWIG_MATLAB) - FIND_PACKAGE(SWIG REQUIRED) + FIND_PACKAGE(SWIG 3.0 REQUIRED) INCLUDE("${SWIG_USE_FILE}") SET(CMAKE_SWIG_FLAGS -DSTART_NAMESPACE_STIR=\"namespace stir {\" -DEND_NAMESPACE_STIR=\"}\") @@ -32,9 +32,10 @@ endif() if(BUILD_SWIG_PYTHON) + # find Python interpreter. Needed for tests, and best to enforce consistency anyway. + find_package(PythonInterp) # find libraries and include files # TODO would be better to use target_include_directories - FIND_PACKAGE(PythonLibs REQUIRED) INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) FIND_PACKAGE(Numpy REQUIRED) @@ -43,7 +44,11 @@ if(BUILD_SWIG_PYTHON) # TODO -builtin option only appropriate for python # while the next statement sets it for all modules called stir SET(SWIG_MODULE_stir_EXTRA_FLAGS -builtin) - SWIG_ADD_MODULE(stir python stir.i ${STIR_REGISTRIES}) + if (CMAKE_VERSION VERSION_LESS "3.8") + SWIG_ADD_MODULE(stir python stir.i ${STIR_REGISTRIES}) + else() + SWIG_ADD_LIBRARY(stir LANGUAGE python TYPE MODULE SOURCES stir.i ${STIR_REGISTRIES}) + endif() SWIG_LINK_LIBRARIES(stir ${STIR_LIBRARIES} ${PYTHON_LIBRARIES}) SET_TARGET_PROPERTIES(${SWIG_MODULE_stir_REAL_NAME} PROPERTIES LINK_FLAGS "${OpenMP_EXE_LINKER_FLAGS}") @@ -86,7 +91,11 @@ if (BUILD_SWIG_OCTAVE) SET(OCTAVE_PREFIX "") SET(SWIG_MODULE_stiroct_EXTRA_FLAGS -module stiroct) - SWIG_ADD_MODULE(stiroct octave stir.i ${STIR_REGISTRIES}) + if (CMAKE_VERSION VERSION_LESS "3.8") + SWIG_ADD_MODULE(stiroct octave stir.i ${STIR_REGISTRIES}) + else() + SWIG_ADD_LIBRARY(stiroct LANGUAGE octave TYPE MODULE SOURCES stir.i ${STIR_REGISTRIES}) + endif() SET_TARGET_PROPERTIES(${SWIG_MODULE_stiroct_REAL_NAME} PROPERTIES SUFFIX ${OCTAVE_SUFFIX} PREFIX "${OCTAVE_PREFIX}") SWIG_LINK_LIBRARIES(stiroct ${STIR_LIBRARIES} ${OCTAVE_LIBRARIES}) @@ -104,8 +113,12 @@ endif (BUILD_SWIG_OCTAVE) if (BUILD_SWIG_MATLAB) set(module_name stir) - SET(SWIG_MODULE_stirMATLAB_EXTRA_FLAGS -module ${module_name}) - SWIG_ADD_MODULE(stirMATLAB matlab stir.i ${STIR_REGISTRIES}) + SET(SWIG_MODULE_stirMATLAB_EXTRA_FLAGS -module ${module_name} ) + if (CMAKE_VERSION VERSION_LESS "3.8") + SWIG_ADD_MODULE(stirMATLAB matlab stir.i ${STIR_REGISTRIES}) + else() + SWIG_ADD_LIBRARY(stirMATLAB LANGUAGE matlab TYPE MODULE SOURCES stir.i ${STIR_REGISTRIES}) + endif() SET_TARGET_PROPERTIES(${SWIG_MODULE_stirMATLAB_REAL_NAME} PROPERTIES SUFFIX "_wrap.${MATLAB_MEX_EXT}" PREFIX "${MATLAB_PREFIX}" LINK_FLAGS "${MATLAB_CXXLINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}" @@ -123,4 +136,4 @@ if (BUILD_SWIG_MATLAB) file(GLOB SwigMatlabFiles "${CMAKE_CURRENT_BINARY_DIR}/Swig*.m") INSTALL(FILES ${SwigMatlabFiles} DESTINATION ${MATLAB_DEST}) -endif (BUILD_SWIG_MATLAB) +endif (BUILD_SWIG_MATLAB) \ No newline at end of file diff --git a/src/swig/Makefile b/src/swig/Makefile index 2b54b1bdd6..2797d94206 100644 --- a/src/swig/Makefile +++ b/src/swig/Makefile @@ -60,4 +60,4 @@ _stir.so: stir_PYTHONwrap.o $(LIBS) Makefile stir.oct: stir_OCTAVEwrap.cpp $(LIBS) Makefile - CXXFLAGS=-g mkoctfile -v -I../include/ -g -DSWIG -o $@ $< $(LIBSa) + CXXFLAGS=-g mkoctfile -v -I../include/ -g -DSWIG -o $@ $< $(LIBSa) \ No newline at end of file diff --git a/src/swig/pyfragments.swg b/src/swig/pyfragments.swg index 33e78385fa..e933497bb6 100644 --- a/src/swig/pyfragments.swg +++ b/src/swig/pyfragments.swg @@ -16,53 +16,53 @@ */ %fragment(SWIG_AsVal_frag(long), "header", - fragment="SWIG_CanCastAsInteger", + fragment="SWIG_CanCastAsInteger", fragment="NumPy_Backward_Compatibility") { - SWIGINTERN int - SWIG_AsVal_dec(long)(PyObject * obj, long * val) - { - if (PyInt_Check(obj)) { - if (val) *val = PyInt_AsLong(obj); - return SWIG_OK; - } else if (PyLong_Check(obj)) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - } - } -%#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - long v = PyInt_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - double d; - int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d)); - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { - if (val) *val = (long)(d); - return res; - } - } - } -%#endif - if (PyArray_IsScalar(obj,Integer)) + SWIGINTERN int + SWIG_AsVal_dec(long)(PyObject * obj, long * val) { - PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_LONG); - PyArray_CastScalarToCtype(obj, (void*)val, descr); - Py_DECREF(descr); - return SWIG_AddCast(SWIG_OK); + if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } + %#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + long v = PyInt_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } + %#endif + if (PyArray_IsScalar(obj,Integer)) + { + PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_LONG); + PyArray_CastScalarToCtype(obj, (void*)val, descr); + Py_DECREF(descr); + return SWIG_AddCast(SWIG_OK); + } + return SWIG_TypeError; } - return SWIG_TypeError; - } } @@ -72,119 +72,119 @@ */ %fragment(SWIG_AsVal_frag(unsigned long),"header", - fragment="SWIG_CanCastAsInteger", + fragment="SWIG_CanCastAsInteger", fragment="NumPy_Backward_Compatibility") { - SWIGINTERN int - SWIG_AsVal_dec(unsigned long)(PyObject *obj, unsigned long *val) - { - if (PyInt_Check(obj)) { - long v = PyInt_AsLong(obj); - if (v >= 0) { - if (val) *val = v; - return SWIG_OK; - } else { - return SWIG_OverflowError; - } - } else if (PyLong_Check(obj)) { - unsigned long v = PyLong_AsUnsignedLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - } - } -%#ifdef SWIG_PYTHON_CAST_MODE + SWIGINTERN int + SWIG_AsVal_dec(unsigned long)(PyObject *obj, unsigned long *val) { - int dispatch = 0; - unsigned long v = PyLong_AsUnsignedLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - double d; - int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d)); - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { - if (val) *val = (unsigned long)(d); - return res; - } - } + if (PyInt_Check(obj)) { + long v = PyInt_AsLong(obj); + if (v >= 0) { + if (val) *val = v; + return SWIG_OK; + } else { + return SWIG_OverflowError; + } + } else if (PyLong_Check(obj)) { + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } + %#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { + if (val) *val = (unsigned long)(d); + return res; + } + } + } + %#endif + if (PyArray_IsScalar(obj,Integer)) + { + PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_ULONG); + PyArray_CastScalarToCtype(obj, (void*)val, descr); + Py_DECREF(descr); + return SWIG_AddCast(SWIG_OK); + } + return SWIG_TypeError; } -%#endif - if (PyArray_IsScalar(obj,Integer)) - { - PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_ULONG); - PyArray_CastScalarToCtype(obj, (void*)val, descr); - Py_DECREF(descr); - return SWIG_AddCast(SWIG_OK); - } - return SWIG_TypeError; - } } %fragment(SWIG_AsVal_frag(double),"header", - fragment="NumPy_Backward_Compatibility") -{ -SWIGINTERN int -SWIG_AsVal_dec(double)(PyObject *obj, double *val) + fragment="NumPy_Backward_Compatibility") { - int res = SWIG_TypeError; - if (PyFloat_Check(obj)) { - if (val) *val = PyFloat_AsDouble(obj); - return SWIG_OK; - } else if (PyInt_Check(obj)) { - if (val) *val = PyInt_AsLong(obj); - return SWIG_OK; - } else if (PyLong_Check(obj)) { - double v = PyLong_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - } - } -%#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - double d = PyFloat_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = d; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); - } else { - PyErr_Clear(); - } - } - } -%#endif - if (PyArray_IsScalar(obj,Double)) + SWIGINTERN int + SWIG_AsVal_dec(double)(PyObject *obj, double *val) { - PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_DOUBLE); - PyArray_CastScalarToCtype(obj, (void*)val, descr); - Py_DECREF(descr); - return SWIG_AddCast(SWIG_OK); + int res = SWIG_TypeError; + if (PyFloat_Check(obj)) { + if (val) *val = PyFloat_AsDouble(obj); + return SWIG_OK; + } else if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + double v = PyLong_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } + %#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + double d = PyFloat_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = d; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); + } else { + PyErr_Clear(); + } + } + } + %#endif + if (PyArray_IsScalar(obj,Double)) + { + PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_DOUBLE); + PyArray_CastScalarToCtype(obj, (void*)val, descr); + Py_DECREF(descr); + return SWIG_AddCast(SWIG_OK); + } + if (PyArray_IsScalar(obj,Float)) + { + float fval; + PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_FLOAT32); + PyArray_CastScalarToCtype(obj, (void*)&fval, descr); + *val=(double)fval; + Py_DECREF(descr); + return SWIG_AddCast(SWIG_OK); + } + return res; } - if (PyArray_IsScalar(obj,Float)) - { - float fval; - PyArray_Descr * descr = PyArray_DescrNewFromType(NPY_FLOAT32); - PyArray_CastScalarToCtype(obj, (void*)&fval, descr); - *val=(double)fval; - Py_DECREF(descr); - return SWIG_AddCast(SWIG_OK); - } - return res; -} } diff --git a/src/swig/stir.i b/src/swig/stir.i index 60e1a867a3..d30638d03b 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -1,64 +1,64 @@ /* - Copyright (C) 2011-07-01 - 2012, Kris Thielemans - Copyright (C) 2013 University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ + Copyright (C) 2011-07-01 - 2012, Kris Thielemans + Copyright (C) 2013 University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details + */ /*! - \file - \brief Interface file for SWIG - - \author Kris Thielemans -*/ + \file + \brief Interface file for SWIG + + \author Kris Thielemans + */ %module stir %{ #define SWIG_FILE_WITH_INIT - - /* Include the following headers in the wrapper code */ + + /* Include the following headers in the wrapper code */ #include #include #include // for size_t #include #include #ifdef SWIGOCTAVE -// TODO terrible work-around to avoid conflict between stir::error and Octave error -// they are in conflict with eachother because we need "using namespace stir" below (swig bug) + // TODO terrible work-around to avoid conflict between stir::error and Octave error + // they are in conflict with eachother because we need "using namespace stir" below (swig bug) #define __stir_error_H__ #endif - + #include "stir/num_threads.h" - - #include "stir/Succeeded.h" - #include "stir/DetectionPosition.h" - #include "stir/Scanner.h" - #include "stir/Bin.h" - #include "stir/ProjDataInfoCylindricalArcCorr.h" - #include "stir/ProjDataInfoCylindricalNoArcCorr.h" - #include "stir/Viewgram.h" - #include "stir/RelatedViewgrams.h" - #include "stir/Sinogram.h" - #include "stir/SegmentByView.h" - #include "stir/SegmentBySinogram.h" - #include "stir/ExamInfo.h" - #include "stir/IO/ExamData.h" - #include "stir/Verbosity.h" - #include "stir/ProjData.h" - #include "stir/ProjDataInMemory.h" - #include "stir/ProjDataInterfile.h" - + +#include "stir/Succeeded.h" +#include "stir/DetectionPosition.h" +#include "stir/Scanner.h" +#include "stir/Bin.h" +#include "stir/ProjDataInfoCylindricalArcCorr.h" +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/Viewgram.h" +#include "stir/RelatedViewgrams.h" +#include "stir/Sinogram.h" +#include "stir/SegmentByView.h" +#include "stir/SegmentBySinogram.h" +#include "stir/ExamInfo.h" +#include "stir/IO/ExamData.h" +#include "stir/Verbosity.h" +#include "stir/ProjData.h" +#include "stir/ProjDataInMemory.h" +#include "stir/ProjDataInterfile.h" + #include "stir/CartesianCoordinate2D.h" #include "stir/CartesianCoordinate3D.h" #include "stir/IndexRange.h" @@ -68,393 +68,394 @@ #include "stir/DiscretisedDensityOnCartesianGrid.h" #include "stir/PixelsOnCartesianGrid.h" #include "stir/VoxelsOnCartesianGrid.h" - + #include "stir/GeneralisedPoissonNoiseGenerator.h" - + #include "stir/IO/read_from_file.h" #include "stir/IO/InterfileOutputFileFormat.h" #ifdef HAVE_LLN_MATRIX #include "stir/IO/ECAT7OutputFileFormat.h" #endif - + #include "stir/ChainedDataProcessor.h" #include "stir/SeparableCartesianMetzImageFilter.h" - -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" + +#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" #include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" #include "stir/OSSPS/OSSPSReconstruction.h" #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" - + #include "stir/analytic/FBP2D/FBP2DReconstruction.h" #include "stir/analytic/FBP3DRP/FBP3DRPReconstruction.h" - + #include #include #include - + +#include "stir/IO/write_to_file.h" #include "stir/scatter/ScatterSimulation.h" #include "stir/scatter/SingleScatterSimulation.h" #include "stir/scatter/SingleScatterLikelihoodAndGradient.h" - - // TODO need this (bug in swig) - // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace - // as opposed to "%template(name) stir::someclass" outside the namespace - using namespace stir; - using std::iostream; - + + // TODO need this (bug in swig) + // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace + // as opposed to "%template(name) stir::someclass" outside the namespace + using namespace stir; + using std::iostream; + #if defined(SWIGPYTHON) - // need to declare this internal SWIG function as we're using it in the - // helper code below. It is used to convert a Python object to a float. - SWIGINTERN int - SWIG_AsVal_double (PyObject * obj, double *val); + // need to declare this internal SWIG function as we're using it in the + // helper code below. It is used to convert a Python object to a float. + SWIGINTERN int + SWIG_AsVal_double (PyObject * obj, double *val); #endif - - // local helper functions for conversions etc. These are not "exposed" to the target language - // (but only enter in the wrapper) - namespace swigstir { + + // local helper functions for conversions etc. These are not "exposed" to the target language + // (but only enter in the wrapper) + namespace swigstir { #if defined(SWIGPYTHON) - // helper function to translate a tuple to a BasicCoordinate - // returns zero on failure - template - int coord_from_tuple(stir::BasicCoordinate& c, PyObject* const args) - { return 0; } - template<> int coord_from_tuple(stir::BasicCoordinate<1, int>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "i", &c[1]); } - template<> int coord_from_tuple(stir::BasicCoordinate<2, int>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "ii", &c[1], &c[2]); } - template<> int coord_from_tuple(stir::BasicCoordinate<3, int>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "iii", &c[1], &c[2], &c[3]); } - template<> int coord_from_tuple(stir::BasicCoordinate<1, float>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "f", &c[1]); } - template<> int coord_from_tuple(stir::BasicCoordinate<2, float>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "ff", &c[1], &c[2]); } - template<> int coord_from_tuple(stir::BasicCoordinate<3, float>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "fff", &c[1], &c[2], &c[3]); } - - template - PyObject* tuple_from_coord(const stir::BasicCoordinate& c) - { - PyObject* p = PyTuple_New(num_dimensions); - for (int d=1; d<=num_dimensions; ++d) - PyTuple_SET_ITEM(p, d-1, PyInt_FromLong(c[d])); - return p; - } - template - PyObject* tuple_from_coord(const stir::BasicCoordinate& c) - { - PyObject* p = PyTuple_New(num_dimensions); - for (int d=1; d<=num_dimensions; ++d) - PyTuple_SET_ITEM(p, d-1, PyInt_FromSize_t(c[d])); - return p; - } - template - PyObject* tuple_from_coord(const stir::BasicCoordinate& c) - { - PyObject* p = PyTuple_New(num_dimensions); - for (int d=1; d<=num_dimensions; ++d) - PyTuple_SET_ITEM(p, d-1, PyFloat_FromDouble(double(c[d]))); - return p; - } - - // fill an array from a Python sequence - // (could be trivially modified to just write to a C++ iterator) - template - void fill_Array_from_Python_iterator(stir::Array * array_ptr, PyObject* const arg) - { - if (!PyIter_Check(arg)) - throw std::runtime_error("STIR-Python internal error: fill_Array_from_Python_iterators called but input is not an iterator"); - - { - PyObject *iterator = PyObject_GetIter(arg); - - PyObject *item; - typename stir::Array::full_iterator array_iter = array_ptr->begin_all(); - while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) + // helper function to translate a tuple to a BasicCoordinate + // returns zero on failure + template + int coord_from_tuple(stir::BasicCoordinate& c, PyObject* const args) + { return 0; } + template<> int coord_from_tuple(stir::BasicCoordinate<1, int>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "i", &c[1]); } + template<> int coord_from_tuple(stir::BasicCoordinate<2, int>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "ii", &c[1], &c[2]); } + template<> int coord_from_tuple(stir::BasicCoordinate<3, int>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "iii", &c[1], &c[2], &c[3]); } + template<> int coord_from_tuple(stir::BasicCoordinate<1, float>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "f", &c[1]); } + template<> int coord_from_tuple(stir::BasicCoordinate<2, float>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "ff", &c[1], &c[2]); } + template<> int coord_from_tuple(stir::BasicCoordinate<3, float>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "fff", &c[1], &c[2], &c[3]); } + + template + PyObject* tuple_from_coord(const stir::BasicCoordinate& c) { - double val; - // TODO currently hard-wired as double which might imply extra conversions - int ecode = SWIG_AsVal_double(item, &val); - if (SWIG_IsOK(ecode)) - { - *array_iter++ = static_cast(val); - } - else - { - Py_DECREF(item); - Py_DECREF(iterator); - char str[1000]; - snprintf(str, 1000, "Wrong type used for fill(): iterator elements are of type %s but needs to be convertible to double", - item->ob_type->tp_name); - throw std::invalid_argument(str); - } - Py_DECREF(item); - } - - if (PyIter_Next(iterator) != NULL || array_iter != array_ptr->end_all()) + PyObject* p = PyTuple_New(num_dimensions); + for (int d=1; d<=num_dimensions; ++d) + PyTuple_SET_ITEM(p, d-1, PyInt_FromLong(c[d])); + return p; + } + template + PyObject* tuple_from_coord(const stir::BasicCoordinate& c) { - throw std::runtime_error("fill() called with incorrect range of iterators, array needs to have the same number of elements"); - } - Py_DECREF(iterator); - - if (PyErr_Occurred()) - { - throw std::runtime_error("Error during fill()"); - } - } - - } - + PyObject* p = PyTuple_New(num_dimensions); + for (int d=1; d<=num_dimensions; ++d) + PyTuple_SET_ITEM(p, d-1, PyInt_FromSize_t(c[d])); + return p; + } + template + PyObject* tuple_from_coord(const stir::BasicCoordinate& c) + { + PyObject* p = PyTuple_New(num_dimensions); + for (int d=1; d<=num_dimensions; ++d) + PyTuple_SET_ITEM(p, d-1, PyFloat_FromDouble(double(c[d]))); + return p; + } + + // fill an array from a Python sequence + // (could be trivially modified to just write to a C++ iterator) + template + void fill_Array_from_Python_iterator(stir::Array * array_ptr, PyObject* const arg) + { + if (!PyIter_Check(arg)) + throw std::runtime_error("STIR-Python internal error: fill_Array_from_Python_iterators called but input is not an iterator"); + + { + PyObject *iterator = PyObject_GetIter(arg); + + PyObject *item; + typename stir::Array::full_iterator array_iter = array_ptr->begin_all(); + while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) + { + double val; + // TODO currently hard-wired as double which might imply extra conversions + int ecode = SWIG_AsVal_double(item, &val); + if (SWIG_IsOK(ecode)) + { + *array_iter++ = static_cast(val); + } + else + { + Py_DECREF(item); + Py_DECREF(iterator); + char str[1000]; + snprintf(str, 1000, "Wrong type used for fill(): iterator elements are of type %s but needs to be convertible to double", + item->ob_type->tp_name); + throw std::invalid_argument(str); + } + Py_DECREF(item); + } + + if (PyIter_Next(iterator) != NULL || array_iter != array_ptr->end_all()) + { + throw std::runtime_error("fill() called with incorrect range of iterators, array needs to have the same number of elements"); + } + Py_DECREF(iterator); + + if (PyErr_Occurred()) + { + throw std::runtime_error("Error during fill()"); + } + } + + } + #if 0 - - // TODO does not work yet. - // it doesn't compile as includes are in init section, which follows after this in the wrapper - // Even if it did compile, it might not work anyway as I haven't tested it. - template - void fill_nparray_from_iterator(PyObject * np, IterT iterator) - { - // This code is more or less a copy of the "simple iterator example" (!) in the Numpy doc - // see e.g. http://students.mimuw.edu.pl/~pbechler/numpy_doc/reference/c-api.iterator.html - typedef float elemT; - NpyIter* iter; - NpyIter_IterNextFunc *iternext; - char** dataptr; - npy_intp* strideptr,* innersizeptr; - - /* Handle zero-sized arrays specially */ - if (PyArray_SIZE(np) == 0) { - return; - } - - /* - * Create and use an iterator to count the nonzeros. - * flag NPY_ITER_READONLY - * - The array is never written to. - * flag NPY_ITER_EXTERNAL_LOOP - * - Inner loop is done outside the iterator for efficiency. - * flag NPY_ITER_NPY_ITER_REFS_OK - * - Reference types are acceptable. - * order NPY_KEEPORDER - * - Visit elements in memory order, regardless of strides. - * This is good for performance when the specific order - * elements are visited is unimportant. - * casting NPY_NO_CASTING - * - No casting is required for this operation. - */ - iter = NpyIter_New(np, NPY_ITER_WRITEONLY| - NPY_ITER_EXTERNAL_LOOP, - NPY_KEEPORDER, NPY_NO_CASTING, - NULL); - if (iter == NULL) { - throw std::runtime_error("Error creating numpy iterator"); - } - - /* - * The iternext function gets stored in a local variable - * so it can be called repeatedly in an efficient manner. - */ - iternext = NpyIter_GetIterNext(iter, NULL); - if (iternext == NULL) { - NpyIter_Deallocate(iter); - throw std::runtime_error("Error creating numpy iterator function"); - } - /* The location of the data pointer which the iterator may update */ - dataptr = NpyIter_GetDataPtrArray(iter); - /* The location of the stride which the iterator may update */ - strideptr = NpyIter_GetInnerStrideArray(iter); - /* The location of the inner loop size which the iterator may update */ - innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); - - /* The iteration loop */ - do { - /* Get the inner loop data/stride/count values */ - char* data = *dataptr; - npy_intp stride = *strideptr; - npy_intp count = *innersizeptr; - - /* This is a typical inner loop for NPY_ITER_EXTERNAL_LOOP */ - while (count--) { - *(reinterpret_cast(data)) = static_cast(*iterator++); - data += stride; + + // TODO does not work yet. + // it doesn't compile as includes are in init section, which follows after this in the wrapper + // Even if it did compile, it might not work anyway as I haven't tested it. + template + void fill_nparray_from_iterator(PyObject * np, IterT iterator) + { + // This code is more or less a copy of the "simple iterator example" (!) in the Numpy doc + // see e.g. http://students.mimuw.edu.pl/~pbechler/numpy_doc/reference/c-api.iterator.html + typedef float elemT; + NpyIter* iter; + NpyIter_IterNextFunc *iternext; + char** dataptr; + npy_intp* strideptr,* innersizeptr; + + /* Handle zero-sized arrays specially */ + if (PyArray_SIZE(np) == 0) { + return; + } + + /* + * Create and use an iterator to count the nonzeros. + * flag NPY_ITER_READONLY + * - The array is never written to. + * flag NPY_ITER_EXTERNAL_LOOP + * - Inner loop is done outside the iterator for efficiency. + * flag NPY_ITER_NPY_ITER_REFS_OK + * - Reference types are acceptable. + * order NPY_KEEPORDER + * - Visit elements in memory order, regardless of strides. + * This is good for performance when the specific order + * elements are visited is unimportant. + * casting NPY_NO_CASTING + * - No casting is required for this operation. + */ + iter = NpyIter_New(np, NPY_ITER_WRITEONLY| + NPY_ITER_EXTERNAL_LOOP, + NPY_KEEPORDER, NPY_NO_CASTING, + NULL); + if (iter == NULL) { + throw std::runtime_error("Error creating numpy iterator"); + } + + /* + * The iternext function gets stored in a local variable + * so it can be called repeatedly in an efficient manner. + */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + throw std::runtime_error("Error creating numpy iterator function"); + } + /* The location of the data pointer which the iterator may update */ + dataptr = NpyIter_GetDataPtrArray(iter); + /* The location of the stride which the iterator may update */ + strideptr = NpyIter_GetInnerStrideArray(iter); + /* The location of the inner loop size which the iterator may update */ + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + /* The iteration loop */ + do { + /* Get the inner loop data/stride/count values */ + char* data = *dataptr; + npy_intp stride = *strideptr; + npy_intp count = *innersizeptr; + + /* This is a typical inner loop for NPY_ITER_EXTERNAL_LOOP */ + while (count--) { + *(reinterpret_cast(data)) = static_cast(*iterator++); + data += stride; + } + + /* Increment the iterator to the next inner loop */ + } while(iternext(iter)); + + NpyIter_Deallocate(iter); } - - /* Increment the iterator to the next inner loop */ - } while(iternext(iter)); - - NpyIter_Deallocate(iter); - } #endif - + #elif defined(SWIGMATLAB) - // convert stir::Array to matlab (currently always converting to double) - // note that the order of the dimensions is reversed to take row-first vs column-first ordering into account - template - mxArray * Array_to_matlab(const stir::Array& a) - { - mwSize dims[num_dimensions]; - BasicCoordinate minind,maxind; - a.get_regular_range(minind,maxind); - const BasicCoordinate sizes=maxind-minind+1; - // copy dimensions in reverse order - std::copy(boost::make_reverse_iterator(sizes.end()), boost::make_reverse_iterator(sizes.begin()), dims); - mxArray *pm = mxCreateNumericArray(num_dimensions, dims, mxDOUBLE_CLASS, mxREAL); - double * data_ptr = mxGetPr(pm); - std::copy(a.begin_all(), a.end_all(), data_ptr); - return pm; - } - - template - void fill_Array_from_matlab_scalar(stir::Array& a, const mxArray *pm) - { - if (mxIsDouble(pm)) - { - double const* data_ptr = mxGetPr(pm); - a.fill(static_cast(*data_ptr)); - } else if (mxIsSingle(pm)) - { - float const* data_ptr = (float *)mxGetData(pm); - a.fill(static_cast(*data_ptr)); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for filling a stir array"); - } - } - - template - void fill_Array_from_matlab(stir::Array& a, const mxArray *pm, bool do_resize) - { - mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); - const mwSize * m_sizes = mxGetDimensions(pm); - // matlab represents scalars/vectors as a matrix, so let's check this first - if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) - { - if (m_sizes[0] ==static_cast(1)) - { - // it's a scalar - fill_Array_from_matlab_scalar(a, pm); - return; - } - matlab_num_dims=static_cast(1); // set it to a 1-dimensional array - } - if (matlab_num_dims > static_cast(num_dimensions)) - { - throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % - num_dimensions)); - } - if (do_resize) - { - BasicCoordinate sizes; - // first set all to 1 to cope with lower-dimensional arrays from matlab - sizes.fill(1); - std::copy(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end())); - a.resize(sizes); - } - else - { - // check sizes - BasicCoordinate minind,maxind; - a.get_regular_range(minind,maxind); - const BasicCoordinate sizes=maxind-minind+1; - if (!std::equal(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end()))) - { - throw std::runtime_error("sizes of matlab array incompatible with stir array"); - } - for (int d=1; d<= num_dimensions-static_cast(matlab_num_dims); ++d) - { - if (sizes[d]!=1) - { - throw std::runtime_error("sizes of first dimensions of the stir array have to be 1 if initialising from a lower dimensional matlab array"); - } - } - } - if (mxIsDouble(pm)) - { - double * data_ptr = mxGetPr(pm); - std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); - } else if (mxIsSingle(pm)) - { - float * data_ptr = (float *)mxGetData(pm); - std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); - } - } - - - //////////// same for Coordinate - // convert stir::BasicCoordinate to matlab (currently always converting to double) - template - mxArray * BasicCoordinate_to_matlab(const stir::BasicCoordinate& a) - { - mwSize dims[2]; - dims[0]=mwSize(num_dimensions); - dims[1]=mwSize(1); - mxArray *pm = mxCreateNumericArray(mwSize(2), dims, mxDOUBLE_CLASS, mxREAL); - double * data_ptr = mxGetPr(pm); - std::copy(a.begin(), a.end(), data_ptr); - return pm; - } - - template - void fill_BasicCoordinate_from_matlab_scalar(stir::BasicCoordinate& a, const mxArray *pm) - { - if (mxIsDouble(pm)) - { - double const* data_ptr = mxGetPr(pm); - a.fill(static_cast(*data_ptr)); - } else if (mxIsSingle(pm)) - { - float const* data_ptr = (float *)mxGetData(pm); - a.fill(static_cast(*data_ptr)); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for filling a stir coordinate"); - } - } - - template - void fill_BasicCoordinate_from_matlab(stir::BasicCoordinate& a, const mxArray *pm) - { - mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); - const mwSize * m_sizes = mxGetDimensions(pm); - // matlab represents scalars/vectors as a matrix, so let's check this first - if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) - { - if (m_sizes[0] ==static_cast(1)) - { - // it's a scalar - fill_BasicCoordinate_from_matlab_scalar(a, pm); - return; - } - matlab_num_dims=static_cast(1); // set it to a 1-dimensional array - } - if (matlab_num_dims != static_cast(1)) - { - throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % - matlab_num_dims % num_dimensions)); - } - if (m_sizes[0]!=static_cast(num_dimensions)) - { - throw std::runtime_error("length of matlab array incompatible with stir coordinate"); - } - if (mxIsDouble(pm)) - { - double * data_ptr = mxGetPr(pm); - std::copy(data_ptr, data_ptr+a.size(), a.begin()); - } else if (mxIsSingle(pm)) - { - float * data_ptr = (float *)mxGetData(pm); - std::copy(data_ptr, data_ptr+a.size(), a.begin()); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); - } - } + // convert stir::Array to matlab (currently always converting to double) + // note that the order of the dimensions is reversed to take row-first vs column-first ordering into account + template + mxArray * Array_to_matlab(const stir::Array& a) + { + mwSize dims[num_dimensions]; + BasicCoordinate minind,maxind; + a.get_regular_range(minind,maxind); + const BasicCoordinate sizes=maxind-minind+1; + // copy dimensions in reverse order + std::copy(boost::make_reverse_iterator(sizes.end()), boost::make_reverse_iterator(sizes.begin()), dims); + mxArray *pm = mxCreateNumericArray(num_dimensions, dims, mxDOUBLE_CLASS, mxREAL); + double * data_ptr = mxGetPr(pm); + std::copy(a.begin_all(), a.end_all(), data_ptr); + return pm; + } + + template + void fill_Array_from_matlab_scalar(stir::Array& a, const mxArray *pm) + { + if (mxIsDouble(pm)) + { + double const* data_ptr = mxGetPr(pm); + a.fill(static_cast(*data_ptr)); + } else if (mxIsSingle(pm)) + { + float const* data_ptr = (float *)mxGetData(pm); + a.fill(static_cast(*data_ptr)); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for filling a stir array"); + } + } + + template + void fill_Array_from_matlab(stir::Array& a, const mxArray *pm, bool do_resize) + { + mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); + const mwSize * m_sizes = mxGetDimensions(pm); + // matlab represents scalars/vectors as a matrix, so let's check this first + if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) + { + if (m_sizes[0] ==static_cast(1)) + { + // it's a scalar + fill_Array_from_matlab_scalar(a, pm); + return; + } + matlab_num_dims=static_cast(1); // set it to a 1-dimensional array + } + if (matlab_num_dims > static_cast(num_dimensions)) + { + throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % + num_dimensions)); + } + if (do_resize) + { + BasicCoordinate sizes; + // first set all to 1 to cope with lower-dimensional arrays from matlab + sizes.fill(1); + std::copy(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end())); + a.resize(sizes); + } + else + { + // check sizes + BasicCoordinate minind,maxind; + a.get_regular_range(minind,maxind); + const BasicCoordinate sizes=maxind-minind+1; + if (!std::equal(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end()))) + { + throw std::runtime_error("sizes of matlab array incompatible with stir array"); + } + for (int d=1; d<= num_dimensions-static_cast(matlab_num_dims); ++d) + { + if (sizes[d]!=1) + { + throw std::runtime_error("sizes of first dimensions of the stir array have to be 1 if initialising from a lower dimensional matlab array"); + } + } + } + if (mxIsDouble(pm)) + { + double * data_ptr = mxGetPr(pm); + std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); + } else if (mxIsSingle(pm)) + { + float * data_ptr = (float *)mxGetData(pm); + std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); + } + } + + + //////////// same for Coordinate + // convert stir::BasicCoordinate to matlab (currently always converting to double) + template + mxArray * BasicCoordinate_to_matlab(const stir::BasicCoordinate& a) + { + mwSize dims[2]; + dims[0]=mwSize(num_dimensions); + dims[1]=mwSize(1); + mxArray *pm = mxCreateNumericArray(mwSize(2), dims, mxDOUBLE_CLASS, mxREAL); + double * data_ptr = mxGetPr(pm); + std::copy(a.begin(), a.end(), data_ptr); + return pm; + } + + template + void fill_BasicCoordinate_from_matlab_scalar(stir::BasicCoordinate& a, const mxArray *pm) + { + if (mxIsDouble(pm)) + { + double const* data_ptr = mxGetPr(pm); + a.fill(static_cast(*data_ptr)); + } else if (mxIsSingle(pm)) + { + float const* data_ptr = (float *)mxGetData(pm); + a.fill(static_cast(*data_ptr)); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for filling a stir coordinate"); + } + } + + template + void fill_BasicCoordinate_from_matlab(stir::BasicCoordinate& a, const mxArray *pm) + { + mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); + const mwSize * m_sizes = mxGetDimensions(pm); + // matlab represents scalars/vectors as a matrix, so let's check this first + if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) + { + if (m_sizes[0] ==static_cast(1)) + { + // it's a scalar + fill_BasicCoordinate_from_matlab_scalar(a, pm); + return; + } + matlab_num_dims=static_cast(1); // set it to a 1-dimensional array + } + if (matlab_num_dims != static_cast(1)) + { + throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % + matlab_num_dims % num_dimensions)); + } + if (m_sizes[0]!=static_cast(num_dimensions)) + { + throw std::runtime_error("length of matlab array incompatible with stir coordinate"); + } + if (mxIsDouble(pm)) + { + double * data_ptr = mxGetPr(pm); + std::copy(data_ptr, data_ptr+a.size(), a.begin()); + } else if (mxIsSingle(pm)) + { + float * data_ptr = (float *)mxGetData(pm); + std::copy(data_ptr, data_ptr+a.size(), a.begin()); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); + } + } #endif - } // end namespace swigstir - %} + } // end namespace swigstir + %} #if defined(SWIGPYTHON) %include "numpy.i" @@ -465,11 +466,11 @@ %init %{ #if defined(SWIGPYTHON) - // numpy support - import_array(); - #include + // numpy support + import_array(); +#include #endif -%} + %} %feature("autodoc", "1"); @@ -485,14 +486,14 @@ %include "exception.i" %exception { - try { - $action - } catch (const std::exception& e) { - SWIG_exception(SWIG_RuntimeError, e.what()); - } catch (const std::string& e) { - SWIG_exception(SWIG_RuntimeError, e.c_str()); - } -} + try { + $action + } catch (const std::exception& e) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } catch (const std::string& e) { + SWIG_exception(SWIG_RuntimeError, e.c_str()); + } +} // declare some functions that return a new pointer such that SWIG can release memory properly %newobject *::clone; @@ -503,7 +504,7 @@ %ignore *::create_shared_clone; #if defined(SWIGPYTHON) -%rename(__assign__) *::operator=; +%rename(__assign__) *::operator=; #endif // include standard swig support for some bits of the STL (i.e. standard C++ lib) @@ -518,7 +519,7 @@ // always ignore these as they are unsafe in out-of-range index access (use at() instead) %ignore *::operator[]; - // this will be replaced by __getitem__ etc, we could keep this for languages not supported by ADD_indexvalue +// this will be replaced by __getitem__ etc, we could keep this for languages not supported by ADD_indexvalue %ignore *::at; #ifdef STIRMATLAB @@ -542,13 +543,13 @@ // Instantiate STL templates used by stir namespace std { - %template(IntVector) vector; - %template(DoubleVector) vector; - %template(FloatVector) vector; - %template(StringList) list; + %template(IntVector) vector; + %template(DoubleVector) vector; + %template(FloatVector) vector; + %template(StringList) list; } -// section for helper classes for creating new iterators. +// section for helper classes for creating new iterators. // The code here is nearly a copy of what's in PyIterators.swg, // except that the decr() function isn't defined. This is because we need it for some STIR iterators // which are forward_iterators. @@ -557,248 +558,248 @@ namespace std { // Note: this needs to be defined after including some stl stuff, as otherwise the necessary fragments // haven't been included in the wrap.cxx yet. %{ - namespace swigstir { + namespace swigstir { #ifdef SWIGPYTHON - template::value_type, - typename FromOper = swig::from_oper > - class SwigPyForwardIteratorClosed_T : public swig::SwigPyIterator_T - { - public: - FromOper from; - typedef OutIterator out_iterator; - typedef ValueType value_type; - typedef swig::SwigPyIterator_T base; - typedef SwigPyForwardIteratorClosed_T self_type; - - SwigPyForwardIteratorClosed_T(out_iterator curr, out_iterator first, out_iterator last, PyObject *seq) - : swig::SwigPyIterator_T(curr, seq), begin(first), end(last) - { - } - - PyObject *value() const { - if (base::current == end) { - throw swig::stop_iteration(); - } else { - return swig::from(static_cast(*(base::current))); - } - } - - swig::SwigPyIterator *copy() const - { - return new self_type(*this); - } - - swig::SwigPyIterator *incr(size_t n = 1) - { - while (n--) { - if (base::current == end) { - throw swig::stop_iteration(); - } else { - ++base::current; - } - } - return this; - } - - private: - out_iterator begin; - out_iterator end; - }; - - template - inline swig::SwigPyIterator* - make_forward_iterator(const OutIter& current, const OutIter& begin,const OutIter& end, PyObject *seq = 0) - { - return new SwigPyForwardIteratorClosed_T(current, begin, end, seq); - } - - + template::value_type, + typename FromOper = swig::from_oper > + class SwigPyForwardIteratorClosed_T : public swig::SwigPyIterator_T + { + public: + FromOper from; + typedef OutIterator out_iterator; + typedef ValueType value_type; + typedef swig::SwigPyIterator_T base; + typedef SwigPyForwardIteratorClosed_T self_type; + + SwigPyForwardIteratorClosed_T(out_iterator curr, out_iterator first, out_iterator last, PyObject *seq) + : swig::SwigPyIterator_T(curr, seq), begin(first), end(last) + { + } + + PyObject *value() const { + if (base::current == end) { + throw swig::stop_iteration(); + } else { + return swig::from(static_cast(*(base::current))); + } + } + + swig::SwigPyIterator *copy() const + { + return new self_type(*this); + } + + swig::SwigPyIterator *incr(size_t n = 1) + { + while (n--) { + if (base::current == end) { + throw swig::stop_iteration(); + } else { + ++base::current; + } + } + return this; + } + + private: + out_iterator begin; + out_iterator end; + }; + + template + inline swig::SwigPyIterator* + make_forward_iterator(const OutIter& current, const OutIter& begin,const OutIter& end, PyObject *seq = 0) + { + return new SwigPyForwardIteratorClosed_T(current, begin, end, seq); + } + + #endif - static Array<3,float> create_array_for_proj_data(const ProjData& proj_data) - { - // int num_sinos=proj_data.get_num_axial_poss(0); - // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) - // { - // num_sinos += 2*proj_data.get_num_axial_poss(s); - // } - int num_sinos = proj_data.get_num_sinograms(); - - Array<3,float> array(IndexRange3D(num_sinos, proj_data.get_num_views(), proj_data.get_num_tangential_poss())); - return array; - } - - // a function for converting ProjData to a 3D array as that's what is easy to use - static Array<3,float> projdata_to_3D(const ProjData& proj_data) - { - Array<3,float> array = create_array_for_proj_data(proj_data); - Array<3,float>::full_iterator array_iter = array.begin_all(); - // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) - // { - // SegmentBySinogram segment=proj_data.get_segment_by_sinogram(s); - // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); - // std::advance(array_iter, segment.size_all()); - // if (s!=0) - // { - // segment=proj_data.get_segment_by_sinogram(-s); - // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); - // std::advance(array_iter, segment.size_all()); - // } - // } - proj_data.copy_to(array_iter); - return array; - } - - // inverse of the above function - void fill_proj_data_from_3D(ProjData& proj_data, const Array<3,float>& array) - { - // int num_sinos=proj_data.get_num_axial_poss(0); - // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) - // { - // num_sinos += 2*proj_data.get_num_axial_poss(s); - // } - // if (array.size() != static_cast(num_sinos)|| - // array[0].size() != static_cast(proj_data.get_num_views()) || - // array[0][0].size() != static_cast(proj_data.get_num_tangential_poss())) - // { - // throw std::runtime_error("Incorrect size for filling this projection data"); - // } - Array<3,float>::const_full_iterator array_iter = array.begin_all(); - // - // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) - // { - // SegmentBySinogram segment=proj_data.get_empty_segment_by_sinogram(s); - // // cannot use std::copy sadly as needs end-iterator for range - // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); - // seg_iter != segment.end_all(); - // /*empty*/) - // *seg_iter++ = *array_iter++; - // proj_data.set_segment(segment); - // - // if (s!=0) - // { - // segment=proj_data.get_empty_segment_by_sinogram(-s); - // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); - // seg_iter != segment.end_all(); - // /*empty*/) - // *seg_iter++ = *array_iter++; - // proj_data.set_segment(segment); - // } - // } - proj_data.fill_from(array_iter); - } - - - } // end of namespace - - %} // end of initial code specification for inclusino in the SWIG wrapper + static Array<3,float> create_array_for_proj_data(const ProjData& proj_data) + { + // int num_sinos=proj_data.get_num_axial_poss(0); + // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) + // { + // num_sinos += 2*proj_data.get_num_axial_poss(s); + // } + int num_sinos = proj_data.get_num_sinograms(); + + Array<3,float> array(IndexRange3D(num_sinos, proj_data.get_num_views(), proj_data.get_num_tangential_poss())); + return array; + } + + // a function for converting ProjData to a 3D array as that's what is easy to use + static Array<3,float> projdata_to_3D(const ProjData& proj_data) + { + Array<3,float> array = create_array_for_proj_data(proj_data); + Array<3,float>::full_iterator array_iter = array.begin_all(); + // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) + // { + // SegmentBySinogram segment=proj_data.get_segment_by_sinogram(s); + // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + // std::advance(array_iter, segment.size_all()); + // if (s!=0) + // { + // segment=proj_data.get_segment_by_sinogram(-s); + // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + // std::advance(array_iter, segment.size_all()); + // } + // } + proj_data.copy_to(array_iter); + return array; + } + + // inverse of the above function + void fill_proj_data_from_3D(ProjData& proj_data, const Array<3,float>& array) + { + // int num_sinos=proj_data.get_num_axial_poss(0); + // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) + // { + // num_sinos += 2*proj_data.get_num_axial_poss(s); + // } + // if (array.size() != static_cast(num_sinos)|| + // array[0].size() != static_cast(proj_data.get_num_views()) || + // array[0][0].size() != static_cast(proj_data.get_num_tangential_poss())) + // { + // throw std::runtime_error("Incorrect size for filling this projection data"); + // } + Array<3,float>::const_full_iterator array_iter = array.begin_all(); + // + // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) + // { + // SegmentBySinogram segment=proj_data.get_empty_segment_by_sinogram(s); + // // cannot use std::copy sadly as needs end-iterator for range + // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); + // seg_iter != segment.end_all(); + // /*empty*/) + // *seg_iter++ = *array_iter++; + // proj_data.set_segment(segment); + // + // if (s!=0) + // { + // segment=proj_data.get_empty_segment_by_sinogram(-s); + // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); + // seg_iter != segment.end_all(); + // /*empty*/) + // *seg_iter++ = *array_iter++; + // proj_data.set_segment(segment); + // } + // } + proj_data.fill_from(array_iter); + } + + + } // end of namespace + + %} // end of initial code specification for inclusino in the SWIG wrapper // doesn't work (yet?) because of bug in int template arguments -// %rename(__getitem__) *::at; +// %rename(__getitem__) *::at; // MACROS to define index access (Work-in-progress) %define %ADD_indexaccess(INDEXTYPE,RETTYPE,TYPE...) #if defined(SWIGPYTHON) #if defined(SWIGPYTHON_BUILTIN) - // %feature("python:slot", "sq_item", functype="ssizeargfunc") TYPE##::__getitem__; - // %feature("python:slot", "sq_ass_item", functype="ssizeobjargproc") TYPE##::__setitem__; - %feature("python:slot", "mp_subscript", functype="binaryfunc") TYPE##::__getitem__; - %feature("python:slot", "mp_ass_subscript", functype="objobjargproc") TYPE##::__setitem__; +// %feature("python:slot", "sq_item", functype="ssizeargfunc") TYPE##::__getitem__; +// %feature("python:slot", "sq_ass_item", functype="ssizeobjargproc") TYPE##::__setitem__; +%feature("python:slot", "mp_subscript", functype="binaryfunc") TYPE##::__getitem__; +%feature("python:slot", "mp_ass_subscript", functype="objobjargproc") TYPE##::__setitem__; #endif %extend TYPE { %exception __getitem__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } %newobject __getitem__; RETTYPE __getitem__(const INDEXTYPE i) { return (*self).at(i); } %exception __setitem__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } void __setitem__(const INDEXTYPE i, const RETTYPE val) { (*self).at(i)=val; } - } +} #elif defined(SWIGOCTAVE) %extend TYPE { %exception __brace__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } %newobject __brace__; RETTYPE __brace__(const INDEXTYPE i) { return (*self).at(i); } %exception __brace_asgn__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } void __brace_asgn__(const INDEXTYPE i, const RETTYPE val) { (*self).at(i)=val; } - } +} #elif defined(SWIGMATLAB) %extend TYPE { %exception paren { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } %newobject paren; RETTYPE paren(const INDEXTYPE i) { return (*self).at(i); } %exception paren_asgn { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } void paren_asgn(const INDEXTYPE i, const RETTYPE val) { (*self).at(i)=val; } - } +} #endif %enddef - // Finally, start with STIR specific definitions +// Finally, start with STIR specific definitions %include "stir/num_threads.h" @@ -806,11 +807,11 @@ namespace std { // #define used below to check what to do #define STIRSWIG_SHARED_PTR - // internally convert all pointers to shared_ptr. This prevents problems - // with STIR functions which accept a shared_ptr as input argument. +// internally convert all pointers to shared_ptr. This prevents problems +// with STIR functions which accept a shared_ptr as input argument. #define SWIG_SHARED_PTR_NAMESPACE stir #ifdef SWIGOCTAVE - // TODO temp work-around +// TODO temp work-around %include #else %include @@ -846,11 +847,11 @@ namespace std { %shared_ptr(stir::Viewgram); #else namespace boost { -template class shared_ptr -{ -public: -T * operator-> () const; -}; + template class shared_ptr + { + public: + T * operator-> () const; + }; } #endif @@ -864,17 +865,17 @@ T * operator-> () const; %include "stir/Object.h" %include "stir/RegisteredObject.h" #else - // use simpler version for SWIG to make the hierarchy a bit easier - namespace stir { +// use simpler version for SWIG to make the hierarchy a bit easier +namespace stir { template - class RegisteredObject - { - public: - //! List all possible registered names to the stream - /*! Names are separated with newlines. */ - inline static void list_registered_names(std::ostream& stream); - }; - } + class RegisteredObject + { + public: + //! List all possible registered names to the stream + /*! Names are separated with newlines. */ + inline static void list_registered_names(std::ostream& stream); + }; +} #endif // disabled warning about nested class. we don't need this class anyway @@ -884,7 +885,7 @@ T * operator-> () const; %nodefaultctor stir::RegisteredParsingObject; %include "stir/RegisteredParsingObject.h" - /* Parse the header files to generate wrappers */ +/* Parse the header files to generate wrappers */ //%include "stir/shared_ptr.h" %include "stir/Succeeded.h" %include "stir/NumericType.h" @@ -893,10 +894,10 @@ T * operator-> () const; %newobject stir::Scanner::get_scanner_from_name; %include "stir/Scanner.h" - /* First do coordinates, indices, images. - We first include them, and sort out template instantiation and indexing below. +/* First do coordinates, indices, images. + We first include them, and sort out template instantiation and indexing below. */ - //%include +//%include %include "stir/BasicCoordinate.h" %include "stir/Coordinate3D.h" @@ -911,7 +912,7 @@ T * operator-> () const; %ignore stir::CartesianCoordinate2D::y() const; %include "stir/CartesianCoordinate2D.h" - // we have to ignore the following because of a bug in SWIG 2.0.4, but we don't need it anyway +// we have to ignore the following because of a bug in SWIG 2.0.4, but we don't need it anyway %ignore *::IndexRange(const VectorWithOffset >& range); %include "stir/IndexRange.h" @@ -922,40 +923,40 @@ T * operator-> () const; %include "stir/VectorWithOffset.h" #if defined(SWIGPYTHON) - // TODO ideally would use %swig_container_methods but we don't have getslice yet +// TODO ideally would use %swig_container_methods but we don't have getslice yet #if defined(SWIGPYTHON_BUILTIN) - %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; - %feature("python:slot", "sq_length", functype="lenfunc") __len__; +%feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; +%feature("python:slot", "sq_length", functype="lenfunc") __len__; #endif // SWIGPYTHON_BUILTIN %extend stir::VectorWithOffset { bool __nonzero__() const { - return !(self->empty()); + return !(self->empty()); } - + /* Alias for Python 3 compatibility */ bool __bool__() const { - return !(self->empty()); + return !(self->empty()); } - + size_type __len__() const { - return self->size(); + return self->size(); } #if 0 // TODO this does not work yet /* -%define %emit_swig_traits(_Type...) -%traits_swigtype(_Type); -%fragment(SWIG_Traits_frag(_Type)); -%enddef - -%emit_swig_traits(MyPrice) - */ + %define %emit_swig_traits(_Type...) + %traits_swigtype(_Type); + %fragment(SWIG_Traits_frag(_Type)); + %enddef + + %emit_swig_traits(MyPrice) + */ %swig_sequence_iterator(stir::VectorWithOffset); #else %newobject _iterator(PyObject **PYTHON_SELF); swig::SwigPyIterator* _iterator(PyObject **PYTHON_SELF) { - return swig::make_output_iterator(self->begin(), self->begin(), self->end(), *PYTHON_SELF); + return swig::make_output_iterator(self->begin(), self->begin(), self->end(), *PYTHON_SELF); } #if defined(SWIGPYTHON_BUILTIN) %feature("python:slot", "tp_iter", functype="getiterfunc") _iterator; @@ -963,7 +964,7 @@ T * operator-> () const; %pythoncode {def __iter__(self): return self._iterator()} #endif #endif - } +} #endif %include "stir/NumericVectorWithOffset.h" @@ -983,267 +984,267 @@ T * operator-> () const; %include "stir/VoxelsOnCartesianGrid.h" %extend stir::VoxelsOnCartesianGrid { - // add read_from_file to this class, as currently there is no way - // to convert the swigged DiscretisedDensity to a VoxelsOnCartesianGrid - static stir::VoxelsOnCartesianGrid * read_from_file(const std::string& filename) + // add read_from_file to this class, as currently there is no way + // to convert the swigged DiscretisedDensity to a VoxelsOnCartesianGrid + static stir::VoxelsOnCartesianGrid * read_from_file(const std::string& filename) { - using namespace stir; - unique_ptr > - ret(read_from_file >(filename)); - return dynamic_cast *>(ret.release()); + using namespace stir; + unique_ptr > + ret(read_from_file >(filename)); + return dynamic_cast *>(ret.release()); } - } +} - //%ADD_indexaccess(int,stir::BasicCoordinate::value_type,stir::BasicCoordinate); -namespace stir { +//%ADD_indexaccess(int,stir::BasicCoordinate::value_type,stir::BasicCoordinate); +namespace stir { #ifdef SWIGPYTHON - // add extra features to the coordinates to make them a bit more Python friendly - %extend BasicCoordinate { - //%feature("autodoc", "construct from tuple, e.g. (2,3,4) for a 3d coordinate") - BasicCoordinate(PyObject* args) - { - BasicCoordinate *c=new BasicCoordinate; - if (!swigstir::coord_from_tuple(*c, args)) - { - throw std::invalid_argument("Wrong type of argument to construct Coordinate used"); - } - return c; - }; - - // print as (1,2,3) as opposed to non-informative default provided by SWIG - std::string __str__() - { - std::ostringstream s; - s<<'('; - for (int d=1; d<=num_dimensions-1; ++d) - s << (*$self)[d] << ", "; - s << (*$self)[num_dimensions] << ')'; - return s.str(); - } - - // print as classname((1,2,3)) as opposed to non-informative default provided by SWIG - std::string __repr__() - { + // add extra features to the coordinates to make them a bit more Python friendly + %extend BasicCoordinate { + //%feature("autodoc", "construct from tuple, e.g. (2,3,4) for a 3d coordinate") + BasicCoordinate(PyObject* args) + { + BasicCoordinate *c=new BasicCoordinate; + if (!swigstir::coord_from_tuple(*c, args)) + { + throw std::invalid_argument("Wrong type of argument to construct Coordinate used"); + } + return c; + }; + + // print as (1,2,3) as opposed to non-informative default provided by SWIG + std::string __str__() + { + std::ostringstream s; + s<<'('; + for (int d=1; d<=num_dimensions-1; ++d) + s << (*$self)[d] << ", "; + s << (*$self)[num_dimensions] << ')'; + return s.str(); + } + + // print as classname((1,2,3)) as opposed to non-informative default provided by SWIG + std::string __repr__() + { #if SWIG_VERSION < 0x020009 - // don't know how to get the Python typename - std::string repr = "stir.Coordinate"; + // don't know how to get the Python typename + std::string repr = "stir.Coordinate"; #else - std::string repr = "$parentclasssymname"; + std::string repr = "$parentclasssymname"; #endif - // TODO attempt to re-use __str__ above, but it doesn't compile, so we replicate the code - // repr += $self->__str__() + ')'; - std::ostringstream s; - s<<"(("; - for (int d=1; d<=num_dimensions-1; ++d) - s << (*$self)[d] << ", "; - s << (*$self)[num_dimensions] << ')'; - repr += s.str() + ")"; - return repr; - } - - bool __nonzero__() const { - return true; - } - - /* Alias for Python 3 compatibility */ - bool __bool__() const { - return true; - } - - size_type __len__() const { - return $self->size(); - } + // TODO attempt to re-use __str__ above, but it doesn't compile, so we replicate the code + // repr += $self->__str__() + ')'; + std::ostringstream s; + s<<"(("; + for (int d=1; d<=num_dimensions-1; ++d) + s << (*$self)[d] << ", "; + s << (*$self)[num_dimensions] << ')'; + repr += s.str() + ")"; + return repr; + } + + bool __nonzero__() const { + return true; + } + + /* Alias for Python 3 compatibility */ + bool __bool__() const { + return true; + } + + size_type __len__() const { + return $self->size(); + } #if defined(SWIGPYTHON_BUILTIN) - %feature("python:slot", "tp_str", functype="reprfunc") __str__; - %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; - %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; - %feature("python:slot", "sq_length", functype="lenfunc") __len__; + %feature("python:slot", "tp_str", functype="reprfunc") __str__; + %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; + %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; + %feature("python:slot", "sq_length", functype="lenfunc") __len__; #endif // SWIGPYTHON_BUILTIN - - } + + } #elif defined(SWIGMATLAB) %extend BasicCoordinate { - // print as [1;2;3] as opposed to non-informative default provided by SWIG - void disp() - { - std::ostringstream s; - s<<'['; - for (int d=1; d<=num_dimensions-1; ++d) - s << (*$self)[d] << "; "; - s << (*$self)[num_dimensions] << "]\n"; - mexPrintf(s.str().c_str()); - - } - //%feature("autodoc", "construct from vector, e.g. [2;3;4] for a 3d coordinate") - BasicCoordinate(const mxArray *pm) - { - $parentclassname * array_ptr = new $parentclassname(); - swigstir::fill_BasicCoordinate_from_matlab(*array_ptr, pm); - return array_ptr; + // print as [1;2;3] as opposed to non-informative default provided by SWIG + void disp() + { + std::ostringstream s; + s<<'['; + for (int d=1; d<=num_dimensions-1; ++d) + s << (*$self)[d] << "; "; + s << (*$self)[num_dimensions] << "]\n"; + mexPrintf(s.str().c_str()); + + } + //%feature("autodoc", "construct from vector, e.g. [2;3;4] for a 3d coordinate") + BasicCoordinate(const mxArray *pm) + { + $parentclassname * array_ptr = new $parentclassname(); + swigstir::fill_BasicCoordinate_from_matlab(*array_ptr, pm); + return array_ptr; + } + + %newobject to_matlab; + mxArray * to_matlab() + { return swigstir::BasicCoordinate_to_matlab(*$self); } + + void fill(const mxArray *pm) + { swigstir::fill_BasicCoordinate_from_matlab(*$self, pm); } } - - %newobject to_matlab; - mxArray * to_matlab() - { return swigstir::BasicCoordinate_to_matlab(*$self); } - - void fill(const mxArray *pm) - { swigstir::fill_BasicCoordinate_from_matlab(*$self, pm); } - } - #endif // PYTHON, MATLAB extension of BasicCoordinate - - %ADD_indexaccess(int, coordT, BasicCoordinate); - %template(Int3BasicCoordinate) BasicCoordinate<3,int>; - %template(Size3BasicCoordinate) BasicCoordinate<3,std::size_t>; - %template(Float3BasicCoordinate) BasicCoordinate<3,float>; - %template(Float3Coordinate) Coordinate3D< float >; - %template(FloatCartesianCoordinate3D) CartesianCoordinate3D; - %template(IntCartesianCoordinate3D) CartesianCoordinate3D; - - %template(Int2BasicCoordinate) BasicCoordinate<2,int>; - %template(Size2BasicCoordinate) BasicCoordinate<2,std::size_t>; - %template(Float2BasicCoordinate) BasicCoordinate<2,float>; - // TODO not needed in python case? - %template(Float2Coordinate) Coordinate2D< float >; - %template(FloatCartesianCoordinate2D) CartesianCoordinate2D; - - //#ifndef SWIGPYTHON - // not necessary for Python as we can use tuples there - %template(make_IntCoordinate) make_coordinate; - %template(make_FloatCoordinate) make_coordinate; - //#endif - - %template(IndexRange1D) IndexRange<1>; - // %template(IndexRange1DVectorWithOffset) VectorWithOffset >; - %template(IndexRange2D) IndexRange<2>; - //%template(IndexRange2DVectorWithOffset) VectorWithOffset >; - %template(IndexRange3D) IndexRange<3>; - - %ADD_indexaccess(int,T,VectorWithOffset); - %template(FloatVectorWithOffset) VectorWithOffset; - - // TODO need to instantiate with name? - %template (FloatNumericVectorWithOffset) NumericVectorWithOffset; - +#endif // PYTHON, MATLAB extension of BasicCoordinate + + %ADD_indexaccess(int, coordT, BasicCoordinate); + %template(Int3BasicCoordinate) BasicCoordinate<3,int>; + %template(Size3BasicCoordinate) BasicCoordinate<3,std::size_t>; + %template(Float3BasicCoordinate) BasicCoordinate<3,float>; + %template(Float3Coordinate) Coordinate3D< float >; + %template(FloatCartesianCoordinate3D) CartesianCoordinate3D; + %template(IntCartesianCoordinate3D) CartesianCoordinate3D; + + %template(Int2BasicCoordinate) BasicCoordinate<2,int>; + %template(Size2BasicCoordinate) BasicCoordinate<2,std::size_t>; + %template(Float2BasicCoordinate) BasicCoordinate<2,float>; + // TODO not needed in python case? + %template(Float2Coordinate) Coordinate2D< float >; + %template(FloatCartesianCoordinate2D) CartesianCoordinate2D; + + //#ifndef SWIGPYTHON + // not necessary for Python as we can use tuples there + %template(make_IntCoordinate) make_coordinate; + %template(make_FloatCoordinate) make_coordinate; + //#endif + + %template(IndexRange1D) IndexRange<1>; + // %template(IndexRange1DVectorWithOffset) VectorWithOffset >; + %template(IndexRange2D) IndexRange<2>; + //%template(IndexRange2DVectorWithOffset) VectorWithOffset >; + %template(IndexRange3D) IndexRange<3>; + + %ADD_indexaccess(int,T,VectorWithOffset); + %template(FloatVectorWithOffset) VectorWithOffset; + + // TODO need to instantiate with name? + %template (FloatNumericVectorWithOffset) NumericVectorWithOffset; + #ifdef SWIGPYTHON - // TODO this extends ND-Arrays, but apparently not 1D Arrays (because specialised template?) - %extend Array{ - // add "flat" iterator, using begin_all() - %newobject flat(PyObject **PYTHON_SELF); - %feature("autodoc", "create a Python iterator over all elements, e.g. array.flat()") flat; - swig::SwigPyIterator* flat(PyObject **PYTHON_SELF) { - return swigstir::make_forward_iterator(self->begin_all(), self->begin_all(), self->end_all(), *PYTHON_SELF); - } - %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]") __getitem__; - elemT __getitem__(PyObject* const args) - { - stir::BasicCoordinate c; - if (!swigstir::coord_from_tuple(c, args)) - { - throw std::invalid_argument("Wrong type of indexing argument used"); - } - return (*$self).at(c); - }; - %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]=4") __setitem__; - void __setitem__(PyObject* const args, const elemT value) - { - stir::BasicCoordinate c; - if (!swigstir::coord_from_tuple(c, args)) - { - throw std::invalid_argument("Wrong type of indexing argument used"); - } - (*$self).at(c) = value; - }; - - %feature("autodoc", "return number of elements per dimension as a tuple, (almost) compatible with numpy. Use as array.shape()") shape; - const PyObject* shape() - { - //const stir::BasicCoordinate c = (*$self).shape(); - stir::BasicCoordinate minind,maxind; - if (!$self->get_regular_range(minind, maxind)) - throw std::range_error("shape called on irregular array"); - stir::BasicCoordinate sizes=maxind-minind+1; - return swigstir::tuple_from_coord(sizes); - } - - %feature("autodoc", "fill from a Python iterator, e.g. array.fill(numpyarray.flat)") fill; - void fill(PyObject* const arg) - { - if (PyIter_Check(arg)) - { - swigstir::fill_Array_from_Python_iterator($self, arg); - } - else - { - char str[1000]; - snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", - arg->ob_type->tp_name); - throw std::invalid_argument(str); - } + // TODO this extends ND-Arrays, but apparently not 1D Arrays (because specialised template?) + %extend Array{ + // add "flat" iterator, using begin_all() + %newobject flat(PyObject **PYTHON_SELF); + %feature("autodoc", "create a Python iterator over all elements, e.g. array.flat()") flat; + swig::SwigPyIterator* flat(PyObject **PYTHON_SELF) { + return swigstir::make_forward_iterator(self->begin_all(), self->begin_all(), self->end_all(), *PYTHON_SELF); + } + %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]") __getitem__; + elemT __getitem__(PyObject* const args) + { + stir::BasicCoordinate c; + if (!swigstir::coord_from_tuple(c, args)) + { + throw std::invalid_argument("Wrong type of indexing argument used"); + } + return (*$self).at(c); + }; + %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]=4") __setitem__; + void __setitem__(PyObject* const args, const elemT value) + { + stir::BasicCoordinate c; + if (!swigstir::coord_from_tuple(c, args)) + { + throw std::invalid_argument("Wrong type of indexing argument used"); + } + (*$self).at(c) = value; + }; + + %feature("autodoc", "return number of elements per dimension as a tuple, (almost) compatible with numpy. Use as array.shape()") shape; + const PyObject* shape() + { + //const stir::BasicCoordinate c = (*$self).shape(); + stir::BasicCoordinate minind,maxind; + if (!$self->get_regular_range(minind, maxind)) + throw std::range_error("shape called on irregular array"); + stir::BasicCoordinate sizes=maxind-minind+1; + return swigstir::tuple_from_coord(sizes); + } + + %feature("autodoc", "fill from a Python iterator, e.g. array.fill(numpyarray.flat)") fill; + void fill(PyObject* const arg) + { + if (PyIter_Check(arg)) + { + swigstir::fill_Array_from_Python_iterator($self, arg); + } + else + { + char str[1000]; + snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", + arg->ob_type->tp_name); + throw std::invalid_argument(str); + } + } } - } #endif - - %extend Array{ - %feature("autodoc", "return number of dimensions in the array") get_num_dimensions; - int get_num_dimensions() - { - return num_dimensions; + + %extend Array{ + %feature("autodoc", "return number of dimensions in the array") get_num_dimensions; + int get_num_dimensions() + { + return num_dimensions; + } } - } - + #ifdef SWIGMATLAB - %extend Array { - Array(const mxArray *pm) - { - $parentclassname * array_ptr = new $parentclassname(); - swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); - return array_ptr; - } - - %newobject to_matlab; - mxArray * to_matlab() - { return swigstir::Array_to_matlab(*$self); } - - void fill(const mxArray *pm) - { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } - } - // repeat this for 1D due to template (partial) specialisation (TODO, get round that somehow) - %extend Array<1,float> { - Array<1,float>(const mxArray *pm) - { - $parentclassname * array_ptr = new $parentclassname(); - swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); - return array_ptr; - } - - %newobject to_matlab; - mxArray * to_matlab() - { return swigstir::Array_to_matlab(*$self); } - - void fill(const mxArray *pm) - { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } - } + %extend Array { + Array(const mxArray *pm) + { + $parentclassname * array_ptr = new $parentclassname(); + swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); + return array_ptr; + } + + %newobject to_matlab; + mxArray * to_matlab() + { return swigstir::Array_to_matlab(*$self); } + + void fill(const mxArray *pm) + { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } + } + // repeat this for 1D due to template (partial) specialisation (TODO, get round that somehow) + %extend Array<1,float> { + Array<1,float>(const mxArray *pm) + { + $parentclassname * array_ptr = new $parentclassname(); + swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); + return array_ptr; + } + + %newobject to_matlab; + mxArray * to_matlab() + { return swigstir::Array_to_matlab(*$self); } + + void fill(const mxArray *pm) + { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } + } #endif - // TODO next line doesn't give anything useful as SWIG doesn't recognise that - // the return value is an array. So, we get a wrapped object that we cannot handle - //%ADD_indexaccess(int,Array::value_type, Array); - - %ADD_indexaccess(%arg(const BasicCoordinate&),elemT, Array); - - %template(FloatArray1D) Array<1,float>; - - // this doesn't work because of bug in swig (incorrectly parses num_dimensions) - //%ADD_indexaccess(int,%arg(Array), Array); - // In any case, even if the above is made to work (e.g. explicit override for every class as below) - // then setitem still doesn't modify the object for more than 1 level + // TODO next line doesn't give anything useful as SWIG doesn't recognise that + // the return value is an array. So, we get a wrapped object that we cannot handle + //%ADD_indexaccess(int,Array::value_type, Array); + + %ADD_indexaccess(%arg(const BasicCoordinate&),elemT, Array); + + %template(FloatArray1D) Array<1,float>; + + // this doesn't work because of bug in swig (incorrectly parses num_dimensions) + //%ADD_indexaccess(int,%arg(Array), Array); + // In any case, even if the above is made to work (e.g. explicit override for every class as below) + // then setitem still doesn't modify the object for more than 1 level #if 1 - // note: next line has no memory allocation problems because all Array<1,...> objects - // are auto-converted to shared_ptrs. - // however, cannot use setitem to modify so ideally we would define getitem only (at least for python) (TODO) - // TODO DISABLE THIS - %ADD_indexaccess(int,%arg(Array<1,float>),%arg(Array<2,float>)); + // note: next line has no memory allocation problems because all Array<1,...> objects + // are auto-converted to shared_ptrs. + // however, cannot use setitem to modify so ideally we would define getitem only (at least for python) (TODO) + // TODO DISABLE THIS + %ADD_indexaccess(int,%arg(Array<1,float>),%arg(Array<2,float>)); #endif - + } // namespace stir %rename (get_scanner) *::get_scanner_ptr; @@ -1254,16 +1255,16 @@ namespace stir { %rename (set_objective_function) *::set_objective_function_sptr; - // Todo need to instantiate with name? - // TODO Swig doesn't see that Array<2,float> is derived from it anyway becuse of num_dimensions bug +// Todo need to instantiate with name? +// TODO Swig doesn't see that Array<2,float> is derived from it anyway becuse of num_dimensions bug %template (FloatNumericVectorWithOffset2D) stir::NumericVectorWithOffset, float>; - %template(FloatArray2D) stir::Array<2,float>; - // TODO name - %template (FloatNumericVectorWithOffset3D) stir::NumericVectorWithOffset, float>; - %template(FloatArray3D) stir::Array<3,float>; +%template(FloatArray2D) stir::Array<2,float>; +// TODO name +%template (FloatNumericVectorWithOffset3D) stir::NumericVectorWithOffset, float>; +%template(FloatArray3D) stir::Array<3,float>; #if 0 - %ADD_indexaccess(int,%arg(stir::Array<2,float>),%arg(stir::Array<3,float>)); +%ADD_indexaccess(int,%arg(stir::Array<2,float>),%arg(stir::Array<3,float>)); #endif %template(Float3DDiscretisedDensity) stir::DiscretisedDensity<3,float>; @@ -1272,6 +1273,8 @@ namespace stir { //%template() stir::DiscretisedDensityOnCartesianGrid<3,float>; %template(FloatVoxelsOnCartesianGrid) stir::VoxelsOnCartesianGrid; +%include "stir/IO/write_to_file.h" +%template(write_image_to_file) stir::write_to_file >; #ifdef STIRSWIG_SHARED_PTR #define DataT stir::DiscretisedDensity<3,float> @@ -1290,17 +1293,17 @@ namespace stir { #define DataT stir::DiscretisedDensity<3,float> %template(Float3DDiscretisedDensityOutputFileFormat) stir::OutputFileFormat; - //cannot do that as pure virtual functions - //%template(ROOutputFileFormat3DFloat) RegisteredObject< OutputFileFormat< DiscretisedDensity< 3,float > > >; - %template(RPInterfileOutputFileFormat) stir::RegisteredParsingObject, stir::OutputFileFormat >; - #undef DataT +//cannot do that as pure virtual functions +//%template(ROOutputFileFormat3DFloat) RegisteredObject< OutputFileFormat< DiscretisedDensity< 3,float > > >; +%template(RPInterfileOutputFileFormat) stir::RegisteredParsingObject, stir::OutputFileFormat >; +#undef DataT %include "stir/IO/InterfileOutputFileFormat.h" #ifdef HAVE_LLN_MATRIX %include "stir/IO/ECAT7OutputFileFormat.h" #endif - /* Now do ProjDataInfo, Sinogram et al +/* Now do ProjDataInfo, Sinogram et al */ %include "stir/TimeFrameDefinitions.h" %include "stir/ExamInfo.h" @@ -1323,25 +1326,25 @@ namespace stir { %include "stir/ProjDataInfo.h" %newobject *::construct_proj_data_info; -%extend stir::ProjDataInfo +%extend stir::ProjDataInfo { - // work around the current SWIG limitation that it doesn't wrap unique_ptr. - // we do this with the crazy (and ugly) way to let SWIG create a new function - // which is the same as the original, but returns a bare pointer. - // (This will be wrapped as a shared_ptr in the end). - // This work-around is fragile however as it depends on knowledge of the - // exact signature of the function. - static ProjDataInfo * - construct_proj_data_info(const shared_ptr& scanner_sptr, - const int span, const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected = true) - { - return - construct_proj_data_info(scanner_sptr, - span, max_delta, num_views, num_tangential_poss, - arc_corrected).get(); - } + // work around the current SWIG limitation that it doesn't wrap unique_ptr. + // we do this with the crazy (and ugly) way to let SWIG create a new function + // which is the same as the original, but returns a bare pointer. + // (This will be wrapped as a shared_ptr in the end). + // This work-around is fragile however as it depends on knowledge of the + // exact signature of the function. + static ProjDataInfo * + construct_proj_data_info(const shared_ptr& scanner_sptr, + const int span, const int max_delta, + const int num_views, const int num_tangential_poss, + const bool arc_corrected = true) + { + return + construct_proj_data_info(scanner_sptr, + span, max_delta, num_views, num_tangential_poss, + arc_corrected).get(); + } } %include "stir/ProjDataInfoCylindrical.h" %include "stir/ProjDataInfoCylindricalArcCorr.h" @@ -1357,68 +1360,68 @@ namespace stir { %include "stir/ProjData.h" namespace stir { -%extend ProjData - { -#ifdef SWIGPYTHON - %feature("autodoc", "create a stir 3D Array from the projection data (internal)") to_array; - %newobject to_array; - Array<3,float> to_array() - { - Array<3,float> array = swigstir::projdata_to_3D(*$self); - return array; - } - - %feature("autodoc", "fill from a Python iterator, e.g. proj_data.fill(numpyarray.flat)") fill; - void fill(PyObject* const arg) + %extend ProjData { - if (PyIter_Check(arg)) - { - Array<3,float> array = swigstir::create_array_for_proj_data(*$self); - swigstir::fill_Array_from_Python_iterator(&array, arg); - swigstir::fill_proj_data_from_3D(*$self, array); - } - else - { - char str[1000]; - snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", - arg->ob_type->tp_name); - throw std::invalid_argument(str); - } - } - +#ifdef SWIGPYTHON + %feature("autodoc", "create a stir 3D Array from the projection data (internal)") to_array; + %newobject to_array; + Array<3,float> to_array() + { + Array<3,float> array = swigstir::projdata_to_3D(*$self); + return array; + } + + %feature("autodoc", "fill from a Python iterator, e.g. proj_data.fill(numpyarray.flat)") fill; + void fill(PyObject* const arg) + { + if (PyIter_Check(arg)) + { + Array<3,float> array = swigstir::create_array_for_proj_data(*$self); + swigstir::fill_Array_from_Python_iterator(&array, arg); + swigstir::fill_proj_data_from_3D(*$self, array); + } + else + { + char str[1000]; + snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", + arg->ob_type->tp_name); + throw std::invalid_argument(str); + } + } + #elif defined(SWIGMATLAB) - %newobject to_matlab; - mxArray * to_matlab() - { - Array<3,float> array = swigstir::projdata_to_3D(*$self); - return swigstir::Array_to_matlab(array); - } - - void fill(const mxArray *pm) - { - Array<3,float> array; - swigstir::fill_Array_from_matlab(array, pm, true); - swigstir::fill_proj_data_from_3D(*$self, array); - } + %newobject to_matlab; + mxArray * to_matlab() + { + Array<3,float> array = swigstir::projdata_to_3D(*$self); + return swigstir::Array_to_matlab(array); + } + + void fill(const mxArray *pm) + { + Array<3,float> array; + swigstir::fill_Array_from_matlab(array, pm, true); + swigstir::fill_proj_data_from_3D(*$self, array); + } #endif - } - } + } +} %include "stir/ProjDataFromStream.h" %include "stir/ProjDataInterfile.h" %include "stir/ProjDataInMemory.h" -namespace stir { - %template(FloatViewgram) Viewgram; - %template(FloatSinogram) Sinogram; - // TODO don't want to give a name - %template(FloatSegment) Segment; - %template(FloatSegmentBySinogram) SegmentBySinogram; - %template(FloatSegmentByView) SegmentByView; - // should not have the following if using boost_smart_ptr.i - // %template(SharedScanner) boost::shared_ptr; - //%template(SharedProjData) boost::shared_ptr; - +namespace stir { + %template(FloatViewgram) Viewgram; + %template(FloatSinogram) Sinogram; + // TODO don't want to give a name + %template(FloatSegment) Segment; + %template(FloatSegmentBySinogram) SegmentBySinogram; + %template(FloatSegmentByView) SegmentByView; + // should not have the following if using boost_smart_ptr.i + // %template(SharedScanner) boost::shared_ptr; + //%template(SharedProjData) boost::shared_ptr; + } // filters @@ -1426,13 +1429,13 @@ namespace stir { #define elemT float %shared_ptr(stir::DataProcessor >) %shared_ptr(stir::RegisteredParsingObject< - stir::ChainedDataProcessor >, - stir::DataProcessor >, - stir::DataProcessor > >) + stir::ChainedDataProcessor >, + stir::DataProcessor >, + stir::DataProcessor > >) %shared_ptr(stir::ChainedDataProcessor >) %shared_ptr(stir::RegisteredParsingObject, - stir::DataProcessor >, - stir::DataProcessor > >) + stir::DataProcessor >, + stir::DataProcessor > >) %shared_ptr(stir::SeparableCartesianMetzImageFilter) #undef elemT #endif @@ -1444,29 +1447,29 @@ namespace stir { #define elemT float %template(DataProcessor3DFloat) stir::DataProcessor >; %template(RPChainedDataProcessor3DFloat) stir::RegisteredParsingObject< - stir::ChainedDataProcessor >, - stir::DataProcessor >, - stir::DataProcessor > >; +stir::ChainedDataProcessor >, +stir::DataProcessor >, +stir::DataProcessor > >; %template(ChainedDataProcessor3DFloat) stir::ChainedDataProcessor >; %template(RPSeparableCartesianMetzImageFilter3DFloat) stir::RegisteredParsingObject< - stir::SeparableCartesianMetzImageFilter, - stir::DataProcessor >, - stir::DataProcessor > >; +stir::SeparableCartesianMetzImageFilter, +stir::DataProcessor >, +stir::DataProcessor > >; %template(SeparableCartesianMetzImageFilter3DFloat) stir::SeparableCartesianMetzImageFilter; #undef elemT %include "stir/GeneralisedPoissonNoiseGenerator.h" - // reconstruction +// reconstruction #ifdef STIRSWIG_SHARED_PTR #define TargetT stir::DiscretisedDensity<3,float> %shared_ptr(stir::GeneralisedObjectiveFunction); %shared_ptr(stir::PoissonLogLikelihoodWithLinearModelForMean); %shared_ptr(stir::RegisteredParsingObject, - stir::GeneralisedObjectiveFunction, - stir::PoissonLogLikelihoodWithLinearModelForMean >); + stir::GeneralisedObjectiveFunction, + stir::PoissonLogLikelihoodWithLinearModelForMean >); %shared_ptr(stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData); @@ -1474,14 +1477,14 @@ namespace stir { %shared_ptr(stir::IterativeReconstruction); %shared_ptr(stir::RegisteredParsingObject< - stir::OSMAPOSLReconstruction , - stir::Reconstruction < TargetT >, - stir::IterativeReconstruction < TargetT > + stir::OSMAPOSLReconstruction , + stir::Reconstruction < TargetT >, + stir::IterativeReconstruction < TargetT > >) %shared_ptr(stir::RegisteredParsingObject< - stir::OSSPSReconstruction , - stir::Reconstruction < TargetT >, - stir::IterativeReconstruction < TargetT > + stir::OSSPSReconstruction , + stir::Reconstruction < TargetT >, + stir::IterativeReconstruction < TargetT > >) %shared_ptr(stir::OSMAPOSLReconstruction); @@ -1500,7 +1503,7 @@ namespace stir { %include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" %include "stir/recon_buildblock/Reconstruction.h" - // there's a get_objective_function, so we'll ignore the sptr version +// there's a get_objective_function, so we'll ignore the sptr version %ignore *::get_objective_function_sptr; %include "stir/recon_buildblock/IterativeReconstruction.h" %include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" @@ -1521,18 +1524,18 @@ namespace stir { // Without it we don't see the parsing functions in python... // Note: we cannot start it with __ as then we we get a run-time error when we're not using the builtin option %template(RPPoissonLogLikelihoodWithLinearModelForMeanAndProjData3DFloat) stir::RegisteredParsingObject, - stir::GeneralisedObjectiveFunction, - stir::PoissonLogLikelihoodWithLinearModelForMean >; +stir::GeneralisedObjectiveFunction, +stir::PoissonLogLikelihoodWithLinearModelForMean >; %template (PoissonLogLikelihoodWithLinearModelForMeanAndProjData3DFloat) stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData; %inline %{ - template + template stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData * ToPoissonLogLikelihoodWithLinearModelForMeanAndProjData(stir::GeneralisedObjectiveFunction *b) { - return dynamic_cast*>(b); -} -%} + return dynamic_cast*>(b); + } + %} %template(ToPoissonLogLikelihoodWithLinearModelForMeanAndProjData3DFloat) ToPoissonLogLikelihoodWithLinearModelForMeanAndProjData; @@ -1543,15 +1546,15 @@ namespace stir { //%template () stir::IterativeReconstruction; %template (RPOSMAPOSLReconstruction3DFloat) stir::RegisteredParsingObject< - stir::OSMAPOSLReconstruction , - stir::Reconstruction < TargetT >, - stir::IterativeReconstruction < TargetT > - >; +stir::OSMAPOSLReconstruction , +stir::Reconstruction < TargetT >, +stir::IterativeReconstruction < TargetT > +>; %template (RPOSSPSReconstruction) stir::RegisteredParsingObject< - stir::OSSPSReconstruction , - stir::Reconstruction < TargetT >, - stir::IterativeReconstruction < TargetT > - >; +stir::OSSPSReconstruction , +stir::Reconstruction < TargetT >, +stir::IterativeReconstruction < TargetT > +>; %template (OSMAPOSLReconstruction3DFloat) stir::OSMAPOSLReconstruction; %template (OSSPSReconstruction3DFloat) stir::OSSPSReconstruction; @@ -1561,18 +1564,18 @@ namespace stir { /// projectors %shared_ptr(stir::ForwardProjectorByBin); %shared_ptr(stir::RegisteredParsingObject); + stir::ForwardProjectorByBin>); %shared_ptr(stir::ForwardProjectorByBinUsingProjMatrixByBin); %shared_ptr(stir::BackProjectorByBin); %shared_ptr(stir::RegisteredParsingObject); + stir::BackProjectorByBin>); %shared_ptr(stir::BackProjectorByBinUsingProjMatrixByBin); %shared_ptr(stir::ProjMatrixByBin); %shared_ptr(stir::RegisteredParsingObject< - stir::ProjMatrixByBinUsingRayTracing, - stir::ProjMatrixByBin, - stir::ProjMatrixByBin - >); + stir::ProjMatrixByBinUsingRayTracing, + stir::ProjMatrixByBin, + stir::ProjMatrixByBin + >); %shared_ptr(stir::ProjMatrixByBinUsingRayTracing); %include "stir/recon_buildblock/ForwardProjectorByBin.h" @@ -1581,30 +1584,31 @@ namespace stir { %include "stir/recon_buildblock/ProjMatrixByBin.h" %template (internalRPProjMatrixByBinUsingRayTracing) stir::RegisteredParsingObject< - stir::ProjMatrixByBinUsingRayTracing, - stir::ProjMatrixByBin, - stir::ProjMatrixByBin - >; +stir::ProjMatrixByBinUsingRayTracing, +stir::ProjMatrixByBin, +stir::ProjMatrixByBin +>; %include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" %shared_ptr( stir::AddParser); %template (internalAddParserForwardProjectorByBin) - stir::AddParser; -%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) - stir::RegisteredParsingObject; +stir::AddParser; +%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) +stir::RegisteredParsingObject; %include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" %shared_ptr( stir::AddParser); %template (internalAddParserBackProjectorByBin) - stir::AddParser; -%template (internalRPBackProjectorByBinUsingProjMatrixByBin) - stir::RegisteredParsingObject; +stir::AddParser; +%template (internalRPBackProjectorByBinUsingProjMatrixByBin) +stir::RegisteredParsingObject; %include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" + //scatter %shared_ptr(stir::ScatterSimulation); @@ -1613,19 +1617,22 @@ namespace stir { stir::ScatterSimulation, stir::ScatterSimulation >); -%shared_ptr(stir::SingleScatterSimulation); +%shared_ptr(stir::SingleScatterSimulation); -%shared_ptr(stir::RegisteredParsingObject< +shared_ptr(stir::RegisteredParsingObject< stir::SingleScatterLikelihoodAndGradient, stir::SingleScatterSimulation, stir::SingleScatterSimulation >); -%shared_ptr(stir::SingleScatterSimulation); + %shared_ptr(stir::SingleScatterLikelihoodAndGradient); + %include "stir/scatter/ScatterSimulation.h" +%include "stir/scatter/SingleScatterSimulation.h" +%include "stir/scatter/SingleScatterLikelihoodAndGradient.h" %template (internalRPSingleScatterSimulation) stir::RegisteredParsingObject< stir::SingleScatterSimulation, @@ -1634,12 +1641,7 @@ stir::ScatterSimulation >; -%template (internalRPSingleScatterSimulation) stir::RegisteredParsingObject< -stir::SingleScatterLikelihoodAndGradient, -stir::SingleScatterSimulation, -stir::SingleScatterSimulation ->; -%include "stir/scatter/SingleScatterSimulation.h" -%include "stir/scatter/SingleScatterLikelihoodAndGradient.h" + + diff --git a/src/swig/stirextra.py b/src/swig/stirextra.py index 341293782e..e8b0ee3dc1 100644 --- a/src/swig/stirextra.py +++ b/src/swig/stirextra.py @@ -24,8 +24,8 @@ def get_bounding_box_indices(image): """ - return [min,max] tuple with indices of first and last voxel in a STIR image - """ + return [min,max] tuple with indices of first and last voxel in a STIR image + """ num_dims = image.get_num_dimensions(); if num_dims == 2: minind=stir.Int2BasicCoordinate() @@ -35,14 +35,14 @@ def get_bounding_box_indices(image): maxind=stir.Int3BasicCoordinate() else: raise exceptions.NotImplementedError('need to handle dimensions different from 2 and 3') - + image.get_regular_range(minind, maxind); return [minind, maxind] def get_physical_coordinates_for_bounding_box(image): """ - return physical coordinates (in mm) for the first and last voxel in a STIR image - """ + return physical coordinates (in mm) for the first and last voxel in a STIR image + """ [minind,maxind]=get_bounding_box_indices(image); minphys=image.get_physical_coordinates_for_indices(minind); maxphys=image.get_physical_coordinates_for_indices(maxind); @@ -50,8 +50,8 @@ def get_physical_coordinates_for_bounding_box(image): def get_physical_coordinates_for_grid(image): """ - return [z,y,x] tuple of grid coordinates for a STIR image - """ + return [z,y,x] tuple of grid coordinates for a STIR image + """ [minind,maxind]=get_bounding_box_indices(image); sizes=maxind-minind+1; minphys=image.get_physical_coordinates_for_indices(minind); @@ -68,8 +68,8 @@ def get_physical_coordinates_for_grid(image): def to_numpy(stirdata): """ - return the data in a STIR image or other Array as a numpy array - """ + return the data in a STIR image or other Array as a numpy array + """ # construct a numpy array using the "flat" STIR iterator try: npstirdata=numpy.fromiter(stirdata.flat(), dtype=numpy.float32); From 964cdb8da956c81a59224b6cbb5d5a7340d7301a Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 8 Jun 2018 22:48:08 +0100 Subject: [PATCH 009/274] comm --- src/include/stir/scatter/ScatterEstimation.h | 12 +++ .../SingleScatterLikelihoodAndGradient.h | 23 ++++-- .../stir/scatter/SingleScatterSimulation.h | 3 +- .../LikelihoodAndGradient.cxx | 20 ++--- .../LikelihoodAndGradientEstimate.cxx | 21 ++++-- ...dAndGradientEstimateForOneScatterPoint.cxx | 75 ++++++++++--------- .../SingleScatterLikelihoodAndGradient.cxx | 58 ++++++++++++++ .../upsample_and_fit_scatter_estimate.cxx | 33 ++++++++ src/swig/stir.i | 5 +- 9 files changed, 187 insertions(+), 63 deletions(-) diff --git a/src/include/stir/scatter/ScatterEstimation.h b/src/include/stir/scatter/ScatterEstimation.h index 00e04d7390..b650f7aa12 100644 --- a/src/include/stir/scatter/ScatterEstimation.h +++ b/src/include/stir/scatter/ScatterEstimation.h @@ -93,6 +93,18 @@ class ScatterEstimation: public ParsingObject const bool remove_interleaving = true); + static void + upsample_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + //BinNormalisation& scatter_normalisation, + // const ProjData& weights_proj_data, + //const float min_scale_factor, + //const float max_scale_factor, + //const unsigned half_filter_width, + //BSpline::BSplineType spline_type, + const bool remove_interleaving = true); + //! Default constructor (calls set_defaults()) ScatterEstimation(); diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 4eb74a2103..6bb5e24afc 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -60,7 +60,20 @@ class SingleScatterLikelihoodAndGradient : public - virtual double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float scale , bool isgradient = true); + virtual double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale , bool isgradient = true); + + + + void initialise(const std::string& parameter_filename); + + virtual void set_defaults(); + virtual void initialise_keymap(); + virtual void ask_parameters(); + virtual Succeeded set_up(); + + //! used to check acceptable parameter ranges, etc... + virtual bool post_processing(); + protected: @@ -82,16 +95,16 @@ class SingleScatterLikelihoodAndGradient : public virtual double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool isgradient); - virtual void + /*virtual void actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, double& scatter_ratio_singles, const unsigned det_num_A, - const unsigned det_num_B, bool isgradient); + const unsigned det_num_B, bool isgradient);*/ - virtual double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float scale_factor, bool isgradient); + virtual double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool isgradient); - virtual double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float scale_factor, bool isgradient); + virtual double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool isgradient); diff --git a/src/include/stir/scatter/SingleScatterSimulation.h b/src/include/stir/scatter/SingleScatterSimulation.h index 791e974ad0..b29b93e101 100644 --- a/src/include/stir/scatter/SingleScatterSimulation.h +++ b/src/include/stir/scatter/SingleScatterSimulation.h @@ -65,7 +65,7 @@ class SingleScatterSimulation : public //! prompts the user to enter parameter values manually virtual void ask_parameters(); -protected: + void initialise(const std::string& parameter_filename); @@ -77,6 +77,7 @@ class SingleScatterSimulation : public //! used to check acceptable parameter ranges, etc... virtual bool post_processing(); +protected: //! //! \brief simulate_for_one_scatter_point diff --git a/src/scatter_buildblock/LikelihoodAndGradient.cxx b/src/scatter_buildblock/LikelihoodAndGradient.cxx index b7049a2316..ccbd50bc87 100644 --- a/src/scatter_buildblock/LikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/LikelihoodAndGradient.cxx @@ -86,6 +86,7 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const int bin_counter = 0; int axial_bins = 0 ; + double sum = 0; for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); @@ -120,7 +121,6 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const #endif this->shift_detector_coordinates_to_origin = CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - float sum = 0 ; info("ScatterSimulator: Initialization finished ..."); @@ -132,28 +132,20 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); ++vs_num.view_num()) { - info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,isgradient); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + std::cout<< bin_counter << " / "<< total_bins <(total_detectors)) - { - warning("Expected num detectors: %d, but found %d\n", - total_detectors, detection_points_vector.size()); - return Succeeded::no; - } - - std::cerr << "LIKELIHOOD:= " << sum << '\n'; - return Succeeded::yes; + return sum; } double @@ -196,7 +188,7 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes } // now compute scatter for all bins - double sum =0; + double sum = 0; VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); diff --git a/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx b/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx index 6914fdeadd..c051a51e44 100644 --- a/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx +++ b/src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx @@ -45,14 +45,25 @@ L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, boo this->find_detectors(det_num_A, det_num_B,bin); - this->actual_L_G_estimate(gradient_image_bin, scatter_ratio_singles, - det_num_A, - det_num_B, isgradient); + for(std::size_t scatter_point_num =0; + scatter_point_num < this->scatt_points_vector.size(); + ++scatter_point_num) + { + + + + + scatter_ratio_singles += + L_G_for_one_scatter_point(gradient_image_bin, + scatter_point_num, + det_num_A, det_num_B, isgradient); + + } return scatter_ratio_singles; } -void +/*void SingleScatterLikelihoodAndGradient:: actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, double& scatter_ratio_singles, @@ -79,7 +90,7 @@ actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, } -} +}*/ END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx b/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx index 85a2638ef2..67d844fad7 100644 --- a/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx +++ b/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx @@ -246,50 +246,51 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, float scatter_ratio=0; - scatter_ratio= - (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + scatter_ratio= (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; /*Single Scatter Forward model Jacobian: * The derivative is given by three term, respectively in [A,S], [B,S] and [S] */ float contribution_AS = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - total_Compton_cross_section_relative_to_511keV(new_energy)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - float contribution_BS = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - (total_Compton_cross_section_relative_to_511keV(new_energy)) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* + total_Compton_cross_section_relative_to_511keV(new_energy)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + float contribution_BS = (detection_probability_XY*emiss_to_detA* + (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* + (total_Compton_cross_section_relative_to_511keV(new_energy)) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* + pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; float contribution_S = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; //Fill gradient image along [A,S], [B,S] and in [S] diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index f2198ba7ea..09448d3b87 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -40,7 +40,65 @@ SingleScatterLikelihoodAndGradient:: ~SingleScatterLikelihoodAndGradient() {} +void +SingleScatterLikelihoodAndGradient:: +initialise_keymap() +{ + base_type::initialise_keymap(); + // this->parser.add_start_key("Single Scatter Simulation"); + // this->parser.add_stop_key("end Single Scatter Simulation"); +} + +void +SingleScatterLikelihoodAndGradient:: +initialise(const std::string& parameter_filename) +{ + if (parameter_filename.size() == 0) + { + this->set_defaults(); + this->ask_parameters(); + } + else + { + this->set_defaults(); + if (!this->parse(parameter_filename.c_str())) + { + error("Error parsing input file %s, exiting", parameter_filename.c_str()); + } + } +} + +void +SingleScatterLikelihoodAndGradient:: +set_defaults() +{ + base_type::set_defaults(); +} + +Succeeded +SingleScatterLikelihoodAndGradient:: +set_up() +{ + return base_type::set_up(); +} + + + +void +SingleScatterLikelihoodAndGradient:: +ask_parameters() +{ + base_type::ask_parameters(); +} +bool +SingleScatterLikelihoodAndGradient:: +post_processing() +{ + if (!base_type::post_processing()) + return false; + return true; +} END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 2ac495f164..c1753d3da0 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -122,4 +122,37 @@ upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, } } + +void +ScatterEstimation:: +upsample_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + //BinNormalisation& scatter_normalisation, + // const ProjData& weights_proj_data, + //const float min_scale_factor, + //const float max_scale_factor, + //const unsigned half_filter_width, + //BSpline::BSplineType spline_type, + const bool remove_interleaving) +{ + stir::BSpline::BSplineType spline_type = stir::BSpline::linear; + shared_ptr + interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + + interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); + + + + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + +} + + END_NAMESPACE_STIR diff --git a/src/swig/stir.i b/src/swig/stir.i index d30638d03b..80983af09a 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -98,6 +98,7 @@ #include "stir/scatter/ScatterSimulation.h" #include "stir/scatter/SingleScatterSimulation.h" #include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/scatter/ScatterEstimation.h" // TODO need this (bug in swig) // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace @@ -1642,6 +1643,8 @@ stir::ScatterSimulation - +%shared_ptr(stir::ScatterEstimation); +%shared_ptr(stir::ParsingObject); +%include "stir/scatter/ScatterEstimation.h" From 4663282c88031926c841df04bc557f523626e05e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 12 Jun 2018 21:51:17 +0100 Subject: [PATCH 010/274] energy_check --- src/include/stir/scatter/ScatterSimulation.h | 1 + .../SingleScatterLikelihoodAndGradient.h | 17 ++- .../LikelihoodAndGradient.cxx | 7 ++ src/scatter_buildblock/ScatterSimulation.cxx | 3 + .../SingleScatterLikelihoodAndGradient.cxx | 60 +---------- .../scatter_detection_modelling.cxx | 6 +- ...scatter_estimate_for_one_scatter_point.cxx | 7 ++ .../scatter_likelihood_and_gradient.cxx | 102 ++++++++++++++++++ 8 files changed, 131 insertions(+), 72 deletions(-) create mode 100644 src/scatter_utilities/scatter_likelihood_and_gradient.cxx diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 5e9b287083..739635dca5 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -103,6 +103,7 @@ class ScatterSimulation : public RegisteredObject, virtual Succeeded process_data(); + //! gives method information virtual std::string method_info() const = 0; diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 6bb5e24afc..133ae8cd93 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -46,6 +46,8 @@ class SingleScatterLikelihoodAndGradient : public SingleScatterSimulation> base_type; public: + + //! Name which will be used when parsing a ScatterSimulation object static const char * const registered_name; @@ -60,19 +62,12 @@ class SingleScatterLikelihoodAndGradient : public - virtual double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale , bool isgradient = true); + double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale , bool isgradient = true); void initialise(const std::string& parameter_filename); - virtual void set_defaults(); - virtual void initialise_keymap(); - virtual void ask_parameters(); - virtual Succeeded set_up(); - - //! used to check acceptable parameter ranges, etc... - virtual bool post_processing(); protected: @@ -93,7 +88,7 @@ class SingleScatterLikelihoodAndGradient : public const unsigned det_num_A, const unsigned det_num_B, bool isgradient); - virtual double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool isgradient); + double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool isgradient); /*virtual void actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, @@ -102,9 +97,9 @@ class SingleScatterLikelihoodAndGradient : public const unsigned det_num_B, bool isgradient);*/ - virtual double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool isgradient); + double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool isgradient); - virtual double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool isgradient); + double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool isgradient); diff --git a/src/scatter_buildblock/LikelihoodAndGradient.cxx b/src/scatter_buildblock/LikelihoodAndGradient.cxx index ccbd50bc87..4aba36fad2 100644 --- a/src/scatter_buildblock/LikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/LikelihoodAndGradient.cxx @@ -52,6 +52,8 @@ double SingleScatterLikelihoodAndGradient:: L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale, bool isgradient) { + + // this is usefull in the scatter estimation process. this->output_proj_data_sptr->fill(0.f); //show energy window information @@ -133,7 +135,10 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const ++vs_num.view_num()) { //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,isgradient); + bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); @@ -152,6 +157,7 @@ double SingleScatterLikelihoodAndGradient:: L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool isgradient) { + Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); @@ -223,4 +229,5 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes } + END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 5acde9e035..acddf30925 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -613,4 +613,7 @@ set_cache_enabled(const bool arg) use_cache = arg; } + + + END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 09448d3b87..ead382b35b 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -30,6 +30,8 @@ SingleScatterLikelihoodAndGradient() : this->set_defaults(); } + + SingleScatterLikelihoodAndGradient:: SingleScatterLikelihoodAndGradient(const std::string& parameter_filename) { @@ -40,65 +42,7 @@ SingleScatterLikelihoodAndGradient:: ~SingleScatterLikelihoodAndGradient() {} -void -SingleScatterLikelihoodAndGradient:: -initialise_keymap() -{ - base_type::initialise_keymap(); - // this->parser.add_start_key("Single Scatter Simulation"); - // this->parser.add_stop_key("end Single Scatter Simulation"); -} - -void -SingleScatterLikelihoodAndGradient:: -initialise(const std::string& parameter_filename) -{ - if (parameter_filename.size() == 0) - { - this->set_defaults(); - this->ask_parameters(); - } - else - { - this->set_defaults(); - if (!this->parse(parameter_filename.c_str())) - { - error("Error parsing input file %s, exiting", parameter_filename.c_str()); - } - } -} - -void -SingleScatterLikelihoodAndGradient:: -set_defaults() -{ - base_type::set_defaults(); -} - -Succeeded -SingleScatterLikelihoodAndGradient:: -set_up() -{ - return base_type::set_up(); -} - -void -SingleScatterLikelihoodAndGradient:: -ask_parameters() -{ - base_type::ask_parameters(); -} - -bool -SingleScatterLikelihoodAndGradient:: -post_processing() -{ - if (!base_type::post_processing()) - return false; - return true; -} - END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index c7583d04e4..bb49e19d4e 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -138,10 +138,10 @@ detection_efficiency_no_scatter(const unsigned det_num_A, { // TODO: slightly dangerous to use a static here // it would give wrong results when the energy_thresholds are changed... - static const float detector_efficiency_no_scatter = - detection_efficiency(511.F, en_window) > 0 + static const float detector_efficiency_no_scatter = 1 ; + /*detection_efficiency(511.F, en_window) > 0 ? detection_efficiency(511.F, en_window) - : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F); + : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F);*/ const CartesianCoordinate3D& detector_coord_A = detection_points_vector[det_num_A]; diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index d9d9bf6d11..ffd6adbb5d 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -73,10 +73,17 @@ SingleScatterSimulation:: { low = first_window; } + else if(this->template_exam_info_sptr->get_low_energy_thres(first_window) >= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) + { + low = second_window; + } + //std::cerr << "low:= "<< low<< '\n'; } + + static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), 2.f, this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); diff --git a/src/scatter_utilities/scatter_likelihood_and_gradient.cxx b/src/scatter_utilities/scatter_likelihood_and_gradient.cxx new file mode 100644 index 0000000000..13ebd73825 --- /dev/null +++ b/src/scatter_utilities/scatter_likelihood_and_gradient.cxx @@ -0,0 +1,102 @@ +// +// +/* + Copyright (C) 2016, UCL + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +/*! + \file + \ingroup utilities + \ingroup scatter + \brief Simulates a coarse scatter sinogram + + \author Nikos Efthimiou + + \par Usage: + \code + simulate_scatter parfile + \endcode + See stir::ScatterSimulation documentation for the format + of the parameter file. +*/ + +#include "stir/scatter/ScatterSimulation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h".h" +#include "stir/Succeeded.h" +#include "stir/CPUTimer.h" +#include "stir/HighResWallClockTimer.h" +#include "stir/IO/read_from_file.h" + +using std::cerr; +using std::cout; +using std::endl; + +static void print_usage_and_exit() +{ + std::cerr<<"This executable runs a Scatter simulation method based on the options " + "in a parameter file"; + std::cerr<<"\nUsage:\n simulate_scatter scatter_simulation.par\n"; + std::cerr<<"Example parameter file:\n\n" + "Scatter Simulation :=\n" + "Simulation method := Single Scatter Simulation\n" + "Scatter Simulation Parameters :=\n" + " template projdata filename :=\n" + "attenuation image filename := \n" + "attenuation image for scatter points filename := \n" + "activity image filename :=\n" + "output filename prefix := ${OUTPUT_PREFIX}\n" + " scatter level := 1\n" + "attenuation threshold := 0.01\n" + "random := 1\n" + "use cache := 1\n" + "End Scatter Simulation Parameters :=\n" + "End Scatter Simulation:="<< std::endl; + exit(EXIT_FAILURE); +} +/***********************************************************/ + +int main(int argc, const char *argv[]) +{ + USING_NAMESPACE_STIR + + HighResWallClockTimer t; + t.reset(); + t.start(); + + if (argc!=2) + print_usage_and_exit(); + + shared_ptr < SingleScatterLikelihoodAndGradient > + simulation_method_sptr; + + KeyParser parser; + parser.add_start_key("Scatter Simulation"); + parser.add_stop_key("End Scatter Simulation"); + parser.add_parsing_key("Simulation method", &simulation_method_sptr); + parser.parse(argv[1]); + + shared_ptr data = ProjData::read_from_file("simulated_scatter_sino.hs"); + const float rescale = 1; + shared_ptr > a(read_from_file >("initial_atn_image_LR.hv")); + VoxelsOnCartesianGrid& gradient_image = dynamic_cast< VoxelsOnCartesianGrid& > (*a); + gradient_image.fill(0); + + double g= simulation_method_sptr->L_G_function(*data,gradient_image, rescale, false); + + t.stop(); + cout << "Total Wall clock timetime: " << t.value() << " seconds" << endl; + return EXIT_SUCCESS; +} + From 527b953faf28c7468f0ec03e33935ac5b9d3e9ce Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 12 Jun 2018 22:02:00 +0100 Subject: [PATCH 011/274] one_script --- .../SingleScatterLikelihoodAndGradient.h | 2 +- src/scatter_buildblock/CMakeLists.txt | 3 - .../LikelihoodAndGradient.cxx | 233 -------- .../LikelihoodAndGradientEstimate.cxx | 96 ---- ...dAndGradientEstimateForOneScatterPoint.cxx | 314 ----------- .../SingleScatterLikelihoodAndGradient.cxx | 497 ++++++++++++++++++ src/scatter_utilities/CMakeLists.txt | 1 + 7 files changed, 499 insertions(+), 647 deletions(-) delete mode 100644 src/scatter_buildblock/LikelihoodAndGradient.cxx delete mode 100644 src/scatter_buildblock/LikelihoodAndGradientEstimate.cxx delete mode 100644 src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 133ae8cd93..c5bc0c7e58 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -66,7 +66,7 @@ class SingleScatterLikelihoodAndGradient : public - void initialise(const std::string& parameter_filename); + //void initialise(const std::string& parameter_filename); diff --git a/src/scatter_buildblock/CMakeLists.txt b/src/scatter_buildblock/CMakeLists.txt index bdc2692efe..99b0d5782b 100644 --- a/src/scatter_buildblock/CMakeLists.txt +++ b/src/scatter_buildblock/CMakeLists.txt @@ -18,9 +18,6 @@ set(${dir_LIB_SOURCES} ScatterSimulation SingleScatterSimulation SingleScatterLikelihoodAndGradient - LikelihoodAndGradientEstimateForOneScatterPoint - LikelihoodAndGradientEstimate - LikelihoodAndGradient ) #$(dir)_REGISTRY_SOURCES:= scatter_buildblock_registries diff --git a/src/scatter_buildblock/LikelihoodAndGradient.cxx b/src/scatter_buildblock/LikelihoodAndGradient.cxx deleted file mode 100644 index 4aba36fad2..0000000000 --- a/src/scatter_buildblock/LikelihoodAndGradient.cxx +++ /dev/null @@ -1,233 +0,0 @@ -/* - Copyright (C) 2004 - 2009 Hammersmith Imanet Ltd - Copyright (C) 2013 - 2016 University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details - */ -/*! - \file - \ingroup scatter - \brief Definition of class stir::ScatterEstimationByBin. - - \author Nikos Efthimiou - \author Kris Thielemans - */ -#include "stir/scatter/ScatterSimulation.h" -#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" -#include "stir/ViewSegmentNumbers.h" -#include "stir/Bin.h" - -#include "stir/Viewgram.h" -#include "stir/is_null_ptr.h" -#include "stir/IO/read_from_file.h" -#include "stir/IO/write_to_file.h" -#include "stir/info.h" -#include "stir/error.h" -#include -#include - -#include "stir/zoom.h" -#include "stir/SSRB.h" - -#include "stir/stir_math.h" -#include "stir/zoom.h" -#include "stir/NumericInfo.h" - -START_NAMESPACE_STIR - - - -double -SingleScatterLikelihoodAndGradient:: -L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale, bool isgradient) -{ - - - // this is usefull in the scatter estimation process. - this->output_proj_data_sptr->fill(0.f); - //show energy window information - - std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; - - if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && - this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) - { - std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; - - } - - - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - std::cerr << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); - this->remove_cache_for_integrals_over_attenuation(); - this->sample_scatter_points(); - this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - - ViewSegmentNumbers vs_num; - - int bin_counter = 0; - int axial_bins = 0 ; - double sum = 0; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns - coordinate in a coordinate system where z=0 in the first ring of the scanner. - We want to shift this to a coordinate system where z=0 in the middle - of the scanner. - We can use get_m() as that uses the 'middle of the scanner' system. - (sorry) - */ -#ifndef NDEBUG - { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( - detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - assert(detector_coord_A.z() == 0); - assert(detector_coord_B.z() == 0); - // check that get_m refers to the middle of the scanner - const float m_first = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); - assert(fabs(m_last + m_first) < m_last * 10E-4); - } -#endif - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - - info("ScatterSimulator: Initialization finished ..."); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); - ++vs_num.view_num()) - { - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - - sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,isgradient); - - bin_counter += - this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - std::cout<< bin_counter << " / "<< total_bins <& gradient_image_bin,const Bin bin, bool isgradient) -{ - double scatter_ratio_singles = 0; - unsigned det_num_B=0; - unsigned det_num_A=0; - - this->find_detectors(det_num_A, det_num_B,bin); - - for(std::size_t scatter_point_num =0; - scatter_point_num < this->scatt_points_vector.size(); - ++scatter_point_num) - { - - - - - scatter_ratio_singles += - L_G_for_one_scatter_point(gradient_image_bin, - scatter_point_num, - det_num_A, det_num_B, isgradient); - - } - - return scatter_ratio_singles; -} - -/*void -SingleScatterLikelihoodAndGradient:: -actual_L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin, - double& scatter_ratio_singles, - const unsigned det_num_A, - const unsigned det_num_B, bool isgradient) -{ - - - - scatter_ratio_singles = 0; - - for(std::size_t scatter_point_num =0; - scatter_point_num < this->scatt_points_vector.size(); - ++scatter_point_num) - { - - - - - scatter_ratio_singles += - L_G_for_one_scatter_point(gradient_image_bin, - scatter_point_num, - det_num_A, det_num_B, isgradient); - - } - -}*/ - - -END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx b/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx deleted file mode 100644 index 67d844fad7..0000000000 --- a/src/scatter_buildblock/LikelihoodAndGradientEstimateForOneScatterPoint.cxx +++ /dev/null @@ -1,314 +0,0 @@ -// -// -/* - Copyright (C) 2004- 2009-11-03, Hammersmith Imanet - Copyright (C) 2011-07-01 - 2011, Kris Thielemans - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details - */ -/*! - \file - \ingroup scatter - \brief Implementation of stir::ScatterEstimationByBin::single_scatter_estimate_for_one_scatter_point - - \author Charalampos Tsoumpas - \author Pablo Aguiar - \author Kris Thielemans - - - */ -#include "stir/scatter/SingleScatterSimulation.h" -#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" -#include "stir/scatter/ScatterSimulation.h" -#ifndef NDEBUG -// currently necessary for assert below -#include "stir/VoxelsOnCartesianGrid.h" -#endif - -#include "stir/round.h" -#include -using namespace std; -START_NAMESPACE_STIR - -static const float total_Compton_cross_section_511keV = -ScatterSimulation:: -total_Compton_cross_section(511.F); - -float -SingleScatterLikelihoodAndGradient:: -L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, - const std::size_t scatter_point_num, - const unsigned det_num_A, - const unsigned det_num_B, bool isgradient) -{ - - // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. - - int low = 0; - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - - { - - int first_window=this->template_exam_info_sptr->get_energy_window_pair().first-1; - int second_window=this->template_exam_info_sptr->get_energy_window_pair().second-1; - - if(this->template_exam_info_sptr->get_low_energy_thres(first_window) <= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) - - { - low = first_window; - } - - } - - static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), - 2.f, - this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); - - //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); - - const CartesianCoordinate3D& scatter_point = - this->scatt_points_vector[scatter_point_num].coord; - const CartesianCoordinate3D& detector_coord_A = - this->detection_points_vector[det_num_A]; - const CartesianCoordinate3D& detector_coord_B = - this->detection_points_vector[det_num_B]; - // note: costheta is -cos_angle such that it is 1 for zero scatter angle - const float costheta = static_cast( - -cos_angle(detector_coord_A - scatter_point, - detector_coord_B - scatter_point)); - // note: costheta is identical for scatter to A or scatter to B - // Hence, the Compton_cross_section and energy are identical for both cases as well. - if(max_single_scatter_cos_angle>costheta) - return 0; - const float new_energy = - photon_energy_after_Compton_scatter_511keV(costheta); - - // The detection efficiency varies with respect to the energy window. - //The code can now compute the scatter for a combination of two windows X and Y - //Default: one window -> The code will combine the window with itself - - std::vectordetection_efficiency_scattered; - std::vectordetection_efficiency_unscattered; - - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - detection_efficiency_scattered.push_back(0); - detection_efficiency_unscattered.push_back(0); - - } - - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); - detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); - - if (detection_efficiency_scattered[i]==0) - return 0; - if (detection_efficiency_unscattered[i]==0) - return 0; - } - - //compute the probability of detection for two given energy windows X and Y - - int index0 = 0; - int index1 = 0; - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - - index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; - index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; - - } - - float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; - float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; - - const float emiss_to_detA = - cached_integral_over_activity_image_between_scattpoint_det - (static_cast (scatter_point_num), - det_num_A); - const float emiss_to_detB = - cached_integral_over_activity_image_between_scattpoint_det - (static_cast (scatter_point_num), - det_num_B); - if (emiss_to_detA==0 && emiss_to_detB==0) - return 0; - const float atten_to_detA = - cached_exp_integral_over_attenuation_image_between_scattpoint_det - (scatter_point_num, - det_num_A); - const float atten_to_detB = - cached_exp_integral_over_attenuation_image_between_scattpoint_det - (scatter_point_num, - det_num_B); - - const float dif_Compton_cross_section_value = - dif_Compton_cross_section(costheta, 511.F); - - const float rA_squared=static_cast(norm_squared(scatter_point-detector_coord_A)); - const float rB_squared=static_cast(norm_squared(scatter_point-detector_coord_B)); - - const float scatter_point_mu= - scatt_points_vector[scatter_point_num].mu_value; - - const CartesianCoordinate3D - detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); - const CartesianCoordinate3D - detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); - const float cos_incident_angle_AS = static_cast( - cos_angle(scatter_point - detector_coord_A, - detA_to_ring_center)); - const float cos_incident_angle_BS = static_cast( - cos_angle(scatter_point - detector_coord_B, - detB_to_ring_center)); - -#ifndef NDEBUG - { - // check if mu-value ok - // currently terribly shift needed as in sample_scatter_points (TODO) - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(*this->density_image_for_scatter_points_sptr); - const CartesianCoordinate3D voxel_size = image.get_voxel_size(); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; - CartesianCoordinate3D shifted=scatter_point; - shifted.z() += z_to_middle; - assert(scatter_point_mu== - (*this->density_image_for_scatter_points_sptr)[this->density_image_for_scatter_points_sptr->get_indices_closest_to_physical_coordinates(shifted)]); - } -#endif - -#ifndef NEWSCALE - /* projectors work in pixel units, so convert attenuation data - from cm^-1 to pixel_units^-1 */ - const float rescale = - dynamic_cast &>(*density_image_sptr). - get_grid_spacing()[3]/10; -#else - const float rescale = - 0.1F; -#endif - - - //normalisation - - - // we will divide by the effiency of the detector pair for unscattered photons - // (computed with the same detection model as used in the scatter code) - // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. - - // there is a scatter_volume factor for every scatter point, as the sum over scatter points - // is an approximation for the integral over the scatter point. - - // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code - - - // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window - //find the window that contains 511 keV - - int index_photopeak = 0; //default for one energy window - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) - { - if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) - - { - - index_photopeak = i; - } - - } - } - - //normalisation factor between trues and scattered counts - - const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index_photopeak) * - scatter_volume/total_Compton_cross_section_511keV; - - - // Single ScatterForward Model - - float scatter_ratio=0; - - scatter_ratio= (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - /*Single Scatter Forward model Jacobian: - * The derivative is given by three term, respectively in [A,S], [B,S] and [S] */ - - float contribution_AS = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - total_Compton_cross_section_relative_to_511keV(new_energy)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - float contribution_BS = (detection_probability_XY*emiss_to_detA* - (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - (total_Compton_cross_section_relative_to_511keV(new_energy)) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* - pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - float contribution_S = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - //Fill gradient image along [A,S], [B,S] and in [S] - - if (isgradient) - - { - line_contribution(gradient,rescale,scatter_point, - detector_coord_B,contribution_BS); - - line_contribution(gradient,rescale,scatter_point, - detector_coord_A,contribution_AS); - - s_contribution(gradient,scatter_point, - contribution_S); - - } - return scatter_ratio; - -} - -END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index ead382b35b..6bb1e7414a 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -15,6 +15,25 @@ See STIR/LICENSE.txt for details */ #include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/scatter/ScatterSimulation.h" +#include "stir/ViewSegmentNumbers.h" +#include "stir/Bin.h" + +#include "stir/Viewgram.h" +#include "stir/is_null_ptr.h" +#include "stir/IO/read_from_file.h" +#include "stir/IO/write_to_file.h" +#include "stir/info.h" +#include "stir/error.h" +#include +#include + +#include "stir/zoom.h" +#include "stir/SSRB.h" + +#include "stir/stir_math.h" +#include "stir/zoom.h" +#include "stir/NumericInfo.h" START_NAMESPACE_STIR @@ -42,7 +61,485 @@ SingleScatterLikelihoodAndGradient:: ~SingleScatterLikelihoodAndGradient() {} +static const float total_Compton_cross_section_511keV = +ScatterSimulation:: +total_Compton_cross_section(511.F); + +double +SingleScatterLikelihoodAndGradient:: +L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale, bool isgradient) +{ + + + // this is usefull in the scatter estimation process. + this->output_proj_data_sptr->fill(0.f); + //show energy window information + + std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + + if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) + { + std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + + } + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + std::cerr << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + double sum = 0; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,isgradient); + + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + std::cout<< bin_counter << " / "<< total_bins <process_data_for_view_segment_num(vs_num); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - + // info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + std::cout<< bin_counter << " / "<< total_bins <& gradient_image, const { - // this is usefull in the scatter estimation process. this->output_proj_data_sptr->fill(0.f); - //show energy window information + std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; @@ -166,7 +165,14 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const } } + int max_x = gradient_image.get_max_x(); + int min_x = gradient_image.get_min_x(); + std::cerr << "LIKELIHOOD:= " << sum << '\n'; + + std::cerr << "MIN_GRADIENT_X:= " << min_x << '\n'; + std::cerr << "MAX_GRADIENT_X:= " << max_x << '\n'; + return sum; } @@ -300,6 +306,12 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, low = first_window; } + else if(this->template_exam_info_sptr->get_low_energy_thres(first_window) >= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) + + { + low = second_window; + } + } static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index bb49e19d4e..6ef5b36b35 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -139,7 +139,7 @@ detection_efficiency_no_scatter(const unsigned det_num_A, // TODO: slightly dangerous to use a static here // it would give wrong results when the energy_thresholds are changed... static const float detector_efficiency_no_scatter = 1 ; - /*detection_efficiency(511.F, en_window) > 0 + /*detection_efficiency(511.F, en_window) > 0 ? detection_efficiency(511.F, en_window) : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F);*/ From 5a700f8f2f16524fe7d6f3a8effda3d087a7fb83 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 13 Jun 2018 12:22:48 +0100 Subject: [PATCH 013/274] swig_scatter --- src/swig/stir.i | 2106 ++++++++++++++++++++++++----------------------- 1 file changed, 1054 insertions(+), 1052 deletions(-) diff --git a/src/swig/stir.i b/src/swig/stir.i index 80983af09a..01eeaa9208 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -1,64 +1,64 @@ /* - Copyright (C) 2011-07-01 - 2012, Kris Thielemans - Copyright (C) 2013 University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details - */ + Copyright (C) 2011-07-01 - 2012, Kris Thielemans + Copyright (C) 2013 University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ /*! - \file - \brief Interface file for SWIG - - \author Kris Thielemans - */ + \file + \brief Interface file for SWIG + + \author Kris Thielemans +*/ %module stir %{ #define SWIG_FILE_WITH_INIT - - /* Include the following headers in the wrapper code */ + + /* Include the following headers in the wrapper code */ #include #include #include // for size_t #include #include #ifdef SWIGOCTAVE - // TODO terrible work-around to avoid conflict between stir::error and Octave error - // they are in conflict with eachother because we need "using namespace stir" below (swig bug) +// TODO terrible work-around to avoid conflict between stir::error and Octave error +// they are in conflict with eachother because we need "using namespace stir" below (swig bug) #define __stir_error_H__ #endif - + #include "stir/num_threads.h" - -#include "stir/Succeeded.h" -#include "stir/DetectionPosition.h" -#include "stir/Scanner.h" -#include "stir/Bin.h" -#include "stir/ProjDataInfoCylindricalArcCorr.h" -#include "stir/ProjDataInfoCylindricalNoArcCorr.h" -#include "stir/Viewgram.h" -#include "stir/RelatedViewgrams.h" -#include "stir/Sinogram.h" -#include "stir/SegmentByView.h" -#include "stir/SegmentBySinogram.h" -#include "stir/ExamInfo.h" -#include "stir/IO/ExamData.h" -#include "stir/Verbosity.h" -#include "stir/ProjData.h" -#include "stir/ProjDataInMemory.h" -#include "stir/ProjDataInterfile.h" - + + #include "stir/Succeeded.h" + #include "stir/DetectionPosition.h" + #include "stir/Scanner.h" + #include "stir/Bin.h" + #include "stir/ProjDataInfoCylindricalArcCorr.h" + #include "stir/ProjDataInfoCylindricalNoArcCorr.h" + #include "stir/Viewgram.h" + #include "stir/RelatedViewgrams.h" + #include "stir/Sinogram.h" + #include "stir/SegmentByView.h" + #include "stir/SegmentBySinogram.h" + #include "stir/ExamInfo.h" + #include "stir/IO/ExamData.h" + #include "stir/Verbosity.h" + #include "stir/ProjData.h" + #include "stir/ProjDataInMemory.h" + #include "stir/ProjDataInterfile.h" + #include "stir/CartesianCoordinate2D.h" #include "stir/CartesianCoordinate3D.h" #include "stir/IndexRange.h" @@ -68,395 +68,396 @@ #include "stir/DiscretisedDensityOnCartesianGrid.h" #include "stir/PixelsOnCartesianGrid.h" #include "stir/VoxelsOnCartesianGrid.h" - + #include "stir/GeneralisedPoissonNoiseGenerator.h" - + #include "stir/IO/read_from_file.h" #include "stir/IO/InterfileOutputFileFormat.h" #ifdef HAVE_LLN_MATRIX #include "stir/IO/ECAT7OutputFileFormat.h" #endif - + #include "stir/ChainedDataProcessor.h" #include "stir/SeparableCartesianMetzImageFilter.h" - -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" + +#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" #include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" #include "stir/OSSPS/OSSPSReconstruction.h" #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" - + #include "stir/analytic/FBP2D/FBP2DReconstruction.h" #include "stir/analytic/FBP3DRP/FBP3DRPReconstruction.h" - + #include #include #include - + #include "stir/IO/write_to_file.h" + #include "stir/scatter/ScatterSimulation.h" #include "stir/scatter/SingleScatterSimulation.h" -#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" #include "stir/scatter/ScatterEstimation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" - // TODO need this (bug in swig) - // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace - // as opposed to "%template(name) stir::someclass" outside the namespace - using namespace stir; - using std::iostream; - + // TODO need this (bug in swig) + // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace + // as opposed to "%template(name) stir::someclass" outside the namespace + using namespace stir; + using std::iostream; + #if defined(SWIGPYTHON) - // need to declare this internal SWIG function as we're using it in the - // helper code below. It is used to convert a Python object to a float. - SWIGINTERN int - SWIG_AsVal_double (PyObject * obj, double *val); + // need to declare this internal SWIG function as we're using it in the + // helper code below. It is used to convert a Python object to a float. + SWIGINTERN int + SWIG_AsVal_double (PyObject * obj, double *val); #endif - - // local helper functions for conversions etc. These are not "exposed" to the target language - // (but only enter in the wrapper) - namespace swigstir { + + // local helper functions for conversions etc. These are not "exposed" to the target language + // (but only enter in the wrapper) + namespace swigstir { #if defined(SWIGPYTHON) - // helper function to translate a tuple to a BasicCoordinate - // returns zero on failure - template - int coord_from_tuple(stir::BasicCoordinate& c, PyObject* const args) - { return 0; } - template<> int coord_from_tuple(stir::BasicCoordinate<1, int>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "i", &c[1]); } - template<> int coord_from_tuple(stir::BasicCoordinate<2, int>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "ii", &c[1], &c[2]); } - template<> int coord_from_tuple(stir::BasicCoordinate<3, int>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "iii", &c[1], &c[2], &c[3]); } - template<> int coord_from_tuple(stir::BasicCoordinate<1, float>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "f", &c[1]); } - template<> int coord_from_tuple(stir::BasicCoordinate<2, float>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "ff", &c[1], &c[2]); } - template<> int coord_from_tuple(stir::BasicCoordinate<3, float>& c, PyObject* const args) - { return PyArg_ParseTuple(args, "fff", &c[1], &c[2], &c[3]); } - - template - PyObject* tuple_from_coord(const stir::BasicCoordinate& c) - { - PyObject* p = PyTuple_New(num_dimensions); - for (int d=1; d<=num_dimensions; ++d) - PyTuple_SET_ITEM(p, d-1, PyInt_FromLong(c[d])); - return p; - } - template - PyObject* tuple_from_coord(const stir::BasicCoordinate& c) - { - PyObject* p = PyTuple_New(num_dimensions); - for (int d=1; d<=num_dimensions; ++d) - PyTuple_SET_ITEM(p, d-1, PyInt_FromSize_t(c[d])); - return p; - } - template - PyObject* tuple_from_coord(const stir::BasicCoordinate& c) + // helper function to translate a tuple to a BasicCoordinate + // returns zero on failure + template + int coord_from_tuple(stir::BasicCoordinate& c, PyObject* const args) + { return 0; } + template<> int coord_from_tuple(stir::BasicCoordinate<1, int>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "i", &c[1]); } + template<> int coord_from_tuple(stir::BasicCoordinate<2, int>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "ii", &c[1], &c[2]); } + template<> int coord_from_tuple(stir::BasicCoordinate<3, int>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "iii", &c[1], &c[2], &c[3]); } + template<> int coord_from_tuple(stir::BasicCoordinate<1, float>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "f", &c[1]); } + template<> int coord_from_tuple(stir::BasicCoordinate<2, float>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "ff", &c[1], &c[2]); } + template<> int coord_from_tuple(stir::BasicCoordinate<3, float>& c, PyObject* const args) + { return PyArg_ParseTuple(args, "fff", &c[1], &c[2], &c[3]); } + + template + PyObject* tuple_from_coord(const stir::BasicCoordinate& c) + { + PyObject* p = PyTuple_New(num_dimensions); + for (int d=1; d<=num_dimensions; ++d) + PyTuple_SET_ITEM(p, d-1, PyInt_FromLong(c[d])); + return p; + } + template + PyObject* tuple_from_coord(const stir::BasicCoordinate& c) + { + PyObject* p = PyTuple_New(num_dimensions); + for (int d=1; d<=num_dimensions; ++d) + PyTuple_SET_ITEM(p, d-1, PyInt_FromSize_t(c[d])); + return p; + } + template + PyObject* tuple_from_coord(const stir::BasicCoordinate& c) + { + PyObject* p = PyTuple_New(num_dimensions); + for (int d=1; d<=num_dimensions; ++d) + PyTuple_SET_ITEM(p, d-1, PyFloat_FromDouble(double(c[d]))); + return p; + } + + // fill an array from a Python sequence + // (could be trivially modified to just write to a C++ iterator) + template + void fill_Array_from_Python_iterator(stir::Array * array_ptr, PyObject* const arg) + { + if (!PyIter_Check(arg)) + throw std::runtime_error("STIR-Python internal error: fill_Array_from_Python_iterators called but input is not an iterator"); + + { + PyObject *iterator = PyObject_GetIter(arg); + + PyObject *item; + typename stir::Array::full_iterator array_iter = array_ptr->begin_all(); + while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) { - PyObject* p = PyTuple_New(num_dimensions); - for (int d=1; d<=num_dimensions; ++d) - PyTuple_SET_ITEM(p, d-1, PyFloat_FromDouble(double(c[d]))); - return p; - } - - // fill an array from a Python sequence - // (could be trivially modified to just write to a C++ iterator) - template - void fill_Array_from_Python_iterator(stir::Array * array_ptr, PyObject* const arg) + double val; + // TODO currently hard-wired as double which might imply extra conversions + int ecode = SWIG_AsVal_double(item, &val); + if (SWIG_IsOK(ecode)) + { + *array_iter++ = static_cast(val); + } + else + { + Py_DECREF(item); + Py_DECREF(iterator); + char str[1000]; + snprintf(str, 1000, "Wrong type used for fill(): iterator elements are of type %s but needs to be convertible to double", + item->ob_type->tp_name); + throw std::invalid_argument(str); + } + Py_DECREF(item); + } + + if (PyIter_Next(iterator) != NULL || array_iter != array_ptr->end_all()) { - if (!PyIter_Check(arg)) - throw std::runtime_error("STIR-Python internal error: fill_Array_from_Python_iterators called but input is not an iterator"); - - { - PyObject *iterator = PyObject_GetIter(arg); - - PyObject *item; - typename stir::Array::full_iterator array_iter = array_ptr->begin_all(); - while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) - { - double val; - // TODO currently hard-wired as double which might imply extra conversions - int ecode = SWIG_AsVal_double(item, &val); - if (SWIG_IsOK(ecode)) - { - *array_iter++ = static_cast(val); - } - else - { - Py_DECREF(item); - Py_DECREF(iterator); - char str[1000]; - snprintf(str, 1000, "Wrong type used for fill(): iterator elements are of type %s but needs to be convertible to double", - item->ob_type->tp_name); - throw std::invalid_argument(str); - } - Py_DECREF(item); - } - - if (PyIter_Next(iterator) != NULL || array_iter != array_ptr->end_all()) - { - throw std::runtime_error("fill() called with incorrect range of iterators, array needs to have the same number of elements"); - } - Py_DECREF(iterator); - - if (PyErr_Occurred()) - { - throw std::runtime_error("Error during fill()"); - } - } - - } - + throw std::runtime_error("fill() called with incorrect range of iterators, array needs to have the same number of elements"); + } + Py_DECREF(iterator); + + if (PyErr_Occurred()) + { + throw std::runtime_error("Error during fill()"); + } + } + + } + #if 0 - - // TODO does not work yet. - // it doesn't compile as includes are in init section, which follows after this in the wrapper - // Even if it did compile, it might not work anyway as I haven't tested it. - template - void fill_nparray_from_iterator(PyObject * np, IterT iterator) - { - // This code is more or less a copy of the "simple iterator example" (!) in the Numpy doc - // see e.g. http://students.mimuw.edu.pl/~pbechler/numpy_doc/reference/c-api.iterator.html - typedef float elemT; - NpyIter* iter; - NpyIter_IterNextFunc *iternext; - char** dataptr; - npy_intp* strideptr,* innersizeptr; - - /* Handle zero-sized arrays specially */ - if (PyArray_SIZE(np) == 0) { - return; - } - - /* - * Create and use an iterator to count the nonzeros. - * flag NPY_ITER_READONLY - * - The array is never written to. - * flag NPY_ITER_EXTERNAL_LOOP - * - Inner loop is done outside the iterator for efficiency. - * flag NPY_ITER_NPY_ITER_REFS_OK - * - Reference types are acceptable. - * order NPY_KEEPORDER - * - Visit elements in memory order, regardless of strides. - * This is good for performance when the specific order - * elements are visited is unimportant. - * casting NPY_NO_CASTING - * - No casting is required for this operation. - */ - iter = NpyIter_New(np, NPY_ITER_WRITEONLY| - NPY_ITER_EXTERNAL_LOOP, - NPY_KEEPORDER, NPY_NO_CASTING, - NULL); - if (iter == NULL) { - throw std::runtime_error("Error creating numpy iterator"); - } - - /* - * The iternext function gets stored in a local variable - * so it can be called repeatedly in an efficient manner. - */ - iternext = NpyIter_GetIterNext(iter, NULL); - if (iternext == NULL) { - NpyIter_Deallocate(iter); - throw std::runtime_error("Error creating numpy iterator function"); - } - /* The location of the data pointer which the iterator may update */ - dataptr = NpyIter_GetDataPtrArray(iter); - /* The location of the stride which the iterator may update */ - strideptr = NpyIter_GetInnerStrideArray(iter); - /* The location of the inner loop size which the iterator may update */ - innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); - - /* The iteration loop */ - do { - /* Get the inner loop data/stride/count values */ - char* data = *dataptr; - npy_intp stride = *strideptr; - npy_intp count = *innersizeptr; - - /* This is a typical inner loop for NPY_ITER_EXTERNAL_LOOP */ - while (count--) { - *(reinterpret_cast(data)) = static_cast(*iterator++); - data += stride; - } - - /* Increment the iterator to the next inner loop */ - } while(iternext(iter)); - - NpyIter_Deallocate(iter); + + // TODO does not work yet. + // it doesn't compile as includes are in init section, which follows after this in the wrapper + // Even if it did compile, it might not work anyway as I haven't tested it. + template + void fill_nparray_from_iterator(PyObject * np, IterT iterator) + { + // This code is more or less a copy of the "simple iterator example" (!) in the Numpy doc + // see e.g. http://students.mimuw.edu.pl/~pbechler/numpy_doc/reference/c-api.iterator.html + typedef float elemT; + NpyIter* iter; + NpyIter_IterNextFunc *iternext; + char** dataptr; + npy_intp* strideptr,* innersizeptr; + + /* Handle zero-sized arrays specially */ + if (PyArray_SIZE(np) == 0) { + return; + } + + /* + * Create and use an iterator to count the nonzeros. + * flag NPY_ITER_READONLY + * - The array is never written to. + * flag NPY_ITER_EXTERNAL_LOOP + * - Inner loop is done outside the iterator for efficiency. + * flag NPY_ITER_NPY_ITER_REFS_OK + * - Reference types are acceptable. + * order NPY_KEEPORDER + * - Visit elements in memory order, regardless of strides. + * This is good for performance when the specific order + * elements are visited is unimportant. + * casting NPY_NO_CASTING + * - No casting is required for this operation. + */ + iter = NpyIter_New(np, NPY_ITER_WRITEONLY| + NPY_ITER_EXTERNAL_LOOP, + NPY_KEEPORDER, NPY_NO_CASTING, + NULL); + if (iter == NULL) { + throw std::runtime_error("Error creating numpy iterator"); + } + + /* + * The iternext function gets stored in a local variable + * so it can be called repeatedly in an efficient manner. + */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + throw std::runtime_error("Error creating numpy iterator function"); + } + /* The location of the data pointer which the iterator may update */ + dataptr = NpyIter_GetDataPtrArray(iter); + /* The location of the stride which the iterator may update */ + strideptr = NpyIter_GetInnerStrideArray(iter); + /* The location of the inner loop size which the iterator may update */ + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + /* The iteration loop */ + do { + /* Get the inner loop data/stride/count values */ + char* data = *dataptr; + npy_intp stride = *strideptr; + npy_intp count = *innersizeptr; + + /* This is a typical inner loop for NPY_ITER_EXTERNAL_LOOP */ + while (count--) { + *(reinterpret_cast(data)) = static_cast(*iterator++); + data += stride; } + + /* Increment the iterator to the next inner loop */ + } while(iternext(iter)); + + NpyIter_Deallocate(iter); + } #endif - + #elif defined(SWIGMATLAB) - // convert stir::Array to matlab (currently always converting to double) - // note that the order of the dimensions is reversed to take row-first vs column-first ordering into account - template - mxArray * Array_to_matlab(const stir::Array& a) - { - mwSize dims[num_dimensions]; - BasicCoordinate minind,maxind; - a.get_regular_range(minind,maxind); - const BasicCoordinate sizes=maxind-minind+1; - // copy dimensions in reverse order - std::copy(boost::make_reverse_iterator(sizes.end()), boost::make_reverse_iterator(sizes.begin()), dims); - mxArray *pm = mxCreateNumericArray(num_dimensions, dims, mxDOUBLE_CLASS, mxREAL); - double * data_ptr = mxGetPr(pm); - std::copy(a.begin_all(), a.end_all(), data_ptr); - return pm; - } - - template - void fill_Array_from_matlab_scalar(stir::Array& a, const mxArray *pm) - { - if (mxIsDouble(pm)) - { - double const* data_ptr = mxGetPr(pm); - a.fill(static_cast(*data_ptr)); - } else if (mxIsSingle(pm)) - { - float const* data_ptr = (float *)mxGetData(pm); - a.fill(static_cast(*data_ptr)); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for filling a stir array"); - } - } - - template - void fill_Array_from_matlab(stir::Array& a, const mxArray *pm, bool do_resize) - { - mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); - const mwSize * m_sizes = mxGetDimensions(pm); - // matlab represents scalars/vectors as a matrix, so let's check this first - if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) - { - if (m_sizes[0] ==static_cast(1)) - { - // it's a scalar - fill_Array_from_matlab_scalar(a, pm); - return; - } - matlab_num_dims=static_cast(1); // set it to a 1-dimensional array - } - if (matlab_num_dims > static_cast(num_dimensions)) - { - throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % - num_dimensions)); - } - if (do_resize) - { - BasicCoordinate sizes; - // first set all to 1 to cope with lower-dimensional arrays from matlab - sizes.fill(1); - std::copy(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end())); - a.resize(sizes); - } - else - { - // check sizes - BasicCoordinate minind,maxind; - a.get_regular_range(minind,maxind); - const BasicCoordinate sizes=maxind-minind+1; - if (!std::equal(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end()))) - { - throw std::runtime_error("sizes of matlab array incompatible with stir array"); - } - for (int d=1; d<= num_dimensions-static_cast(matlab_num_dims); ++d) - { - if (sizes[d]!=1) - { - throw std::runtime_error("sizes of first dimensions of the stir array have to be 1 if initialising from a lower dimensional matlab array"); - } - } - } - if (mxIsDouble(pm)) - { - double * data_ptr = mxGetPr(pm); - std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); - } else if (mxIsSingle(pm)) - { - float * data_ptr = (float *)mxGetData(pm); - std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); - } - } - - - //////////// same for Coordinate - // convert stir::BasicCoordinate to matlab (currently always converting to double) - template - mxArray * BasicCoordinate_to_matlab(const stir::BasicCoordinate& a) - { - mwSize dims[2]; - dims[0]=mwSize(num_dimensions); - dims[1]=mwSize(1); - mxArray *pm = mxCreateNumericArray(mwSize(2), dims, mxDOUBLE_CLASS, mxREAL); - double * data_ptr = mxGetPr(pm); - std::copy(a.begin(), a.end(), data_ptr); - return pm; - } - - template - void fill_BasicCoordinate_from_matlab_scalar(stir::BasicCoordinate& a, const mxArray *pm) - { - if (mxIsDouble(pm)) - { - double const* data_ptr = mxGetPr(pm); - a.fill(static_cast(*data_ptr)); - } else if (mxIsSingle(pm)) - { - float const* data_ptr = (float *)mxGetData(pm); - a.fill(static_cast(*data_ptr)); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for filling a stir coordinate"); - } - } - - template - void fill_BasicCoordinate_from_matlab(stir::BasicCoordinate& a, const mxArray *pm) - { - mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); - const mwSize * m_sizes = mxGetDimensions(pm); - // matlab represents scalars/vectors as a matrix, so let's check this first - if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) - { - if (m_sizes[0] ==static_cast(1)) - { - // it's a scalar - fill_BasicCoordinate_from_matlab_scalar(a, pm); - return; - } - matlab_num_dims=static_cast(1); // set it to a 1-dimensional array - } - if (matlab_num_dims != static_cast(1)) - { - throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % - matlab_num_dims % num_dimensions)); - } - if (m_sizes[0]!=static_cast(num_dimensions)) - { - throw std::runtime_error("length of matlab array incompatible with stir coordinate"); - } - if (mxIsDouble(pm)) - { - double * data_ptr = mxGetPr(pm); - std::copy(data_ptr, data_ptr+a.size(), a.begin()); - } else if (mxIsSingle(pm)) - { - float * data_ptr = (float *)mxGetData(pm); - std::copy(data_ptr, data_ptr+a.size(), a.begin()); - } else - { - throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); - } - } + // convert stir::Array to matlab (currently always converting to double) + // note that the order of the dimensions is reversed to take row-first vs column-first ordering into account + template + mxArray * Array_to_matlab(const stir::Array& a) + { + mwSize dims[num_dimensions]; + BasicCoordinate minind,maxind; + a.get_regular_range(minind,maxind); + const BasicCoordinate sizes=maxind-minind+1; + // copy dimensions in reverse order + std::copy(boost::make_reverse_iterator(sizes.end()), boost::make_reverse_iterator(sizes.begin()), dims); + mxArray *pm = mxCreateNumericArray(num_dimensions, dims, mxDOUBLE_CLASS, mxREAL); + double * data_ptr = mxGetPr(pm); + std::copy(a.begin_all(), a.end_all(), data_ptr); + return pm; + } + + template + void fill_Array_from_matlab_scalar(stir::Array& a, const mxArray *pm) + { + if (mxIsDouble(pm)) + { + double const* data_ptr = mxGetPr(pm); + a.fill(static_cast(*data_ptr)); + } else if (mxIsSingle(pm)) + { + float const* data_ptr = (float *)mxGetData(pm); + a.fill(static_cast(*data_ptr)); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for filling a stir array"); + } + } + + template + void fill_Array_from_matlab(stir::Array& a, const mxArray *pm, bool do_resize) + { + mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); + const mwSize * m_sizes = mxGetDimensions(pm); + // matlab represents scalars/vectors as a matrix, so let's check this first + if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) + { + if (m_sizes[0] ==static_cast(1)) + { + // it's a scalar + fill_Array_from_matlab_scalar(a, pm); + return; + } + matlab_num_dims=static_cast(1); // set it to a 1-dimensional array + } + if (matlab_num_dims > static_cast(num_dimensions)) + { + throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % + num_dimensions)); + } + if (do_resize) + { + BasicCoordinate sizes; + // first set all to 1 to cope with lower-dimensional arrays from matlab + sizes.fill(1); + std::copy(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end())); + a.resize(sizes); + } + else + { + // check sizes + BasicCoordinate minind,maxind; + a.get_regular_range(minind,maxind); + const BasicCoordinate sizes=maxind-minind+1; + if (!std::equal(m_sizes, m_sizes+matlab_num_dims, boost::make_reverse_iterator(sizes.end()))) + { + throw std::runtime_error("sizes of matlab array incompatible with stir array"); + } + for (int d=1; d<= num_dimensions-static_cast(matlab_num_dims); ++d) + { + if (sizes[d]!=1) + { + throw std::runtime_error("sizes of first dimensions of the stir array have to be 1 if initialising from a lower dimensional matlab array"); + } + } + } + if (mxIsDouble(pm)) + { + double * data_ptr = mxGetPr(pm); + std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); + } else if (mxIsSingle(pm)) + { + float * data_ptr = (float *)mxGetData(pm); + std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); + } + } + + + //////////// same for Coordinate + // convert stir::BasicCoordinate to matlab (currently always converting to double) + template + mxArray * BasicCoordinate_to_matlab(const stir::BasicCoordinate& a) + { + mwSize dims[2]; + dims[0]=mwSize(num_dimensions); + dims[1]=mwSize(1); + mxArray *pm = mxCreateNumericArray(mwSize(2), dims, mxDOUBLE_CLASS, mxREAL); + double * data_ptr = mxGetPr(pm); + std::copy(a.begin(), a.end(), data_ptr); + return pm; + } + + template + void fill_BasicCoordinate_from_matlab_scalar(stir::BasicCoordinate& a, const mxArray *pm) + { + if (mxIsDouble(pm)) + { + double const* data_ptr = mxGetPr(pm); + a.fill(static_cast(*data_ptr)); + } else if (mxIsSingle(pm)) + { + float const* data_ptr = (float *)mxGetData(pm); + a.fill(static_cast(*data_ptr)); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for filling a stir coordinate"); + } + } + + template + void fill_BasicCoordinate_from_matlab(stir::BasicCoordinate& a, const mxArray *pm) + { + mwSize matlab_num_dims = mxGetNumberOfDimensions(pm); + const mwSize * m_sizes = mxGetDimensions(pm); + // matlab represents scalars/vectors as a matrix, so let's check this first + if (matlab_num_dims == static_cast(2) && m_sizes[1]==static_cast(1)) + { + if (m_sizes[0] ==static_cast(1)) + { + // it's a scalar + fill_BasicCoordinate_from_matlab_scalar(a, pm); + return; + } + matlab_num_dims=static_cast(1); // set it to a 1-dimensional array + } + if (matlab_num_dims != static_cast(1)) + { + throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % + matlab_num_dims % num_dimensions)); + } + if (m_sizes[0]!=static_cast(num_dimensions)) + { + throw std::runtime_error("length of matlab array incompatible with stir coordinate"); + } + if (mxIsDouble(pm)) + { + double * data_ptr = mxGetPr(pm); + std::copy(data_ptr, data_ptr+a.size(), a.begin()); + } else if (mxIsSingle(pm)) + { + float * data_ptr = (float *)mxGetData(pm); + std::copy(data_ptr, data_ptr+a.size(), a.begin()); + } else + { + throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); + } + } #endif - } // end namespace swigstir - %} + } // end namespace swigstir + %} #if defined(SWIGPYTHON) %include "numpy.i" @@ -467,11 +468,11 @@ %init %{ #if defined(SWIGPYTHON) - // numpy support - import_array(); -#include + // numpy support + import_array(); + #include #endif - %} +%} %feature("autodoc", "1"); @@ -487,14 +488,14 @@ %include "exception.i" %exception { - try { - $action - } catch (const std::exception& e) { - SWIG_exception(SWIG_RuntimeError, e.what()); - } catch (const std::string& e) { - SWIG_exception(SWIG_RuntimeError, e.c_str()); - } -} + try { + $action + } catch (const std::exception& e) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } catch (const std::string& e) { + SWIG_exception(SWIG_RuntimeError, e.c_str()); + } +} // declare some functions that return a new pointer such that SWIG can release memory properly %newobject *::clone; @@ -505,7 +506,7 @@ %ignore *::create_shared_clone; #if defined(SWIGPYTHON) -%rename(__assign__) *::operator=; +%rename(__assign__) *::operator=; #endif // include standard swig support for some bits of the STL (i.e. standard C++ lib) @@ -520,7 +521,7 @@ // always ignore these as they are unsafe in out-of-range index access (use at() instead) %ignore *::operator[]; -// this will be replaced by __getitem__ etc, we could keep this for languages not supported by ADD_indexvalue + // this will be replaced by __getitem__ etc, we could keep this for languages not supported by ADD_indexvalue %ignore *::at; #ifdef STIRMATLAB @@ -544,13 +545,13 @@ // Instantiate STL templates used by stir namespace std { - %template(IntVector) vector; - %template(DoubleVector) vector; - %template(FloatVector) vector; - %template(StringList) list; + %template(IntVector) vector; + %template(DoubleVector) vector; + %template(FloatVector) vector; + %template(StringList) list; } -// section for helper classes for creating new iterators. +// section for helper classes for creating new iterators. // The code here is nearly a copy of what's in PyIterators.swg, // except that the decr() function isn't defined. This is because we need it for some STIR iterators // which are forward_iterators. @@ -559,248 +560,248 @@ namespace std { // Note: this needs to be defined after including some stl stuff, as otherwise the necessary fragments // haven't been included in the wrap.cxx yet. %{ - namespace swigstir { + namespace swigstir { #ifdef SWIGPYTHON - template::value_type, - typename FromOper = swig::from_oper > - class SwigPyForwardIteratorClosed_T : public swig::SwigPyIterator_T - { - public: - FromOper from; - typedef OutIterator out_iterator; - typedef ValueType value_type; - typedef swig::SwigPyIterator_T base; - typedef SwigPyForwardIteratorClosed_T self_type; - - SwigPyForwardIteratorClosed_T(out_iterator curr, out_iterator first, out_iterator last, PyObject *seq) - : swig::SwigPyIterator_T(curr, seq), begin(first), end(last) - { - } - - PyObject *value() const { - if (base::current == end) { - throw swig::stop_iteration(); - } else { - return swig::from(static_cast(*(base::current))); - } - } - - swig::SwigPyIterator *copy() const - { - return new self_type(*this); - } - - swig::SwigPyIterator *incr(size_t n = 1) - { - while (n--) { - if (base::current == end) { - throw swig::stop_iteration(); - } else { - ++base::current; - } - } - return this; - } - - private: - out_iterator begin; - out_iterator end; - }; - - template - inline swig::SwigPyIterator* - make_forward_iterator(const OutIter& current, const OutIter& begin,const OutIter& end, PyObject *seq = 0) - { - return new SwigPyForwardIteratorClosed_T(current, begin, end, seq); - } - - -#endif - static Array<3,float> create_array_for_proj_data(const ProjData& proj_data) - { - // int num_sinos=proj_data.get_num_axial_poss(0); - // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) - // { - // num_sinos += 2*proj_data.get_num_axial_poss(s); - // } - int num_sinos = proj_data.get_num_sinograms(); - - Array<3,float> array(IndexRange3D(num_sinos, proj_data.get_num_views(), proj_data.get_num_tangential_poss())); - return array; - } - - // a function for converting ProjData to a 3D array as that's what is easy to use - static Array<3,float> projdata_to_3D(const ProjData& proj_data) - { - Array<3,float> array = create_array_for_proj_data(proj_data); - Array<3,float>::full_iterator array_iter = array.begin_all(); - // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) - // { - // SegmentBySinogram segment=proj_data.get_segment_by_sinogram(s); - // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); - // std::advance(array_iter, segment.size_all()); - // if (s!=0) - // { - // segment=proj_data.get_segment_by_sinogram(-s); - // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); - // std::advance(array_iter, segment.size_all()); - // } - // } - proj_data.copy_to(array_iter); - return array; - } - - // inverse of the above function - void fill_proj_data_from_3D(ProjData& proj_data, const Array<3,float>& array) - { - // int num_sinos=proj_data.get_num_axial_poss(0); - // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) - // { - // num_sinos += 2*proj_data.get_num_axial_poss(s); - // } - // if (array.size() != static_cast(num_sinos)|| - // array[0].size() != static_cast(proj_data.get_num_views()) || - // array[0][0].size() != static_cast(proj_data.get_num_tangential_poss())) - // { - // throw std::runtime_error("Incorrect size for filling this projection data"); - // } - Array<3,float>::const_full_iterator array_iter = array.begin_all(); - // - // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) - // { - // SegmentBySinogram segment=proj_data.get_empty_segment_by_sinogram(s); - // // cannot use std::copy sadly as needs end-iterator for range - // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); - // seg_iter != segment.end_all(); - // /*empty*/) - // *seg_iter++ = *array_iter++; - // proj_data.set_segment(segment); - // - // if (s!=0) - // { - // segment=proj_data.get_empty_segment_by_sinogram(-s); - // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); - // seg_iter != segment.end_all(); - // /*empty*/) - // *seg_iter++ = *array_iter++; - // proj_data.set_segment(segment); - // } - // } - proj_data.fill_from(array_iter); - } - - - } // end of namespace + template::value_type, + typename FromOper = swig::from_oper > + class SwigPyForwardIteratorClosed_T : public swig::SwigPyIterator_T + { + public: + FromOper from; + typedef OutIterator out_iterator; + typedef ValueType value_type; + typedef swig::SwigPyIterator_T base; + typedef SwigPyForwardIteratorClosed_T self_type; + + SwigPyForwardIteratorClosed_T(out_iterator curr, out_iterator first, out_iterator last, PyObject *seq) + : swig::SwigPyIterator_T(curr, seq), begin(first), end(last) + { + } + + PyObject *value() const { + if (base::current == end) { + throw swig::stop_iteration(); + } else { + return swig::from(static_cast(*(base::current))); + } + } - %} // end of initial code specification for inclusino in the SWIG wrapper + swig::SwigPyIterator *copy() const + { + return new self_type(*this); + } + + swig::SwigPyIterator *incr(size_t n = 1) + { + while (n--) { + if (base::current == end) { + throw swig::stop_iteration(); + } else { + ++base::current; + } + } + return this; + } + + private: + out_iterator begin; + out_iterator end; + }; + + template + inline swig::SwigPyIterator* + make_forward_iterator(const OutIter& current, const OutIter& begin,const OutIter& end, PyObject *seq = 0) + { + return new SwigPyForwardIteratorClosed_T(current, begin, end, seq); + } + + +#endif + static Array<3,float> create_array_for_proj_data(const ProjData& proj_data) + { + // int num_sinos=proj_data.get_num_axial_poss(0); + // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) + // { + // num_sinos += 2*proj_data.get_num_axial_poss(s); + // } + int num_sinos = proj_data.get_num_sinograms(); + + Array<3,float> array(IndexRange3D(num_sinos, proj_data.get_num_views(), proj_data.get_num_tangential_poss())); + return array; + } + + // a function for converting ProjData to a 3D array as that's what is easy to use + static Array<3,float> projdata_to_3D(const ProjData& proj_data) + { + Array<3,float> array = create_array_for_proj_data(proj_data); + Array<3,float>::full_iterator array_iter = array.begin_all(); + // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) + // { + // SegmentBySinogram segment=proj_data.get_segment_by_sinogram(s); + // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + // std::advance(array_iter, segment.size_all()); + // if (s!=0) + // { + // segment=proj_data.get_segment_by_sinogram(-s); + // std::copy(segment.begin_all_const(), segment.end_all_const(), array_iter); + // std::advance(array_iter, segment.size_all()); + // } + // } + proj_data.copy_to(array_iter); + return array; + } + + // inverse of the above function + void fill_proj_data_from_3D(ProjData& proj_data, const Array<3,float>& array) + { + // int num_sinos=proj_data.get_num_axial_poss(0); + // for (int s=1; s<= proj_data.get_max_segment_num(); ++s) + // { + // num_sinos += 2*proj_data.get_num_axial_poss(s); + // } + // if (array.size() != static_cast(num_sinos)|| + // array[0].size() != static_cast(proj_data.get_num_views()) || + // array[0][0].size() != static_cast(proj_data.get_num_tangential_poss())) + // { + // throw std::runtime_error("Incorrect size for filling this projection data"); + // } + Array<3,float>::const_full_iterator array_iter = array.begin_all(); + // + // for (int s=0; s<= proj_data.get_max_segment_num(); ++s) + // { + // SegmentBySinogram segment=proj_data.get_empty_segment_by_sinogram(s); + // // cannot use std::copy sadly as needs end-iterator for range + // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); + // seg_iter != segment.end_all(); + // /*empty*/) + // *seg_iter++ = *array_iter++; + // proj_data.set_segment(segment); + // + // if (s!=0) + // { + // segment=proj_data.get_empty_segment_by_sinogram(-s); + // for (SegmentBySinogram::full_iterator seg_iter = segment.begin_all(); + // seg_iter != segment.end_all(); + // /*empty*/) + // *seg_iter++ = *array_iter++; + // proj_data.set_segment(segment); + // } + // } + proj_data.fill_from(array_iter); + } + + + } // end of namespace + + %} // end of initial code specification for inclusino in the SWIG wrapper // doesn't work (yet?) because of bug in int template arguments -// %rename(__getitem__) *::at; +// %rename(__getitem__) *::at; // MACROS to define index access (Work-in-progress) %define %ADD_indexaccess(INDEXTYPE,RETTYPE,TYPE...) #if defined(SWIGPYTHON) #if defined(SWIGPYTHON_BUILTIN) -// %feature("python:slot", "sq_item", functype="ssizeargfunc") TYPE##::__getitem__; -// %feature("python:slot", "sq_ass_item", functype="ssizeobjargproc") TYPE##::__setitem__; -%feature("python:slot", "mp_subscript", functype="binaryfunc") TYPE##::__getitem__; -%feature("python:slot", "mp_ass_subscript", functype="objobjargproc") TYPE##::__setitem__; + // %feature("python:slot", "sq_item", functype="ssizeargfunc") TYPE##::__getitem__; + // %feature("python:slot", "sq_ass_item", functype="ssizeobjargproc") TYPE##::__setitem__; + %feature("python:slot", "mp_subscript", functype="binaryfunc") TYPE##::__getitem__; + %feature("python:slot", "mp_ass_subscript", functype="objobjargproc") TYPE##::__setitem__; #endif %extend TYPE { %exception __getitem__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } %newobject __getitem__; RETTYPE __getitem__(const INDEXTYPE i) { return (*self).at(i); } %exception __setitem__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } void __setitem__(const INDEXTYPE i, const RETTYPE val) { (*self).at(i)=val; } -} + } #elif defined(SWIGOCTAVE) %extend TYPE { %exception __brace__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } %newobject __brace__; RETTYPE __brace__(const INDEXTYPE i) { return (*self).at(i); } %exception __brace_asgn__ { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } void __brace_asgn__(const INDEXTYPE i, const RETTYPE val) { (*self).at(i)=val; } -} + } #elif defined(SWIGMATLAB) %extend TYPE { %exception paren { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } %newobject paren; RETTYPE paren(const INDEXTYPE i) { return (*self).at(i); } %exception paren_asgn { - try - { - $action - } - catch (std::out_of_range& e) { - SWIG_exception(SWIG_IndexError,const_cast(e.what())); - } - catch (std::invalid_argument& e) { - SWIG_exception(SWIG_TypeError,const_cast(e.what())); - } + try + { + $action + } + catch (std::out_of_range& e) { + SWIG_exception(SWIG_IndexError,const_cast(e.what())); + } + catch (std::invalid_argument& e) { + SWIG_exception(SWIG_TypeError,const_cast(e.what())); + } } void paren_asgn(const INDEXTYPE i, const RETTYPE val) { (*self).at(i)=val; } -} + } #endif %enddef -// Finally, start with STIR specific definitions + // Finally, start with STIR specific definitions %include "stir/num_threads.h" @@ -808,11 +809,11 @@ namespace std { // #define used below to check what to do #define STIRSWIG_SHARED_PTR -// internally convert all pointers to shared_ptr. This prevents problems -// with STIR functions which accept a shared_ptr as input argument. + // internally convert all pointers to shared_ptr. This prevents problems + // with STIR functions which accept a shared_ptr as input argument. #define SWIG_SHARED_PTR_NAMESPACE stir #ifdef SWIGOCTAVE -// TODO temp work-around + // TODO temp work-around %include #else %include @@ -848,11 +849,11 @@ namespace std { %shared_ptr(stir::Viewgram); #else namespace boost { - template class shared_ptr - { - public: - T * operator-> () const; - }; +template class shared_ptr +{ +public: +T * operator-> () const; +}; } #endif @@ -866,17 +867,17 @@ namespace boost { %include "stir/Object.h" %include "stir/RegisteredObject.h" #else -// use simpler version for SWIG to make the hierarchy a bit easier -namespace stir { + // use simpler version for SWIG to make the hierarchy a bit easier + namespace stir { template - class RegisteredObject - { - public: - //! List all possible registered names to the stream - /*! Names are separated with newlines. */ - inline static void list_registered_names(std::ostream& stream); - }; -} + class RegisteredObject + { + public: + //! List all possible registered names to the stream + /*! Names are separated with newlines. */ + inline static void list_registered_names(std::ostream& stream); + }; + } #endif // disabled warning about nested class. we don't need this class anyway @@ -886,7 +887,7 @@ namespace stir { %nodefaultctor stir::RegisteredParsingObject; %include "stir/RegisteredParsingObject.h" -/* Parse the header files to generate wrappers */ + /* Parse the header files to generate wrappers */ //%include "stir/shared_ptr.h" %include "stir/Succeeded.h" %include "stir/NumericType.h" @@ -895,10 +896,10 @@ namespace stir { %newobject stir::Scanner::get_scanner_from_name; %include "stir/Scanner.h" -/* First do coordinates, indices, images. - We first include them, and sort out template instantiation and indexing below. + /* First do coordinates, indices, images. + We first include them, and sort out template instantiation and indexing below. */ -//%include + //%include %include "stir/BasicCoordinate.h" %include "stir/Coordinate3D.h" @@ -913,7 +914,7 @@ namespace stir { %ignore stir::CartesianCoordinate2D::y() const; %include "stir/CartesianCoordinate2D.h" -// we have to ignore the following because of a bug in SWIG 2.0.4, but we don't need it anyway + // we have to ignore the following because of a bug in SWIG 2.0.4, but we don't need it anyway %ignore *::IndexRange(const VectorWithOffset >& range); %include "stir/IndexRange.h" @@ -924,40 +925,40 @@ namespace stir { %include "stir/VectorWithOffset.h" #if defined(SWIGPYTHON) -// TODO ideally would use %swig_container_methods but we don't have getslice yet + // TODO ideally would use %swig_container_methods but we don't have getslice yet #if defined(SWIGPYTHON_BUILTIN) -%feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; -%feature("python:slot", "sq_length", functype="lenfunc") __len__; + %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; + %feature("python:slot", "sq_length", functype="lenfunc") __len__; #endif // SWIGPYTHON_BUILTIN %extend stir::VectorWithOffset { bool __nonzero__() const { - return !(self->empty()); + return !(self->empty()); } - + /* Alias for Python 3 compatibility */ bool __bool__() const { - return !(self->empty()); + return !(self->empty()); } - + size_type __len__() const { - return self->size(); + return self->size(); } #if 0 // TODO this does not work yet /* - %define %emit_swig_traits(_Type...) - %traits_swigtype(_Type); - %fragment(SWIG_Traits_frag(_Type)); - %enddef - - %emit_swig_traits(MyPrice) - */ +%define %emit_swig_traits(_Type...) +%traits_swigtype(_Type); +%fragment(SWIG_Traits_frag(_Type)); +%enddef + +%emit_swig_traits(MyPrice) + */ %swig_sequence_iterator(stir::VectorWithOffset); #else %newobject _iterator(PyObject **PYTHON_SELF); swig::SwigPyIterator* _iterator(PyObject **PYTHON_SELF) { - return swig::make_output_iterator(self->begin(), self->begin(), self->end(), *PYTHON_SELF); + return swig::make_output_iterator(self->begin(), self->begin(), self->end(), *PYTHON_SELF); } #if defined(SWIGPYTHON_BUILTIN) %feature("python:slot", "tp_iter", functype="getiterfunc") _iterator; @@ -965,7 +966,7 @@ namespace stir { %pythoncode {def __iter__(self): return self._iterator()} #endif #endif -} + } #endif %include "stir/NumericVectorWithOffset.h" @@ -985,267 +986,267 @@ namespace stir { %include "stir/VoxelsOnCartesianGrid.h" %extend stir::VoxelsOnCartesianGrid { - // add read_from_file to this class, as currently there is no way - // to convert the swigged DiscretisedDensity to a VoxelsOnCartesianGrid - static stir::VoxelsOnCartesianGrid * read_from_file(const std::string& filename) + // add read_from_file to this class, as currently there is no way + // to convert the swigged DiscretisedDensity to a VoxelsOnCartesianGrid + static stir::VoxelsOnCartesianGrid * read_from_file(const std::string& filename) { - using namespace stir; - unique_ptr > - ret(read_from_file >(filename)); - return dynamic_cast *>(ret.release()); + using namespace stir; + unique_ptr > + ret(read_from_file >(filename)); + return dynamic_cast *>(ret.release()); } -} + } -//%ADD_indexaccess(int,stir::BasicCoordinate::value_type,stir::BasicCoordinate); -namespace stir { + //%ADD_indexaccess(int,stir::BasicCoordinate::value_type,stir::BasicCoordinate); +namespace stir { #ifdef SWIGPYTHON - // add extra features to the coordinates to make them a bit more Python friendly - %extend BasicCoordinate { - //%feature("autodoc", "construct from tuple, e.g. (2,3,4) for a 3d coordinate") - BasicCoordinate(PyObject* args) - { - BasicCoordinate *c=new BasicCoordinate; - if (!swigstir::coord_from_tuple(*c, args)) - { - throw std::invalid_argument("Wrong type of argument to construct Coordinate used"); - } - return c; - }; - - // print as (1,2,3) as opposed to non-informative default provided by SWIG - std::string __str__() - { - std::ostringstream s; - s<<'('; - for (int d=1; d<=num_dimensions-1; ++d) - s << (*$self)[d] << ", "; - s << (*$self)[num_dimensions] << ')'; - return s.str(); - } - - // print as classname((1,2,3)) as opposed to non-informative default provided by SWIG - std::string __repr__() - { + // add extra features to the coordinates to make them a bit more Python friendly + %extend BasicCoordinate { + //%feature("autodoc", "construct from tuple, e.g. (2,3,4) for a 3d coordinate") + BasicCoordinate(PyObject* args) + { + BasicCoordinate *c=new BasicCoordinate; + if (!swigstir::coord_from_tuple(*c, args)) + { + throw std::invalid_argument("Wrong type of argument to construct Coordinate used"); + } + return c; + }; + + // print as (1,2,3) as opposed to non-informative default provided by SWIG + std::string __str__() + { + std::ostringstream s; + s<<'('; + for (int d=1; d<=num_dimensions-1; ++d) + s << (*$self)[d] << ", "; + s << (*$self)[num_dimensions] << ')'; + return s.str(); + } + + // print as classname((1,2,3)) as opposed to non-informative default provided by SWIG + std::string __repr__() + { #if SWIG_VERSION < 0x020009 - // don't know how to get the Python typename - std::string repr = "stir.Coordinate"; + // don't know how to get the Python typename + std::string repr = "stir.Coordinate"; #else - std::string repr = "$parentclasssymname"; + std::string repr = "$parentclasssymname"; #endif - // TODO attempt to re-use __str__ above, but it doesn't compile, so we replicate the code - // repr += $self->__str__() + ')'; - std::ostringstream s; - s<<"(("; - for (int d=1; d<=num_dimensions-1; ++d) - s << (*$self)[d] << ", "; - s << (*$self)[num_dimensions] << ')'; - repr += s.str() + ")"; - return repr; - } - - bool __nonzero__() const { - return true; - } - - /* Alias for Python 3 compatibility */ - bool __bool__() const { - return true; - } - - size_type __len__() const { - return $self->size(); - } + // TODO attempt to re-use __str__ above, but it doesn't compile, so we replicate the code + // repr += $self->__str__() + ')'; + std::ostringstream s; + s<<"(("; + for (int d=1; d<=num_dimensions-1; ++d) + s << (*$self)[d] << ", "; + s << (*$self)[num_dimensions] << ')'; + repr += s.str() + ")"; + return repr; + } + + bool __nonzero__() const { + return true; + } + + /* Alias for Python 3 compatibility */ + bool __bool__() const { + return true; + } + + size_type __len__() const { + return $self->size(); + } #if defined(SWIGPYTHON_BUILTIN) - %feature("python:slot", "tp_str", functype="reprfunc") __str__; - %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; - %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; - %feature("python:slot", "sq_length", functype="lenfunc") __len__; + %feature("python:slot", "tp_str", functype="reprfunc") __str__; + %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; + %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; + %feature("python:slot", "sq_length", functype="lenfunc") __len__; #endif // SWIGPYTHON_BUILTIN - - } + + } #elif defined(SWIGMATLAB) %extend BasicCoordinate { - // print as [1;2;3] as opposed to non-informative default provided by SWIG - void disp() - { - std::ostringstream s; - s<<'['; - for (int d=1; d<=num_dimensions-1; ++d) - s << (*$self)[d] << "; "; - s << (*$self)[num_dimensions] << "]\n"; - mexPrintf(s.str().c_str()); - - } - //%feature("autodoc", "construct from vector, e.g. [2;3;4] for a 3d coordinate") - BasicCoordinate(const mxArray *pm) - { - $parentclassname * array_ptr = new $parentclassname(); - swigstir::fill_BasicCoordinate_from_matlab(*array_ptr, pm); - return array_ptr; - } - - %newobject to_matlab; - mxArray * to_matlab() - { return swigstir::BasicCoordinate_to_matlab(*$self); } - - void fill(const mxArray *pm) - { swigstir::fill_BasicCoordinate_from_matlab(*$self, pm); } + // print as [1;2;3] as opposed to non-informative default provided by SWIG + void disp() + { + std::ostringstream s; + s<<'['; + for (int d=1; d<=num_dimensions-1; ++d) + s << (*$self)[d] << "; "; + s << (*$self)[num_dimensions] << "]\n"; + mexPrintf(s.str().c_str()); + } -#endif // PYTHON, MATLAB extension of BasicCoordinate - - %ADD_indexaccess(int, coordT, BasicCoordinate); - %template(Int3BasicCoordinate) BasicCoordinate<3,int>; - %template(Size3BasicCoordinate) BasicCoordinate<3,std::size_t>; - %template(Float3BasicCoordinate) BasicCoordinate<3,float>; - %template(Float3Coordinate) Coordinate3D< float >; - %template(FloatCartesianCoordinate3D) CartesianCoordinate3D; - %template(IntCartesianCoordinate3D) CartesianCoordinate3D; - - %template(Int2BasicCoordinate) BasicCoordinate<2,int>; - %template(Size2BasicCoordinate) BasicCoordinate<2,std::size_t>; - %template(Float2BasicCoordinate) BasicCoordinate<2,float>; - // TODO not needed in python case? - %template(Float2Coordinate) Coordinate2D< float >; - %template(FloatCartesianCoordinate2D) CartesianCoordinate2D; - - //#ifndef SWIGPYTHON - // not necessary for Python as we can use tuples there - %template(make_IntCoordinate) make_coordinate; - %template(make_FloatCoordinate) make_coordinate; - //#endif - - %template(IndexRange1D) IndexRange<1>; - // %template(IndexRange1DVectorWithOffset) VectorWithOffset >; - %template(IndexRange2D) IndexRange<2>; - //%template(IndexRange2DVectorWithOffset) VectorWithOffset >; - %template(IndexRange3D) IndexRange<3>; - - %ADD_indexaccess(int,T,VectorWithOffset); - %template(FloatVectorWithOffset) VectorWithOffset; - - // TODO need to instantiate with name? - %template (FloatNumericVectorWithOffset) NumericVectorWithOffset; - + //%feature("autodoc", "construct from vector, e.g. [2;3;4] for a 3d coordinate") + BasicCoordinate(const mxArray *pm) + { + $parentclassname * array_ptr = new $parentclassname(); + swigstir::fill_BasicCoordinate_from_matlab(*array_ptr, pm); + return array_ptr; + } + + %newobject to_matlab; + mxArray * to_matlab() + { return swigstir::BasicCoordinate_to_matlab(*$self); } + + void fill(const mxArray *pm) + { swigstir::fill_BasicCoordinate_from_matlab(*$self, pm); } + } + #endif // PYTHON, MATLAB extension of BasicCoordinate + + %ADD_indexaccess(int, coordT, BasicCoordinate); + %template(Int3BasicCoordinate) BasicCoordinate<3,int>; + %template(Size3BasicCoordinate) BasicCoordinate<3,std::size_t>; + %template(Float3BasicCoordinate) BasicCoordinate<3,float>; + %template(Float3Coordinate) Coordinate3D< float >; + %template(FloatCartesianCoordinate3D) CartesianCoordinate3D; + %template(IntCartesianCoordinate3D) CartesianCoordinate3D; + + %template(Int2BasicCoordinate) BasicCoordinate<2,int>; + %template(Size2BasicCoordinate) BasicCoordinate<2,std::size_t>; + %template(Float2BasicCoordinate) BasicCoordinate<2,float>; + // TODO not needed in python case? + %template(Float2Coordinate) Coordinate2D< float >; + %template(FloatCartesianCoordinate2D) CartesianCoordinate2D; + + //#ifndef SWIGPYTHON + // not necessary for Python as we can use tuples there + %template(make_IntCoordinate) make_coordinate; + %template(make_FloatCoordinate) make_coordinate; + //#endif + + %template(IndexRange1D) IndexRange<1>; + // %template(IndexRange1DVectorWithOffset) VectorWithOffset >; + %template(IndexRange2D) IndexRange<2>; + //%template(IndexRange2DVectorWithOffset) VectorWithOffset >; + %template(IndexRange3D) IndexRange<3>; + + %ADD_indexaccess(int,T,VectorWithOffset); + %template(FloatVectorWithOffset) VectorWithOffset; + + // TODO need to instantiate with name? + %template (FloatNumericVectorWithOffset) NumericVectorWithOffset; + #ifdef SWIGPYTHON - // TODO this extends ND-Arrays, but apparently not 1D Arrays (because specialised template?) - %extend Array{ - // add "flat" iterator, using begin_all() - %newobject flat(PyObject **PYTHON_SELF); - %feature("autodoc", "create a Python iterator over all elements, e.g. array.flat()") flat; - swig::SwigPyIterator* flat(PyObject **PYTHON_SELF) { - return swigstir::make_forward_iterator(self->begin_all(), self->begin_all(), self->end_all(), *PYTHON_SELF); - } - %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]") __getitem__; - elemT __getitem__(PyObject* const args) - { - stir::BasicCoordinate c; - if (!swigstir::coord_from_tuple(c, args)) - { - throw std::invalid_argument("Wrong type of indexing argument used"); - } - return (*$self).at(c); - }; - %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]=4") __setitem__; - void __setitem__(PyObject* const args, const elemT value) - { - stir::BasicCoordinate c; - if (!swigstir::coord_from_tuple(c, args)) - { - throw std::invalid_argument("Wrong type of indexing argument used"); - } - (*$self).at(c) = value; - }; - - %feature("autodoc", "return number of elements per dimension as a tuple, (almost) compatible with numpy. Use as array.shape()") shape; - const PyObject* shape() - { - //const stir::BasicCoordinate c = (*$self).shape(); - stir::BasicCoordinate minind,maxind; - if (!$self->get_regular_range(minind, maxind)) - throw std::range_error("shape called on irregular array"); - stir::BasicCoordinate sizes=maxind-minind+1; - return swigstir::tuple_from_coord(sizes); - } - - %feature("autodoc", "fill from a Python iterator, e.g. array.fill(numpyarray.flat)") fill; - void fill(PyObject* const arg) - { - if (PyIter_Check(arg)) - { - swigstir::fill_Array_from_Python_iterator($self, arg); - } - else - { - char str[1000]; - snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", - arg->ob_type->tp_name); - throw std::invalid_argument(str); - } - } + // TODO this extends ND-Arrays, but apparently not 1D Arrays (because specialised template?) + %extend Array{ + // add "flat" iterator, using begin_all() + %newobject flat(PyObject **PYTHON_SELF); + %feature("autodoc", "create a Python iterator over all elements, e.g. array.flat()") flat; + swig::SwigPyIterator* flat(PyObject **PYTHON_SELF) { + return swigstir::make_forward_iterator(self->begin_all(), self->begin_all(), self->end_all(), *PYTHON_SELF); } -#endif - - %extend Array{ - %feature("autodoc", "return number of dimensions in the array") get_num_dimensions; - int get_num_dimensions() - { - return num_dimensions; - } + %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]") __getitem__; + elemT __getitem__(PyObject* const args) + { + stir::BasicCoordinate c; + if (!swigstir::coord_from_tuple(c, args)) + { + throw std::invalid_argument("Wrong type of indexing argument used"); + } + return (*$self).at(c); + }; + %feature("autodoc", "tuple indexing, e.g. array[(1,2,3)]=4") __setitem__; + void __setitem__(PyObject* const args, const elemT value) + { + stir::BasicCoordinate c; + if (!swigstir::coord_from_tuple(c, args)) + { + throw std::invalid_argument("Wrong type of indexing argument used"); + } + (*$self).at(c) = value; + }; + + %feature("autodoc", "return number of elements per dimension as a tuple, (almost) compatible with numpy. Use as array.shape()") shape; + const PyObject* shape() + { + //const stir::BasicCoordinate c = (*$self).shape(); + stir::BasicCoordinate minind,maxind; + if (!$self->get_regular_range(minind, maxind)) + throw std::range_error("shape called on irregular array"); + stir::BasicCoordinate sizes=maxind-minind+1; + return swigstir::tuple_from_coord(sizes); } - -#ifdef SWIGMATLAB - %extend Array { - Array(const mxArray *pm) - { - $parentclassname * array_ptr = new $parentclassname(); - swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); - return array_ptr; - } - - %newobject to_matlab; - mxArray * to_matlab() - { return swigstir::Array_to_matlab(*$self); } - - void fill(const mxArray *pm) - { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } + + %feature("autodoc", "fill from a Python iterator, e.g. array.fill(numpyarray.flat)") fill; + void fill(PyObject* const arg) + { + if (PyIter_Check(arg)) + { + swigstir::fill_Array_from_Python_iterator($self, arg); + } + else + { + char str[1000]; + snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", + arg->ob_type->tp_name); + throw std::invalid_argument(str); + } } - // repeat this for 1D due to template (partial) specialisation (TODO, get round that somehow) - %extend Array<1,float> { - Array<1,float>(const mxArray *pm) - { - $parentclassname * array_ptr = new $parentclassname(); - swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); - return array_ptr; - } - - %newobject to_matlab; - mxArray * to_matlab() - { return swigstir::Array_to_matlab(*$self); } - - void fill(const mxArray *pm) - { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } + } +#endif + + %extend Array{ + %feature("autodoc", "return number of dimensions in the array") get_num_dimensions; + int get_num_dimensions() + { + return num_dimensions; } + } + +#ifdef SWIGMATLAB + %extend Array { + Array(const mxArray *pm) + { + $parentclassname * array_ptr = new $parentclassname(); + swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); + return array_ptr; + } + + %newobject to_matlab; + mxArray * to_matlab() + { return swigstir::Array_to_matlab(*$self); } + + void fill(const mxArray *pm) + { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } + } + // repeat this for 1D due to template (partial) specialisation (TODO, get round that somehow) + %extend Array<1,float> { + Array<1,float>(const mxArray *pm) + { + $parentclassname * array_ptr = new $parentclassname(); + swigstir::fill_Array_from_matlab(*array_ptr, pm, true /* do resize */); + return array_ptr; + } + + %newobject to_matlab; + mxArray * to_matlab() + { return swigstir::Array_to_matlab(*$self); } + + void fill(const mxArray *pm) + { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } + } #endif - // TODO next line doesn't give anything useful as SWIG doesn't recognise that - // the return value is an array. So, we get a wrapped object that we cannot handle - //%ADD_indexaccess(int,Array::value_type, Array); - - %ADD_indexaccess(%arg(const BasicCoordinate&),elemT, Array); - - %template(FloatArray1D) Array<1,float>; - - // this doesn't work because of bug in swig (incorrectly parses num_dimensions) - //%ADD_indexaccess(int,%arg(Array), Array); - // In any case, even if the above is made to work (e.g. explicit override for every class as below) - // then setitem still doesn't modify the object for more than 1 level + // TODO next line doesn't give anything useful as SWIG doesn't recognise that + // the return value is an array. So, we get a wrapped object that we cannot handle + //%ADD_indexaccess(int,Array::value_type, Array); + + %ADD_indexaccess(%arg(const BasicCoordinate&),elemT, Array); + + %template(FloatArray1D) Array<1,float>; + + // this doesn't work because of bug in swig (incorrectly parses num_dimensions) + //%ADD_indexaccess(int,%arg(Array), Array); + // In any case, even if the above is made to work (e.g. explicit override for every class as below) + // then setitem still doesn't modify the object for more than 1 level #if 1 - // note: next line has no memory allocation problems because all Array<1,...> objects - // are auto-converted to shared_ptrs. - // however, cannot use setitem to modify so ideally we would define getitem only (at least for python) (TODO) - // TODO DISABLE THIS - %ADD_indexaccess(int,%arg(Array<1,float>),%arg(Array<2,float>)); + // note: next line has no memory allocation problems because all Array<1,...> objects + // are auto-converted to shared_ptrs. + // however, cannot use setitem to modify so ideally we would define getitem only (at least for python) (TODO) + // TODO DISABLE THIS + %ADD_indexaccess(int,%arg(Array<1,float>),%arg(Array<2,float>)); #endif - + } // namespace stir %rename (get_scanner) *::get_scanner_ptr; @@ -1256,16 +1257,16 @@ namespace stir { %rename (set_objective_function) *::set_objective_function_sptr; -// Todo need to instantiate with name? -// TODO Swig doesn't see that Array<2,float> is derived from it anyway becuse of num_dimensions bug + // Todo need to instantiate with name? + // TODO Swig doesn't see that Array<2,float> is derived from it anyway becuse of num_dimensions bug %template (FloatNumericVectorWithOffset2D) stir::NumericVectorWithOffset, float>; -%template(FloatArray2D) stir::Array<2,float>; -// TODO name -%template (FloatNumericVectorWithOffset3D) stir::NumericVectorWithOffset, float>; -%template(FloatArray3D) stir::Array<3,float>; + %template(FloatArray2D) stir::Array<2,float>; + // TODO name + %template (FloatNumericVectorWithOffset3D) stir::NumericVectorWithOffset, float>; + %template(FloatArray3D) stir::Array<3,float>; #if 0 -%ADD_indexaccess(int,%arg(stir::Array<2,float>),%arg(stir::Array<3,float>)); + %ADD_indexaccess(int,%arg(stir::Array<2,float>),%arg(stir::Array<3,float>)); #endif %template(Float3DDiscretisedDensity) stir::DiscretisedDensity<3,float>; @@ -1274,6 +1275,7 @@ namespace stir { //%template() stir::DiscretisedDensityOnCartesianGrid<3,float>; %template(FloatVoxelsOnCartesianGrid) stir::VoxelsOnCartesianGrid; + %include "stir/IO/write_to_file.h" %template(write_image_to_file) stir::write_to_file >; @@ -1294,17 +1296,17 @@ namespace stir { #define DataT stir::DiscretisedDensity<3,float> %template(Float3DDiscretisedDensityOutputFileFormat) stir::OutputFileFormat; -//cannot do that as pure virtual functions -//%template(ROOutputFileFormat3DFloat) RegisteredObject< OutputFileFormat< DiscretisedDensity< 3,float > > >; -%template(RPInterfileOutputFileFormat) stir::RegisteredParsingObject, stir::OutputFileFormat >; -#undef DataT + //cannot do that as pure virtual functions + //%template(ROOutputFileFormat3DFloat) RegisteredObject< OutputFileFormat< DiscretisedDensity< 3,float > > >; + %template(RPInterfileOutputFileFormat) stir::RegisteredParsingObject, stir::OutputFileFormat >; + #undef DataT %include "stir/IO/InterfileOutputFileFormat.h" #ifdef HAVE_LLN_MATRIX %include "stir/IO/ECAT7OutputFileFormat.h" #endif -/* Now do ProjDataInfo, Sinogram et al + /* Now do ProjDataInfo, Sinogram et al */ %include "stir/TimeFrameDefinitions.h" %include "stir/ExamInfo.h" @@ -1327,25 +1329,25 @@ namespace stir { %include "stir/ProjDataInfo.h" %newobject *::construct_proj_data_info; -%extend stir::ProjDataInfo +%extend stir::ProjDataInfo { - // work around the current SWIG limitation that it doesn't wrap unique_ptr. - // we do this with the crazy (and ugly) way to let SWIG create a new function - // which is the same as the original, but returns a bare pointer. - // (This will be wrapped as a shared_ptr in the end). - // This work-around is fragile however as it depends on knowledge of the - // exact signature of the function. - static ProjDataInfo * - construct_proj_data_info(const shared_ptr& scanner_sptr, - const int span, const int max_delta, - const int num_views, const int num_tangential_poss, - const bool arc_corrected = true) - { - return - construct_proj_data_info(scanner_sptr, - span, max_delta, num_views, num_tangential_poss, - arc_corrected).get(); - } + // work around the current SWIG limitation that it doesn't wrap unique_ptr. + // we do this with the crazy (and ugly) way to let SWIG create a new function + // which is the same as the original, but returns a bare pointer. + // (This will be wrapped as a shared_ptr in the end). + // This work-around is fragile however as it depends on knowledge of the + // exact signature of the function. + static ProjDataInfo * + construct_proj_data_info(const shared_ptr& scanner_sptr, + const int span, const int max_delta, + const int num_views, const int num_tangential_poss, + const bool arc_corrected = true) + { + return + construct_proj_data_info(scanner_sptr, + span, max_delta, num_views, num_tangential_poss, + arc_corrected).get(); + } } %include "stir/ProjDataInfoCylindrical.h" %include "stir/ProjDataInfoCylindricalArcCorr.h" @@ -1361,68 +1363,68 @@ namespace stir { %include "stir/ProjData.h" namespace stir { - %extend ProjData - { +%extend ProjData + { #ifdef SWIGPYTHON - %feature("autodoc", "create a stir 3D Array from the projection data (internal)") to_array; - %newobject to_array; - Array<3,float> to_array() - { - Array<3,float> array = swigstir::projdata_to_3D(*$self); - return array; - } - - %feature("autodoc", "fill from a Python iterator, e.g. proj_data.fill(numpyarray.flat)") fill; - void fill(PyObject* const arg) - { - if (PyIter_Check(arg)) - { - Array<3,float> array = swigstir::create_array_for_proj_data(*$self); - swigstir::fill_Array_from_Python_iterator(&array, arg); - swigstir::fill_proj_data_from_3D(*$self, array); - } - else - { - char str[1000]; - snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", - arg->ob_type->tp_name); - throw std::invalid_argument(str); - } - } - + %feature("autodoc", "create a stir 3D Array from the projection data (internal)") to_array; + %newobject to_array; + Array<3,float> to_array() + { + Array<3,float> array = swigstir::projdata_to_3D(*$self); + return array; + } + + %feature("autodoc", "fill from a Python iterator, e.g. proj_data.fill(numpyarray.flat)") fill; + void fill(PyObject* const arg) + { + if (PyIter_Check(arg)) + { + Array<3,float> array = swigstir::create_array_for_proj_data(*$self); + swigstir::fill_Array_from_Python_iterator(&array, arg); + swigstir::fill_proj_data_from_3D(*$self, array); + } + else + { + char str[1000]; + snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", + arg->ob_type->tp_name); + throw std::invalid_argument(str); + } + } + #elif defined(SWIGMATLAB) - %newobject to_matlab; - mxArray * to_matlab() - { - Array<3,float> array = swigstir::projdata_to_3D(*$self); - return swigstir::Array_to_matlab(array); - } - - void fill(const mxArray *pm) - { - Array<3,float> array; - swigstir::fill_Array_from_matlab(array, pm, true); - swigstir::fill_proj_data_from_3D(*$self, array); - } -#endif + %newobject to_matlab; + mxArray * to_matlab() + { + Array<3,float> array = swigstir::projdata_to_3D(*$self); + return swigstir::Array_to_matlab(array); } -} + + void fill(const mxArray *pm) + { + Array<3,float> array; + swigstir::fill_Array_from_matlab(array, pm, true); + swigstir::fill_proj_data_from_3D(*$self, array); + } +#endif + } + } %include "stir/ProjDataFromStream.h" %include "stir/ProjDataInterfile.h" %include "stir/ProjDataInMemory.h" -namespace stir { - %template(FloatViewgram) Viewgram; - %template(FloatSinogram) Sinogram; - // TODO don't want to give a name - %template(FloatSegment) Segment; - %template(FloatSegmentBySinogram) SegmentBySinogram; - %template(FloatSegmentByView) SegmentByView; - // should not have the following if using boost_smart_ptr.i - // %template(SharedScanner) boost::shared_ptr; - //%template(SharedProjData) boost::shared_ptr; - +namespace stir { + %template(FloatViewgram) Viewgram; + %template(FloatSinogram) Sinogram; + // TODO don't want to give a name + %template(FloatSegment) Segment; + %template(FloatSegmentBySinogram) SegmentBySinogram; + %template(FloatSegmentByView) SegmentByView; + // should not have the following if using boost_smart_ptr.i + // %template(SharedScanner) boost::shared_ptr; + //%template(SharedProjData) boost::shared_ptr; + } // filters @@ -1430,13 +1432,13 @@ namespace stir { #define elemT float %shared_ptr(stir::DataProcessor >) %shared_ptr(stir::RegisteredParsingObject< - stir::ChainedDataProcessor >, - stir::DataProcessor >, - stir::DataProcessor > >) + stir::ChainedDataProcessor >, + stir::DataProcessor >, + stir::DataProcessor > >) %shared_ptr(stir::ChainedDataProcessor >) %shared_ptr(stir::RegisteredParsingObject, - stir::DataProcessor >, - stir::DataProcessor > >) + stir::DataProcessor >, + stir::DataProcessor > >) %shared_ptr(stir::SeparableCartesianMetzImageFilter) #undef elemT #endif @@ -1448,29 +1450,29 @@ namespace stir { #define elemT float %template(DataProcessor3DFloat) stir::DataProcessor >; %template(RPChainedDataProcessor3DFloat) stir::RegisteredParsingObject< -stir::ChainedDataProcessor >, -stir::DataProcessor >, -stir::DataProcessor > >; + stir::ChainedDataProcessor >, + stir::DataProcessor >, + stir::DataProcessor > >; %template(ChainedDataProcessor3DFloat) stir::ChainedDataProcessor >; %template(RPSeparableCartesianMetzImageFilter3DFloat) stir::RegisteredParsingObject< -stir::SeparableCartesianMetzImageFilter, -stir::DataProcessor >, -stir::DataProcessor > >; + stir::SeparableCartesianMetzImageFilter, + stir::DataProcessor >, + stir::DataProcessor > >; %template(SeparableCartesianMetzImageFilter3DFloat) stir::SeparableCartesianMetzImageFilter; #undef elemT %include "stir/GeneralisedPoissonNoiseGenerator.h" -// reconstruction + // reconstruction #ifdef STIRSWIG_SHARED_PTR #define TargetT stir::DiscretisedDensity<3,float> %shared_ptr(stir::GeneralisedObjectiveFunction); %shared_ptr(stir::PoissonLogLikelihoodWithLinearModelForMean); %shared_ptr(stir::RegisteredParsingObject, - stir::GeneralisedObjectiveFunction, - stir::PoissonLogLikelihoodWithLinearModelForMean >); + stir::GeneralisedObjectiveFunction, + stir::PoissonLogLikelihoodWithLinearModelForMean >); %shared_ptr(stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData); @@ -1478,14 +1480,14 @@ stir::DataProcessor > >; %shared_ptr(stir::IterativeReconstruction); %shared_ptr(stir::RegisteredParsingObject< - stir::OSMAPOSLReconstruction , - stir::Reconstruction < TargetT >, - stir::IterativeReconstruction < TargetT > + stir::OSMAPOSLReconstruction , + stir::Reconstruction < TargetT >, + stir::IterativeReconstruction < TargetT > >) %shared_ptr(stir::RegisteredParsingObject< - stir::OSSPSReconstruction , - stir::Reconstruction < TargetT >, - stir::IterativeReconstruction < TargetT > + stir::OSSPSReconstruction , + stir::Reconstruction < TargetT >, + stir::IterativeReconstruction < TargetT > >) %shared_ptr(stir::OSMAPOSLReconstruction); @@ -1504,7 +1506,7 @@ stir::DataProcessor > >; %include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" %include "stir/recon_buildblock/Reconstruction.h" -// there's a get_objective_function, so we'll ignore the sptr version + // there's a get_objective_function, so we'll ignore the sptr version %ignore *::get_objective_function_sptr; %include "stir/recon_buildblock/IterativeReconstruction.h" %include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" @@ -1525,18 +1527,18 @@ stir::DataProcessor > >; // Without it we don't see the parsing functions in python... // Note: we cannot start it with __ as then we we get a run-time error when we're not using the builtin option %template(RPPoissonLogLikelihoodWithLinearModelForMeanAndProjData3DFloat) stir::RegisteredParsingObject, -stir::GeneralisedObjectiveFunction, -stir::PoissonLogLikelihoodWithLinearModelForMean >; + stir::GeneralisedObjectiveFunction, + stir::PoissonLogLikelihoodWithLinearModelForMean >; %template (PoissonLogLikelihoodWithLinearModelForMeanAndProjData3DFloat) stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData; %inline %{ - template + template stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData * ToPoissonLogLikelihoodWithLinearModelForMeanAndProjData(stir::GeneralisedObjectiveFunction *b) { - return dynamic_cast*>(b); - } - %} + return dynamic_cast*>(b); +} +%} %template(ToPoissonLogLikelihoodWithLinearModelForMeanAndProjData3DFloat) ToPoissonLogLikelihoodWithLinearModelForMeanAndProjData; @@ -1547,15 +1549,15 @@ stir::PoissonLogLikelihoodWithLinearModelForMean >; //%template () stir::IterativeReconstruction; %template (RPOSMAPOSLReconstruction3DFloat) stir::RegisteredParsingObject< -stir::OSMAPOSLReconstruction , -stir::Reconstruction < TargetT >, -stir::IterativeReconstruction < TargetT > ->; + stir::OSMAPOSLReconstruction , + stir::Reconstruction < TargetT >, + stir::IterativeReconstruction < TargetT > + >; %template (RPOSSPSReconstruction) stir::RegisteredParsingObject< -stir::OSSPSReconstruction , -stir::Reconstruction < TargetT >, -stir::IterativeReconstruction < TargetT > ->; + stir::OSSPSReconstruction , + stir::Reconstruction < TargetT >, + stir::IterativeReconstruction < TargetT > + >; %template (OSMAPOSLReconstruction3DFloat) stir::OSMAPOSLReconstruction; %template (OSSPSReconstruction3DFloat) stir::OSSPSReconstruction; @@ -1565,18 +1567,18 @@ stir::IterativeReconstruction < TargetT > /// projectors %shared_ptr(stir::ForwardProjectorByBin); %shared_ptr(stir::RegisteredParsingObject); + stir::ForwardProjectorByBin>); %shared_ptr(stir::ForwardProjectorByBinUsingProjMatrixByBin); %shared_ptr(stir::BackProjectorByBin); %shared_ptr(stir::RegisteredParsingObject); + stir::BackProjectorByBin>); %shared_ptr(stir::BackProjectorByBinUsingProjMatrixByBin); %shared_ptr(stir::ProjMatrixByBin); %shared_ptr(stir::RegisteredParsingObject< - stir::ProjMatrixByBinUsingRayTracing, - stir::ProjMatrixByBin, - stir::ProjMatrixByBin - >); + stir::ProjMatrixByBinUsingRayTracing, + stir::ProjMatrixByBin, + stir::ProjMatrixByBin + >); %shared_ptr(stir::ProjMatrixByBinUsingRayTracing); %include "stir/recon_buildblock/ForwardProjectorByBin.h" @@ -1585,55 +1587,43 @@ stir::IterativeReconstruction < TargetT > %include "stir/recon_buildblock/ProjMatrixByBin.h" %template (internalRPProjMatrixByBinUsingRayTracing) stir::RegisteredParsingObject< -stir::ProjMatrixByBinUsingRayTracing, -stir::ProjMatrixByBin, -stir::ProjMatrixByBin ->; + stir::ProjMatrixByBinUsingRayTracing, + stir::ProjMatrixByBin, + stir::ProjMatrixByBin + >; %include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" %shared_ptr( stir::AddParser); %template (internalAddParserForwardProjectorByBin) -stir::AddParser; -%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) -stir::RegisteredParsingObject; + stir::AddParser; +%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) + stir::RegisteredParsingObject; %include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" %shared_ptr( stir::AddParser); %template (internalAddParserBackProjectorByBin) -stir::AddParser; -%template (internalRPBackProjectorByBinUsingProjMatrixByBin) -stir::RegisteredParsingObject; + stir::AddParser; +%template (internalRPBackProjectorByBinUsingProjMatrixByBin) + stir::RegisteredParsingObject; %include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" - //scatter %shared_ptr(stir::ScatterSimulation); - %shared_ptr(stir::RegisteredParsingObject< stir::SingleScatterSimulation, stir::ScatterSimulation, stir::ScatterSimulation >); - %shared_ptr(stir::SingleScatterSimulation); -shared_ptr(stir::RegisteredParsingObject< - stir::SingleScatterLikelihoodAndGradient, - stir::SingleScatterSimulation, - stir::SingleScatterSimulation - >); - -%shared_ptr(stir::SingleScatterLikelihoodAndGradient); %include "stir/scatter/ScatterSimulation.h" -%include "stir/scatter/SingleScatterSimulation.h" -%include "stir/scatter/SingleScatterLikelihoodAndGradient.h" %template (internalRPSingleScatterSimulation) stir::RegisteredParsingObject< stir::SingleScatterSimulation, @@ -1641,6 +1631,7 @@ stir::ScatterSimulation, stir::ScatterSimulation >; +%include "stir/scatter/SingleScatterSimulation.h" %shared_ptr(stir::ScatterEstimation); @@ -1648,3 +1639,14 @@ stir::ScatterSimulation %include "stir/scatter/ScatterEstimation.h" + +%shared_ptr(stir::RegisteredParsingObject< + stir::SingleScatterLikelihoodAndGradient, + stir::SingleScatterSimulation, + stir::SingleScatterSimulation + >); +%shared_ptr(stir::SingleScatterLikelihoodAndGradient); + + + +%include "stir/scatter/SingleScatterLikelihoodAndGradient.h" From 5832d9b287033cb79c79ef54ae8256d30d61b7fd Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 14 Jun 2018 12:09:33 +0100 Subject: [PATCH 014/274] clean_up --- src/scatter_buildblock/ScatterSimulation.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index b38ba0c635..744587ae2d 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -242,7 +242,7 @@ ScatterSimulation:: ask_parameters() { this->attenuation_threshold = ask_num("attenuation threshold(cm^-1)",0.0f, 5.0f, 0.01f); - this->random = ask_num("random points?",0, 1, 1); + this->random = ask_num("random points?",0, 0, 0); this->use_cache = ask_num(" Use cache?",0, 1, 1); this->density_image_filename = ask_string("density image filename", ""); this->activity_image_filename = ask_string("activity image filename", ""); From 2694037e5aef472f33155684216d3958ea2f3784 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 15 Jun 2018 15:39:48 +0100 Subject: [PATCH 015/274] fix_notation --- src/IO/interfile.cxx | 26 ++++++++++---------- src/scatter_buildblock/ScatterSimulation.cxx | 7 +++--- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/IO/interfile.cxx b/src/IO/interfile.cxx index 63a852cc48..1137681e56 100644 --- a/src/IO/interfile.cxx +++ b/src/IO/interfile.cxx @@ -1029,19 +1029,19 @@ write_basic_interfile_PDFS_header(const string& header_file_name, - for (unsigned int num_windows=0; num_windows<=exam_info_ptr->get_num_energy_windows()-1; ++num_windows) - { - - if (pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows) > 0 && - pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows) >= 0) - { - output_header << "energy window lower level [" << num_windows +1 << "] := " << - pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows) << '\n'; - output_header << "energy window upper level [" << num_windows +1<< "] := " << - pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows) << '\n'; - } - - } + for (unsigned int num_windows = 0; num_windows < exam_info_ptr->get_num_energy_windows(); ++num_windows) + { + + if (pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows ) >= 0 && + pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows ) >= 0) + { + output_header << "energy window lower level [" << num_windows +1 << "] := " << + pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows) << '\n'; + output_header << "energy window upper level [" << num_windows +1 << "] := " << + pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows) << '\n'; + } + + } //just for en_win>1 diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 744587ae2d..03c76e013c 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -73,13 +73,14 @@ if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && } - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + for (int i = 1; i <= this->template_exam_info_sptr->get_num_energy_windows(); ++i) { - std::cerr << "energy window lower level"<<"["< Date: Fri, 15 Jun 2018 15:49:03 +0100 Subject: [PATCH 016/274] fix_nikos --- src/scatter_buildblock/ScatterEstimation.cxx | 2 +- src/scatter_buildblock/ScatterSimulation.cxx | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/scatter_buildblock/ScatterEstimation.cxx b/src/scatter_buildblock/ScatterEstimation.cxx index 478c57009c..106c1ab958 100644 --- a/src/scatter_buildblock/ScatterEstimation.cxx +++ b/src/scatter_buildblock/ScatterEstimation.cxx @@ -962,7 +962,7 @@ process_data() // info("ScatterEstimation: Begin the estimation process..."); for (int i_scat_iter = 1; - i_scat_iter < this->num_scatter_iterations; + i_scat_iter <= this->num_scatter_iterations; i_scat_iter++) { diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 03c76e013c..cfebeef731 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -480,25 +480,23 @@ void ScatterSimulation:: set_output_proj_data(const std::string& filename) { - + if(is_null_ptr(this->proj_data_info_cyl_noarc_cor_sptr)) { error("Template ProjData has not been set. Abord."); } - this->output_proj_data_filename = filename; - if (is_null_ptr(this->template_exam_info_sptr)) { shared_ptr exam_info_sptr(new ExamInfo); this->output_proj_data_sptr.reset(new ProjDataInterfile(exam_info_sptr, this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone(), - this->output_proj_data_filename)); + this->output_proj_data_filename,std::ios::in | std::ios::out | std::ios::trunc)); } else this->output_proj_data_sptr.reset(new ProjDataInterfile(this->template_exam_info_sptr, this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone(), - this->output_proj_data_filename)); + this->output_proj_data_filename,std::ios::in | std::ios::out | std::ios::trunc)); } void From 938cdfda91b0bc36a73ce478ac7ab9564758fcd6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 25 Jun 2018 17:15:41 +0100 Subject: [PATCH 017/274] fix_num_en_win_max --- src/scatter_buildblock/ScatterSimulation.cxx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index cfebeef731..7bfd0479cf 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -65,18 +65,26 @@ process_data() std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; -if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && - this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) -{ - std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) + { + std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; -} + } for (int i = 1; i <= this->template_exam_info_sptr->get_num_energy_windows(); ++i) { std::cerr << "energy window lower level"<<"["< Date: Wed, 18 Jul 2018 17:16:23 +0100 Subject: [PATCH 018/274] zoom_and_filter --- src/IO/InterfileHeader.cxx | 3 ++- src/buildblock/CMakeLists.txt | 4 +++- .../buildblock/SeparableGaussianArrayFilter.cxx | 0 .../buildblock/SeparableGaussianImageFilter.cxx | 8 ++++---- src/buildblock/zoom.cxx | 17 +++++++++++++++-- .../stir/SeparableGaussianArrayFilter.h | 0 .../stir/SeparableGaussianImageFilter.h | 0 src/include/stir/zoom.h | 2 +- 8 files changed, 25 insertions(+), 9 deletions(-) rename src/{local => }/buildblock/SeparableGaussianArrayFilter.cxx (100%) rename src/{local => }/buildblock/SeparableGaussianImageFilter.cxx (95%) rename src/include/{local => }/stir/SeparableGaussianArrayFilter.h (100%) rename src/include/{local => }/stir/SeparableGaussianImageFilter.h (100%) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index 2097ce526e..a801365459 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -359,10 +359,11 @@ bool InterfileHeader::post_processing() //set the lower and the higher energy thresholds for all the energy windows available. Default: 1. - //set the number of energy windows and pair + //set the number of energy windows exam_info_sptr->set_num_energy_windows(num_energy_windows); + //set the number of energy window pair if (energy_window_pair.size() > 0) { if (energy_window_pair.size() != 2) diff --git a/src/buildblock/CMakeLists.txt b/src/buildblock/CMakeLists.txt index b5761a341d..d384f542b3 100644 --- a/src/buildblock/CMakeLists.txt +++ b/src/buildblock/CMakeLists.txt @@ -54,7 +54,9 @@ set(${dir_LIB_SOURCES} ThresholdMinToSmallPositiveValueDataProcessor ChainedDataProcessor ArrayFilter1DUsingConvolution - SeparableConvolutionImageFilter + SeparableConvolutionImageFilter + SeparableGaussianImageFilter + SeparableGaussianArrayFilter NonseparableConvolutionUsingRealDFTImageFilter SSRB inverse_SSRB diff --git a/src/local/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx similarity index 100% rename from src/local/buildblock/SeparableGaussianArrayFilter.cxx rename to src/buildblock/SeparableGaussianArrayFilter.cxx diff --git a/src/local/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx similarity index 95% rename from src/local/buildblock/SeparableGaussianImageFilter.cxx rename to src/buildblock/SeparableGaussianImageFilter.cxx index faac45a9a5..8027a05fc5 100644 --- a/src/local/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -33,9 +33,9 @@ virtual_set_up(const DiscretisedDensity<3,elemT>& density) return Succeeded::no; } - gaussian_filter = + /*gaussian_filter = SeparableGaussianArrayFilter<3,elemT>(standard_deviation, - number_of_coefficients); + number_of_coefficients); */ return Succeeded::yes; } @@ -69,8 +69,8 @@ void SeparableGaussianImageFilter:: set_defaults() { - standard_deviation =0 ; - number_of_coefficients = 0; + //standard_deviation =0 ; + //number_of_coefficients =0; } diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index cd80afc760..389b1426ab 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -365,7 +365,7 @@ zoom_image(const VoxelsOnCartesianGrid &image, void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in) + const VoxelsOnCartesianGrid &image_in, bool rescale) { /* @@ -411,7 +411,7 @@ zoom_image(VoxelsOnCartesianGrid &image_out, (image_out.get_origin().z() - image_in.get_origin().z()) / image_in.get_voxel_size().z(); - + if(zoom_x==1.0F && zoom_y==1.0F && zoom_z==1.0F && x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && image_in.get_index_range() == image_out.get_index_range() @@ -442,6 +442,19 @@ zoom_image(VoxelsOnCartesianGrid &image_out, overlap_interpolate(image_out, temp2, zoom_z, z_offset); + + //rescaling the image + + if (rescale) + + { + BasicCoordinate<3,float> orig_grid = image_in.get_grid_spacing(); + BasicCoordinate<3,float> new_grid = image_out.get_grid_spacing(); + float scale_att = (orig_grid[3]/new_grid[3]) * (orig_grid[2]/new_grid[2]) * (orig_grid[1]/new_grid[1]); + + image_out*= scale_att; + } + } void diff --git a/src/include/local/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h similarity index 100% rename from src/include/local/stir/SeparableGaussianArrayFilter.h rename to src/include/stir/SeparableGaussianArrayFilter.h diff --git a/src/include/local/stir/SeparableGaussianImageFilter.h b/src/include/stir/SeparableGaussianImageFilter.h similarity index 100% rename from src/include/local/stir/SeparableGaussianImageFilter.h rename to src/include/stir/SeparableGaussianImageFilter.h diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index c056e0bf91..399dd8cc4d 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -192,7 +192,7 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, */ void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in); + const VoxelsOnCartesianGrid &image_in, bool rescale = false); //------------------ 2D zooms--------------------- From 6044a9629d78fc57d748076b545574e21dffb149 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Jul 2018 17:19:37 +0100 Subject: [PATCH 019/274] edit --- src/buildblock/SeparableGaussianImageFilter.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index 8027a05fc5..8510c3885d 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -69,8 +69,8 @@ void SeparableGaussianImageFilter:: set_defaults() { - //standard_deviation =0 ; - //number_of_coefficients =0; + standard_deviation =0 ; + number_of_coefficients =0; } From 2623e3302818a070c3c3be965bda752a3bbfbb90 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Jul 2018 17:44:53 +0100 Subject: [PATCH 020/274] ok --- .../SeparableGaussianArrayFilter.cxx | 21 +++++++++++++------ .../SeparableGaussianImageFilter.cxx | 2 +- .../stir/SeparableGaussianArrayFilter.h | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 83671b57fc..42b75ee15c 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -1,5 +1,5 @@ -#include "local/stir/SeparableGaussianArrayFilter.h" +#include "stir/SeparableGaussianArrayFilter.h" #include "stir/ArrayFilter1DUsingConvolution.h" #include "stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h" #include "stir/info.h" @@ -39,14 +39,23 @@ template SeparableGaussianArrayFilter:: SeparableGaussianArrayFilter(const float standard_deviation_v, const int number_of_coefficients_v) - :standard_deviation(standard_deviation_v), - number_of_coefficients(number_of_coefficients_v) + { - + standard_deviation = standard_deviation_v; + number_of_coefficients = number_of_coefficients_v; + bool normalise; + construct_filter(normalise); +} + +template +void +SeparableGaussianArrayFilter:: +construct_filter(bool normalise) +{ VectorWithOffset filter_coefficients; - calculate_coefficients(filter_coefficients, number_of_coefficients_v, - standard_deviation_v); + calculate_coefficients(filter_coefficients, number_of_coefficients, + standard_deviation); info("Printing filter coefficients - nonrescaled"); for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index 8510c3885d..d38c0a3d32 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -1,5 +1,5 @@ -#include "local/stir/SeparableGaussianImageFilter.h" +#include "stir/SeparableGaussianImageFilter.h" #include "stir/VoxelsOnCartesianGrid.h" START_NAMESPACE_STIR diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index 582a970b77..58364bd652 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -48,6 +48,7 @@ class SeparableGaussianArrayFilter: void calculate_coefficients(VectorWithOffset& filter_coefficients, const int number_of_coefficients, const float standard_deviation); + void construct_filter(bool normalise = false); float standard_deviation; int number_of_coefficients; From b63ae3508f8b0a1a8b4ff9b40853c30c495fae32 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Jul 2018 18:07:34 +0100 Subject: [PATCH 021/274] filter --- .../SeparableGaussianArrayFilter.cxx | 53 ++++++------------- .../stir/SeparableGaussianArrayFilter.h | 10 ++-- 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 42b75ee15c..b19e596b8e 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -24,7 +24,7 @@ START_NAMESPACE_STIR template SeparableGaussianArrayFilter:: SeparableGaussianArrayFilter() -:standard_deviation(0),number_of_coefficients(0) +//:standard_deviation(0),number_of_coefficients(0) { for (int i=1;i<=num_dimensions;i++) @@ -37,14 +37,19 @@ SeparableGaussianArrayFilter() template SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter(const float standard_deviation_v, - const int number_of_coefficients_v) +SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& standard_deviation_v, + const BasicCoordinate< num_dimensions,int>& number_of_coefficients_v, bool normalise) { - standard_deviation = standard_deviation_v; - number_of_coefficients = number_of_coefficients_v; - bool normalise; + +for (int i = 1; i<=num_dimensions;i++) + { + standard_deviation[i]=standard_deviation_v[i]; + number_of_coefficients[i]=number_of_coefficients_v[i]; + + } + construct_filter(normalise); } @@ -54,40 +59,16 @@ SeparableGaussianArrayFilter:: construct_filter(bool normalise) { VectorWithOffset filter_coefficients; - calculate_coefficients(filter_coefficients, number_of_coefficients, - standard_deviation); - - info("Printing filter coefficients - nonrescaled"); - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) - info(boost::format("%1% %2% ") % i % filter_coefficients[i]); - - // rescaled to dc =1 - /* float sum =0.F; - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) - { - sum +=double (filter_coefficients[i]); - } - - cerr << " SUM IS " << sum << endl; + for (int i = 1; i<=number_of_coefficients.size();i++) + { + calculate_coefficients(filter_coefficients, number_of_coefficients[i], + standard_deviation[i]); - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) - { - filter_coefficients[i] /= sum; - } - cerr << " here - rescaled" << endl; - cerr << "Printing filter coefficients" << endl; - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) - cerr << i<<" "<< filter_coefficients[i] <<" " << endl; - */ - this->all_1d_array_filters[2]. - reset(new ArrayFilter1DUsingConvolution(filter_coefficients)); - this->all_1d_array_filters[0]. - reset(new ArrayFilter1DUsingConvolution()); - this->all_1d_array_filters[1]. + this->all_1d_array_filters[i]. reset(new ArrayFilter1DUsingConvolution(filter_coefficients)); - + } } template void diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index 58364bd652..c30e5be002 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -40,8 +40,9 @@ class SeparableGaussianArrayFilter: //! Default constructor SeparableGaussianArrayFilter(); - SeparableGaussianArrayFilter(const float standard_deviation, - const int number_of_coefficients); + SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& standard_deviation, + const BasicCoordinate< num_dimensions,int>& number_of_coefficients, + bool normalise = false); private: @@ -49,8 +50,9 @@ class SeparableGaussianArrayFilter: const int number_of_coefficients, const float standard_deviation); void construct_filter(bool normalise = false); - float standard_deviation; - int number_of_coefficients; + + BasicCoordinate< num_dimensions,float> standard_deviation; + BasicCoordinate< num_dimensions,int> number_of_coefficients; }; From 4b21a74c79ddd75c7230fa6f17126abc12b89b3c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Jul 2018 18:11:44 +0100 Subject: [PATCH 022/274] ok --- .../SeparableGaussianArrayFilter.cxx | 40 ++++++++++++++++--- .../stir/SeparableGaussianArrayFilter.h | 7 +++- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index b19e596b8e..07b97f4e2b 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -53,6 +53,7 @@ for (int i = 1; i<=num_dimensions;i++) construct_filter(normalise); } + template void SeparableGaussianArrayFilter:: @@ -60,21 +61,23 @@ construct_filter(bool normalise) { VectorWithOffset filter_coefficients; for (int i = 1; i<=number_of_coefficients.size();i++) + { - calculate_coefficients(filter_coefficients, number_of_coefficients[i], - standard_deviation[i]); + calculate_coefficients(filter_coefficients, number_of_coefficients[i], + standard_deviation[i],normalise); - this->all_1d_array_filters[i]. + this->all_1d_array_filters[i]. reset(new ArrayFilter1DUsingConvolution(filter_coefficients)); } } + template void SeparableGaussianArrayFilter:: calculate_coefficients(VectorWithOffset& filter_coefficients, const int number_of_coefficients, - const float standard_deviation) + const float standard_deviation, bool normalise) { @@ -88,9 +91,36 @@ calculate_coefficients(VectorWithOffset& filter_coefficients, const int n exp(-square(i)/(2.*square(standard_deviation)))/ sqrt(2*square(standard_deviation)*_PI); } - + + +// normalisation: rescaled to dc =1 + +if (normalise) + + { + + float sum = 0.F; + for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) + { + sum +=double (filter_coefficients[i]); + } + + cerr << " SUM IS " << sum << endl; + + for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) + { + filter_coefficients[i] /= sum; + } + + cerr << " here - rescaled" << endl; + cerr << "Printing filter coefficients" << endl; + for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) + cerr << i<<" "<< filter_coefficients[i] <<" " << endl; + + } } + template class SeparableGaussianArrayFilter<3,float>; END_NAMESPACE_STIR diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index c30e5be002..2351d8b389 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -46,10 +46,13 @@ class SeparableGaussianArrayFilter: private: + + void construct_filter(bool normalise = false); + void calculate_coefficients(VectorWithOffset& filter_coefficients, const int number_of_coefficients, - const float standard_deviation); - void construct_filter(bool normalise = false); + const float standard_deviation, bool normalise); + BasicCoordinate< num_dimensions,float> standard_deviation; BasicCoordinate< num_dimensions,int> number_of_coefficients; From 6543a25b1dc14c7521fbb2f8614c1455a0aea70b Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Jul 2018 18:23:31 +0100 Subject: [PATCH 023/274] ok2 --- src/buildblock/SeparableGaussianArrayFilter.cxx | 1 + src/buildblock/SeparableGaussianImageFilter.cxx | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 07b97f4e2b..702459f811 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -44,6 +44,7 @@ SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& stand { for (int i = 1; i<=num_dimensions;i++) + { standard_deviation[i]=standard_deviation_v[i]; number_of_coefficients[i]=number_of_coefficients_v[i]; diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index d38c0a3d32..2cfe7e3097 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -33,6 +33,11 @@ virtual_set_up(const DiscretisedDensity<3,elemT>& density) return Succeeded::no; } + + const float rescale = dynamic_cast*>(&density)->get_grid_spacing()[3]/10; + + + /*gaussian_filter = SeparableGaussianArrayFilter<3,elemT>(standard_deviation, number_of_coefficients); */ From f88fd3618b6561eabded1511d6e26584fb477621 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 19 Jul 2018 09:46:21 +0100 Subject: [PATCH 024/274] default --- src/buildblock/SeparableGaussianArrayFilter.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 702459f811..316a5406c5 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -27,6 +27,15 @@ SeparableGaussianArrayFilter() //:standard_deviation(0),number_of_coefficients(0) { + for (int i = 1; i<=num_dimensions;i++) + + { + standard_deviation[i] = 0; + number_of_coefficients[i]= 0; + + } + + for (int i=1;i<=num_dimensions;i++) { this->all_1d_array_filters[i-1]. From 09e727b29dfa1417d5a5086abd9c26194ee1ff52 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 19 Jul 2018 11:54:01 +0100 Subject: [PATCH 025/274] kris_edit --- .../SeparableGaussianArrayFilter.cxx | 39 +++++++++---------- .../SeparableGaussianImageFilter.cxx | 16 ++++---- src/buildblock/zoom.cxx | 12 ++++-- .../stir/SeparableGaussianArrayFilter.h | 4 +- src/include/stir/zoom.h | 2 +- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 316a5406c5..d2e25a3355 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -24,18 +24,9 @@ START_NAMESPACE_STIR template SeparableGaussianArrayFilter:: SeparableGaussianArrayFilter() -//:standard_deviation(0),number_of_coefficients(0) +:standard_deviation(0),number_of_coefficients(0) { - for (int i = 1; i<=num_dimensions;i++) - - { - standard_deviation[i] = 0; - number_of_coefficients[i]= 0; - - } - - for (int i=1;i<=num_dimensions;i++) { this->all_1d_array_filters[i-1]. @@ -43,22 +34,26 @@ SeparableGaussianArrayFilter() } } +template +SeparableGaussianArrayFilter:: +SeparableGaussianArrayFilter(const float standard_deviation_v,const float number_of_coefficients_v, bool normalise) +:standard_deviation(standard_deviation_v),number_of_coefficients(number_of_coefficients_v) + { + + //normalisation to 1 is optinal + + construct_filter(normalise); + } + template SeparableGaussianArrayFilter:: SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& standard_deviation_v, const BasicCoordinate< num_dimensions,int>& number_of_coefficients_v, bool normalise) - +:standard_deviation(standard_deviation_v),number_of_coefficients(0) { - -for (int i = 1; i<=num_dimensions;i++) - - { - standard_deviation[i]=standard_deviation_v[i]; - number_of_coefficients[i]=number_of_coefficients_v[i]; - - } +//normalisation to 1 is optinal construct_filter(normalise); } @@ -90,7 +85,11 @@ calculate_coefficients(VectorWithOffset& filter_coefficients, const int n const float standard_deviation, bool normalise) { - + if (standard_deviation==0) + { + filter_coefficients.recycle(); + return; + } filter_coefficients.grow(-number_of_coefficients,number_of_coefficients); filter_coefficients[0] = 1/sqrt(2*square(standard_deviation)*_PI); diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index 2cfe7e3097..6f73b41f5f 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -33,14 +33,12 @@ virtual_set_up(const DiscretisedDensity<3,elemT>& density) return Succeeded::no; } + //const float rescale = dynamic_cast*>(&density)->get_grid_spacing(); - const float rescale = dynamic_cast*>(&density)->get_grid_spacing()[3]/10; - - - /*gaussian_filter = - SeparableGaussianArrayFilter<3,elemT>(standard_deviation, - number_of_coefficients); */ + gaussian_filter = + SeparableGaussianArrayFilter<3,elemT>(standard_deviation, + number_of_coefficients); return Succeeded::yes; } @@ -52,8 +50,9 @@ SeparableGaussianImageFilter:: virtual_apply(DiscretisedDensity<3,elemT>& density) const { - - gaussian_filter(density); + + + gaussian_filter(density); } @@ -65,6 +64,7 @@ virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const { + gaussian_filter(out_density,in_density); } diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 389b1426ab..07cb6f6809 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -46,6 +46,7 @@ #include "stir/ProjDataInfoCylindricalArcCorr.h" #include "stir/IndexRange3D.h" #include "stir/IndexRange2D.h" +#include "local/stir/SeparableGaussianImageFilter.h" #include START_NAMESPACE_STIR @@ -365,7 +366,7 @@ zoom_image(const VoxelsOnCartesianGrid &image, void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale) + const VoxelsOnCartesianGrid &image_in, bool rescale, bool filter) { /* @@ -450,11 +451,16 @@ zoom_image(VoxelsOnCartesianGrid &image_out, { BasicCoordinate<3,float> orig_grid = image_in.get_grid_spacing(); BasicCoordinate<3,float> new_grid = image_out.get_grid_spacing(); - float scale_att = (orig_grid[3]/new_grid[3]) * (orig_grid[2]/new_grid[2]) * (orig_grid[1]/new_grid[1]); + float scale_image = (orig_grid[3]/new_grid[3]) * (orig_grid[2]/new_grid[2]) * (orig_grid[1]/new_grid[1]); - image_out*= scale_att; + image_out*= scale_image; } + + //apply filter +// if (filter) + + } void diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index 2351d8b389..a323ccb16a 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -44,7 +44,9 @@ class SeparableGaussianArrayFilter: const BasicCoordinate< num_dimensions,int>& number_of_coefficients, bool normalise = false); - + SeparableGaussianArrayFilter(const float standard_deviation, + const float number_of_coefficients, + bool normalise = false); private: void construct_filter(bool normalise = false); diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 399dd8cc4d..0ceba98e6b 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -192,7 +192,7 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, */ void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale = false); + const VoxelsOnCartesianGrid &image_in, bool rescale = false, bool filter = false); //------------------ 2D zooms--------------------- From 94667a73fdd2c17e925a3f38b6eed9b05f6117c5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 19 Jul 2018 12:39:17 +0100 Subject: [PATCH 026/274] ok --- .../SeparableGaussianArrayFilter.cxx | 2 +- .../SeparableGaussianImageFilter.cxx | 54 ++++++++++--------- .../stir/SeparableGaussianImageFilter.h | 8 +-- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index d2e25a3355..1af140be2c 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -51,7 +51,7 @@ SeparableGaussianArrayFilter:: SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& standard_deviation_v, const BasicCoordinate< num_dimensions,int>& number_of_coefficients_v, bool normalise) -:standard_deviation(standard_deviation_v),number_of_coefficients(0) +:standard_deviation(standard_deviation_v),number_of_coefficients(number_of_coefficients_v) { //normalisation to 1 is optinal diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index 6f73b41f5f..6de0173d4d 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -13,11 +13,19 @@ SeparableGaussianImageFilter() } template -float +VectorWithOffset SeparableGaussianImageFilter:: -get_standard_deviation() +get_fwhms() { - return standard_deviation; + return fwhms; +} + +template +VectorWithOffset +SeparableGaussianImageFilter:: +get_max_kernel_sizes() +{ + return max_kernel_sizes; } template @@ -35,10 +43,14 @@ virtual_set_up(const DiscretisedDensity<3,elemT>& density) //const float rescale = dynamic_cast*>(&density)->get_grid_spacing(); + const VoxelsOnCartesianGrid& image = + dynamic_cast&>(density); + + // gaussian_filter = + /* SeparableGaussianArrayFilter<3,elemT>(get_metz_fwhms(), + image.get_voxel_size(), + get_max_kernel_sizes());*/ - gaussian_filter = - SeparableGaussianArrayFilter<3,elemT>(standard_deviation, - number_of_coefficients); return Succeeded::yes; } @@ -74,8 +86,8 @@ void SeparableGaussianImageFilter:: set_defaults() { - standard_deviation =0 ; - number_of_coefficients =0; + fwhms.fill(0); + max_kernel_sizes.fill(-1); } @@ -85,27 +97,17 @@ SeparableGaussianImageFilter:: initialise_keymap() { this->parser.add_start_key("Separable Gaussian Filter Parameters"); - this->parser.add_key ("standard_deviation", &standard_deviation); - this->parser.add_key ("number_of_coefficients", &number_of_coefficients); - this->parser.add_stop_key("END Separable Gaussian Filter Parameters"); + this->parser.add_key("x-dir filter FWHM (in mm)", &fwhms[3]); + this->parser.add_key("y-dir filter FWHM (in mm)", &fwhms[2]); + this->parser.add_key("z-dir filter FWHM (in mm)", &fwhms[1]); -} + this->parser.add_key("x-dir maximum kernel size", &max_kernel_sizes[3]); + this->parser.add_key("y-dir maximum kernel size", &max_kernel_sizes[2]); + this->parser.add_key("z-dir maximum kernel size", &max_kernel_sizes[1]); -template -bool -SeparableGaussianImageFilter:: -post_processing() -{ - return false; - /*const unsigned int size = filter_coefficients_for_parsing.size(); - const int min_index = -(size/2); - filter_coefficients.grow(min_index, min_index + size - 1); - for (int i = min_index; i<= filter_coefficients.get_max_index(); ++i) - filter_coefficients[i] = - static_cast(filter_coefficients_for_parsing[i-min_index]); - return false;*/ -} + this->parser.add_stop_key("END Separable Gaussian Filter Parameters"); +} template<> diff --git a/src/include/stir/SeparableGaussianImageFilter.h b/src/include/stir/SeparableGaussianImageFilter.h index 5b5b0fd5a4..8c75a624f8 100644 --- a/src/include/stir/SeparableGaussianImageFilter.h +++ b/src/include/stir/SeparableGaussianImageFilter.h @@ -54,12 +54,12 @@ class SeparableGaussianImageFilter : //! Default constructor SeparableGaussianImageFilter(); - float get_standard_deviation(); - + VectorWithOffset get_fwhms(); + VectorWithOffset get_max_kernel_sizes(); private: - float standard_deviation; - int number_of_coefficients; + VectorWithOffset fwhms; + VectorWithOffset max_kernel_sizes; SeparableGaussianArrayFilter gaussian_filter; From 22a0c8e19dc4e479d52c9620f2d653f67e2c968b Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 19 Jul 2018 17:02:21 +0100 Subject: [PATCH 027/274] filter --- .../SeparableGaussianArrayFilter.cxx | 36 ++++--- .../SeparableGaussianImageFilter.cxx | 39 +++++--- src/buildblock/zoom.cxx | 95 ++++++++++++++++++- .../stir/SeparableGaussianArrayFilter.h | 17 ++-- .../stir/SeparableGaussianImageFilter.h | 12 ++- src/include/stir/zoom.h | 10 +- .../local_buildblock_registries.cxx | 2 +- 7 files changed, 167 insertions(+), 44 deletions(-) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 1af140be2c..8e75616092 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -24,7 +24,7 @@ START_NAMESPACE_STIR template SeparableGaussianArrayFilter:: SeparableGaussianArrayFilter() -:standard_deviation(0),number_of_coefficients(0) +:fwhm(0),max_kernel_sizes(0) { for (int i=1;i<=num_dimensions;i++) @@ -36,8 +36,8 @@ SeparableGaussianArrayFilter() template SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter(const float standard_deviation_v,const float number_of_coefficients_v, bool normalise) -:standard_deviation(standard_deviation_v),number_of_coefficients(number_of_coefficients_v) +SeparableGaussianArrayFilter(const float fwhm_v,const float max_kernel_sizes_v, bool normalise) +:fwhm(fwhm_v),max_kernel_sizes(max_kernel_sizes_v) { //normalisation to 1 is optinal @@ -48,10 +48,10 @@ SeparableGaussianArrayFilter(const float standard_deviation_v,const float number template SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& standard_deviation_v, - const BasicCoordinate< num_dimensions,int>& number_of_coefficients_v, bool normalise) +SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& fwhm_v, + const BasicCoordinate< num_dimensions,int>& max_kernel_sizes_v, bool normalise) -:standard_deviation(standard_deviation_v),number_of_coefficients(number_of_coefficients_v) +:fwhm(fwhm_v),max_kernel_sizes(max_kernel_sizes_v) { //normalisation to 1 is optinal @@ -65,11 +65,11 @@ SeparableGaussianArrayFilter:: construct_filter(bool normalise) { VectorWithOffset filter_coefficients; - for (int i = 1; i<=number_of_coefficients.size();i++) + for (int i = 1; i<=max_kernel_sizes.size();i++) { - calculate_coefficients(filter_coefficients, number_of_coefficients[i], - standard_deviation[i],normalise); + calculate_coefficients(filter_coefficients, max_kernel_sizes[i], + fwhm[i],normalise); this->all_1d_array_filters[i]. @@ -81,24 +81,34 @@ construct_filter(bool normalise) template void SeparableGaussianArrayFilter:: -calculate_coefficients(VectorWithOffset& filter_coefficients, const int number_of_coefficients, - const float standard_deviation, bool normalise) +calculate_coefficients(VectorWithOffset& filter_coefficients, const int max_kernel_sizes, + const float fwhm, bool normalise) { + + float standard_deviation = sqrt(fwhm*fwhm/(8*log(2.F))); + if (standard_deviation==0) { filter_coefficients.recycle(); return; } - filter_coefficients.grow(-number_of_coefficients,number_of_coefficients); + + const int kernel_lenght = max_kernel_sizes/2; + filter_coefficients.grow(-kernel_lenght,kernel_lenght); + filter_coefficients[0] = 1/sqrt(2*square(standard_deviation)*_PI); - for (int i = 1; i<=number_of_coefficients;i++) + for (int i = 1; i<=kernel_lenght;i++) { filter_coefficients[i] = filter_coefficients[-i]= exp(-square(i)/(2.*square(standard_deviation)))/ sqrt(2*square(standard_deviation)*_PI); + +// kernel.grow(0,2*max_kernel_size-1); + + } diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index 6de0173d4d..cdd7e62da2 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -1,9 +1,14 @@ #include "stir/SeparableGaussianImageFilter.h" +#include "stir/SeparableGaussianArrayFilter.h" #include "stir/VoxelsOnCartesianGrid.h" START_NAMESPACE_STIR +//TODO remove define + +#define num_dimensions 3 + template SeparableGaussianImageFilter:: SeparableGaussianImageFilter() @@ -12,21 +17,33 @@ SeparableGaussianImageFilter() set_defaults(); } + template -VectorWithOffset +BasicCoordinate< num_dimensions,float> SeparableGaussianImageFilter:: get_fwhms() { return fwhms; } + template -VectorWithOffset +BasicCoordinate< num_dimensions,int> SeparableGaussianImageFilter:: get_max_kernel_sizes() { return max_kernel_sizes; } + + +template +bool +SeparableGaussianImageFilter:: +get_normalised_filter() +{ + return normalise; +} + template Succeeded @@ -41,15 +58,11 @@ virtual_set_up(const DiscretisedDensity<3,elemT>& density) return Succeeded::no; } - //const float rescale = dynamic_cast*>(&density)->get_grid_spacing(); - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(density); + const BasicCoordinate< num_dimensions,float> rescale = dynamic_cast*>(&density)->get_grid_spacing(); - // gaussian_filter = - /* SeparableGaussianArrayFilter<3,elemT>(get_metz_fwhms(), - image.get_voxel_size(), - get_max_kernel_sizes());*/ + + gaussian_filter = SeparableGaussianArrayFilter(get_fwhms(),get_max_kernel_sizes(),get_normalised_filter()); return Succeeded::yes; @@ -76,7 +89,6 @@ virtual_apply(DiscretisedDensity<3,elemT>& out_density, const DiscretisedDensity<3,elemT>& in_density) const { - gaussian_filter(out_density,in_density); } @@ -86,8 +98,9 @@ void SeparableGaussianImageFilter:: set_defaults() { - fwhms.fill(0); - max_kernel_sizes.fill(-1); + fwhms.fill(0); + max_kernel_sizes.fill(-1); + normalise = false; } @@ -105,6 +118,8 @@ initialise_keymap() this->parser.add_key("y-dir maximum kernel size", &max_kernel_sizes[2]); this->parser.add_key("z-dir maximum kernel size", &max_kernel_sizes[1]); + this->parser.add_key("Normalise filter to 1", &normalise); + this->parser.add_stop_key("END Separable Gaussian Filter Parameters"); } diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 07cb6f6809..546ae087f9 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -39,6 +39,8 @@ #include "stir/interpolate.h" #include "stir/zoom.h" +#include "stir/DataProcessor.h" +#include "stir/DiscretisedDensity.h" #include "stir/VoxelsOnCartesianGrid.h" #include "stir/PixelsOnCartesianGrid.h" #include "stir/Viewgram.h" @@ -46,7 +48,7 @@ #include "stir/ProjDataInfoCylindricalArcCorr.h" #include "stir/IndexRange3D.h" #include "stir/IndexRange2D.h" -#include "local/stir/SeparableGaussianImageFilter.h" +#include "stir/SeparableGaussianImageFilter.h" #include START_NAMESPACE_STIR @@ -364,9 +366,10 @@ zoom_image(const VoxelsOnCartesianGrid &image, return new_image; } + void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale, bool filter) + const VoxelsOnCartesianGrid &image_in, bool rescale, bool apply_filter, shared_ptr > > filter_ptr) { /* @@ -458,11 +461,97 @@ zoom_image(VoxelsOnCartesianGrid &image_out, //apply filter -// if (filter) + + if (apply_filter) + { + filter_ptr->apply(image_out); + } +} + +void +zoom_image(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in) +{ + +/* + interpolation routine uses the following relation: + x_in_index = x_out_index/zoom + offset + + compare to 'physical' coordinates + x_phys = (x_index) * voxel_size.x + origin.x + + as x_in_phys == x_out_phys, we find + (x_in_index)* voxel_size_in.x + origin_in.x == + (x_out_index )* voxel_size_out.x + origin_out.x + <=> + x_in_index = (x_out_index * voxel_size_out.x + + origin_out.x - origin_in.x) + / voxel_size_in.x + + so, zoom= voxel_size_in.x/ voxel_size_out.x + offset = (origin_out.x - origin_in.x)/ voxel_size_in.x + + */ + // check relation between indices and physical coordinates + { + const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); + if (norm(image_in.get_physical_coordinates_for_indices(indices) + - (image_in.get_voxel_size() * BasicCoordinate<3,float>(indices) + image_in.get_origin()) + ) > 2.F) + error("zoom_image is confused about the relation between indices and physical coordinates"); + } + const float zoom_x = + image_in.get_voxel_size().x() / image_out.get_voxel_size().x(); + const float zoom_y = + image_in.get_voxel_size().y() / image_out.get_voxel_size().y(); + const float zoom_z = + image_in.get_voxel_size().z() / image_out.get_voxel_size().z(); + const float x_offset = + (image_out.get_origin().x() - image_in.get_origin().x()) + / image_in.get_voxel_size().x(); + const float y_offset = + (image_out.get_origin().y() - image_in.get_origin().y()) + / image_in.get_voxel_size().y(); + const float z_offset = + (image_out.get_origin().z() - image_in.get_origin().z()) + / image_in.get_voxel_size().z(); + + + if(zoom_x==1.0F && zoom_y==1.0F && zoom_z==1.0F && + x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && + image_in.get_index_range() == image_out.get_index_range() + ) + { + image_out = image_in; + return; + } + + // TODO creating a lot of new images here... + Array<3,float> + temp(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), + image_in.get_min_y(), image_in.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); + + for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) + for (int y=image_in.get_min_y(); y<=image_in.get_max_y(); y++) + overlap_interpolate(temp[z][y], image_in[z][y], zoom_x, x_offset); + + Array<3,float> temp2(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), + image_out.get_min_y(), image_out.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); + + for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) + overlap_interpolate(temp2[z], temp[z], zoom_y, y_offset); + + temp.recycle(); + + overlap_interpolate(image_out, temp2, zoom_z, z_offset); } + + void zoom_image(PixelsOnCartesianGrid &image2D_out, const PixelsOnCartesianGrid &image2D_in) diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index a323ccb16a..f17857d57a 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -25,6 +25,7 @@ #include "stir/DiscretisedDensity.h" #include "stir/SeparableArrayFunctionObject.h" #include "stir/Array.h" +#include "stir/BasicCoordinate.h" #include @@ -40,24 +41,24 @@ class SeparableGaussianArrayFilter: //! Default constructor SeparableGaussianArrayFilter(); - SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& standard_deviation, - const BasicCoordinate< num_dimensions,int>& number_of_coefficients, + SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& fwhm, + const BasicCoordinate< num_dimensions,int>& max_kernel_sizes, bool normalise = false); - SeparableGaussianArrayFilter(const float standard_deviation, - const float number_of_coefficients, + SeparableGaussianArrayFilter(const float fwhm, + const float max_kernel_sizes, bool normalise = false); private: void construct_filter(bool normalise = false); void calculate_coefficients(VectorWithOffset& filter_coefficients, - const int number_of_coefficients, - const float standard_deviation, bool normalise); + const int max_kernel_sizes, + const float fwhm, bool normalise); - BasicCoordinate< num_dimensions,float> standard_deviation; - BasicCoordinate< num_dimensions,int> number_of_coefficients; + BasicCoordinate< num_dimensions,float> fwhm; + BasicCoordinate< num_dimensions,int> max_kernel_sizes; }; diff --git a/src/include/stir/SeparableGaussianImageFilter.h b/src/include/stir/SeparableGaussianImageFilter.h index 8c75a624f8..245abe77b7 100644 --- a/src/include/stir/SeparableGaussianImageFilter.h +++ b/src/include/stir/SeparableGaussianImageFilter.h @@ -19,7 +19,7 @@ #define __stir_SeparableGaussianImageFilter_H__ -#include "local/stir/SeparableGaussianArrayFilter.h" +#include "stir/SeparableGaussianArrayFilter.h" #include "stir/RegisteredParsingObject.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" @@ -54,12 +54,14 @@ class SeparableGaussianImageFilter : //! Default constructor SeparableGaussianImageFilter(); - VectorWithOffset get_fwhms(); - VectorWithOffset get_max_kernel_sizes(); + BasicCoordinate< num_dimensions,float> get_fwhms(); + BasicCoordinate< num_dimensions,int> get_max_kernel_sizes(); + bool get_normalised_filter(); private: - VectorWithOffset fwhms; - VectorWithOffset max_kernel_sizes; + BasicCoordinate< num_dimensions,float> fwhms; + BasicCoordinate< num_dimensions,int> max_kernel_sizes; + bool normalise; SeparableGaussianArrayFilter gaussian_filter; diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 0ceba98e6b..1e3983c6c9 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -90,6 +90,8 @@ */ #include "stir/common.h" +#include "stir/DiscretisedDensity.h" +#include "stir/DataProcessor.h" START_NAMESPACE_STIR @@ -99,7 +101,6 @@ template class VoxelsOnCartesianGrid; template class PixelsOnCartesianGrid; template class CartesianCoordinate3D; template class BasicCoordinate; - /*! \ingroup buildblock \name Functions for interpolating data to new pixel/bin sizes @@ -190,9 +191,14 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices) remain the same. */ + void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale = false, bool filter = false); + const VoxelsOnCartesianGrid &image_in, bool rescale , bool apply_filter, shared_ptr > > filter_ptr); + +void +zoom_image(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in); //------------------ 2D zooms--------------------- diff --git a/src/local/buildblock/local_buildblock_registries.cxx b/src/local/buildblock/local_buildblock_registries.cxx index a1554273cc..86aa00dfde 100644 --- a/src/local/buildblock/local_buildblock_registries.cxx +++ b/src/local/buildblock/local_buildblock_registries.cxx @@ -3,7 +3,7 @@ See STIR/LICENSE.txt for detail $, IRSL See STIR/LICENSE.txt for details */ -#include "local/stir/SeparableGaussianImageFilter.h" +//#include "/local/stir/SeparableGaussianImageFilter.h" #ifdef SANIDA #include "local/stir/DAVImageFilter3D.h" #include "local/stir/ModifiedInverseAverigingImageFilter.h" From 9e6dd7c169841e3c47c9652a6e4daa033e0d5566 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 20 Jul 2018 12:12:24 +0100 Subject: [PATCH 028/274] filtergaussian --- .../SeparableGaussianImageFilter.cxx | 100 +++++++++--------- src/buildblock/buildblock_registries.cxx | 3 +- src/buildblock/zoom.cxx | 79 +------------- .../stir/SeparableGaussianArrayFilter.h | 10 +- .../stir/SeparableGaussianImageFilter.h | 7 +- src/swig/stir.i | 18 +++- 6 files changed, 80 insertions(+), 137 deletions(-) diff --git a/src/buildblock/SeparableGaussianImageFilter.cxx b/src/buildblock/SeparableGaussianImageFilter.cxx index cdd7e62da2..11bb1ee079 100644 --- a/src/buildblock/SeparableGaussianImageFilter.cxx +++ b/src/buildblock/SeparableGaussianImageFilter.cxx @@ -1,6 +1,5 @@ #include "stir/SeparableGaussianImageFilter.h" -#include "stir/SeparableGaussianArrayFilter.h" #include "stir/VoxelsOnCartesianGrid.h" START_NAMESPACE_STIR @@ -9,48 +8,13 @@ START_NAMESPACE_STIR #define num_dimensions 3 -template -SeparableGaussianImageFilter:: -SeparableGaussianImageFilter() -//:filter_coefficients(VectorWithOffset(-1,1)) -{ - set_defaults(); -} - - -template -BasicCoordinate< num_dimensions,float> -SeparableGaussianImageFilter:: -get_fwhms() -{ - return fwhms; -} - - -template -BasicCoordinate< num_dimensions,int> -SeparableGaussianImageFilter:: -get_max_kernel_sizes() -{ - return max_kernel_sizes; -} - - -template -bool -SeparableGaussianImageFilter:: -get_normalised_filter() -{ - return normalise; -} - template Succeeded SeparableGaussianImageFilter:: virtual_set_up(const DiscretisedDensity<3,elemT>& density) { - + if(dynamic_cast*>(&density)== 0) { @@ -62,10 +26,10 @@ virtual_set_up(const DiscretisedDensity<3,elemT>& density) const BasicCoordinate< num_dimensions,float> rescale = dynamic_cast*>(&density)->get_grid_spacing(); - gaussian_filter = SeparableGaussianArrayFilter(get_fwhms(),get_max_kernel_sizes(),get_normalised_filter()); + gaussian_filter = SeparableGaussianArrayFilter(fwhms/rescale,max_kernel_sizes,normalise); return Succeeded::yes; - + } @@ -74,7 +38,7 @@ void SeparableGaussianImageFilter:: virtual_apply(DiscretisedDensity<3,elemT>& density) const -{ +{ gaussian_filter(density); @@ -85,45 +49,79 @@ virtual_apply(DiscretisedDensity<3,elemT>& density) const template void SeparableGaussianImageFilter:: -virtual_apply(DiscretisedDensity<3,elemT>& out_density, - const DiscretisedDensity<3,elemT>& in_density) const +virtual_apply(DiscretisedDensity<3,elemT>& out_density, + const DiscretisedDensity<3,elemT>& in_density) const { - + gaussian_filter(out_density,in_density); } +template +SeparableGaussianImageFilter:: +SeparableGaussianImageFilter() +: fwhms(0),max_kernel_sizes(0) +{ + set_defaults(); +} + +template +BasicCoordinate< num_dimensions,float> +SeparableGaussianImageFilter:: +get_fwhms() +{ + return fwhms; +} + +template +bool +SeparableGaussianImageFilter:: +get_normalised_filter() +{ + return normalise; +} + + +template +BasicCoordinate< num_dimensions,int> +SeparableGaussianImageFilter:: +get_max_kernel_sizes() +{ + return max_kernel_sizes; +} + + template void SeparableGaussianImageFilter:: set_defaults() { + base_type::set_defaults(); fwhms.fill(0); max_kernel_sizes.fill(-1); normalise = false; - + } template -void +void SeparableGaussianImageFilter:: initialise_keymap() { - this->parser.add_start_key("Separable Gaussian Filter Parameters"); + base_type::initialise_keymap(); + this->parser.add_start_key("Separable Gaussian Filter Parameters"); this->parser.add_key("x-dir filter FWHM (in mm)", &fwhms[3]); this->parser.add_key("y-dir filter FWHM (in mm)", &fwhms[2]); this->parser.add_key("z-dir filter FWHM (in mm)", &fwhms[1]); - this->parser.add_key("x-dir maximum kernel size", &max_kernel_sizes[3]); this->parser.add_key("y-dir maximum kernel size", &max_kernel_sizes[2]); this->parser.add_key("z-dir maximum kernel size", &max_kernel_sizes[1]); - this->parser.add_key("Normalise filter to 1", &normalise); - - this->parser.add_stop_key("END Separable Gaussian Filter Parameters"); - + this->parser.add_stop_key("END Separable Gaussian Filter Parameters"); } + + template<> const char * const diff --git a/src/buildblock/buildblock_registries.cxx b/src/buildblock/buildblock_registries.cxx index bb93c11fb3..ee015275c9 100644 --- a/src/buildblock/buildblock_registries.cxx +++ b/src/buildblock/buildblock_registries.cxx @@ -28,6 +28,7 @@ */ #include "stir/SeparableCartesianMetzImageFilter.h" +#include "stir/SeparableGaussianImageFilter.h" #include "stir/MedianImageFilter3D.h" #include "stir/MinimalImageFilter3D.h" #include "stir/ChainedDataProcessor.h" @@ -40,10 +41,10 @@ START_NAMESPACE_STIR static MedianImageFilter3D::RegisterIt dummy; static MinimalImageFilter3D::RegisterIt dummy1; static SeparableCartesianMetzImageFilter::RegisterIt dummy2; +static SeparableGaussianImageFilter::RegisterIt dummy9; static SeparableConvolutionImageFilter::RegisterIt dummy5; static NonseparableConvolutionUsingRealDFTImageFilter::RegisterIt dummy7; static TruncateToCylindricalFOVImageProcessor ::RegisterIt dummy6; static ChainedDataProcessor >::RegisterIt dummy3; static ThresholdMinToSmallPositiveValueDataProcessor >::RegisterIt dummy4; - END_NAMESPACE_STIR diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 546ae087f9..8130bdb576 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -372,82 +372,9 @@ zoom_image(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, bool rescale, bool apply_filter, shared_ptr > > filter_ptr) { -/* - interpolation routine uses the following relation: - x_in_index = x_out_index/zoom + offset - - compare to 'physical' coordinates - x_phys = (x_index) * voxel_size.x + origin.x - - as x_in_phys == x_out_phys, we find - (x_in_index)* voxel_size_in.x + origin_in.x == - (x_out_index )* voxel_size_out.x + origin_out.x - <=> - x_in_index = (x_out_index * voxel_size_out.x - + origin_out.x - origin_in.x) - / voxel_size_in.x - - so, zoom= voxel_size_in.x/ voxel_size_out.x - offset = (origin_out.x - origin_in.x)/ voxel_size_in.x - - */ - // check relation between indices and physical coordinates - { - const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); - if (norm(image_in.get_physical_coordinates_for_indices(indices) - - (image_in.get_voxel_size() * BasicCoordinate<3,float>(indices) + image_in.get_origin()) - ) > 2.F) - error("zoom_image is confused about the relation between indices and physical coordinates"); - } - const float zoom_x = - image_in.get_voxel_size().x() / image_out.get_voxel_size().x(); - const float zoom_y = - image_in.get_voxel_size().y() / image_out.get_voxel_size().y(); - const float zoom_z = - image_in.get_voxel_size().z() / image_out.get_voxel_size().z(); - const float x_offset = - (image_out.get_origin().x() - image_in.get_origin().x()) - / image_in.get_voxel_size().x(); - const float y_offset = - (image_out.get_origin().y() - image_in.get_origin().y()) - / image_in.get_voxel_size().y(); - const float z_offset = - (image_out.get_origin().z() - image_in.get_origin().z()) - / image_in.get_voxel_size().z(); - - - if(zoom_x==1.0F && zoom_y==1.0F && zoom_z==1.0F && - x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && - image_in.get_index_range() == image_out.get_index_range() - ) - { - image_out = image_in; - return; - } - - // TODO creating a lot of new images here... - Array<3,float> - temp(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), - image_in.get_min_y(), image_in.get_max_y(), - image_out.get_min_x(), image_out.get_max_x())); - - for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) - for (int y=image_in.get_min_y(); y<=image_in.get_max_y(); y++) - overlap_interpolate(temp[z][y], image_in[z][y], zoom_x, x_offset); - - Array<3,float> temp2(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), - image_out.get_min_y(), image_out.get_max_y(), - image_out.get_min_x(), image_out.get_max_x())); - - for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) - overlap_interpolate(temp2[z], temp[z], zoom_y, y_offset); - - temp.recycle(); - - overlap_interpolate(image_out, temp2, zoom_z, z_offset); - + zoom_image(image_out, image_in); - //rescaling the image +//The image is rescaled to preserve the voxel values if (rescale) @@ -460,7 +387,7 @@ zoom_image(VoxelsOnCartesianGrid &image_out, } - //apply filter +//Filter output image if (apply_filter) { diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index f17857d57a..66d56e54ed 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -4,13 +4,12 @@ /*! \file - \ingroup local/buildblock - \brief - - + \ingroup ImageProcessor + \brief Declaration of class stir::SeparableGaussianArrayFilter + \author Sanida Mustafovic \author Kris Thielemans - + $Date: $Revision: */ @@ -41,6 +40,7 @@ class SeparableGaussianArrayFilter: //! Default constructor SeparableGaussianArrayFilter(); + SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& fwhm, const BasicCoordinate< num_dimensions,int>& max_kernel_sizes, bool normalise = false); diff --git a/src/include/stir/SeparableGaussianImageFilter.h b/src/include/stir/SeparableGaussianImageFilter.h index 245abe77b7..31dc1de7e1 100644 --- a/src/include/stir/SeparableGaussianImageFilter.h +++ b/src/include/stir/SeparableGaussianImageFilter.h @@ -54,11 +54,11 @@ class SeparableGaussianImageFilter : //! Default constructor SeparableGaussianImageFilter(); + BasicCoordinate< num_dimensions,float> get_fwhms(); BasicCoordinate< num_dimensions,int> get_max_kernel_sizes(); bool get_normalised_filter(); -private: BasicCoordinate< num_dimensions,float> fwhms; BasicCoordinate< num_dimensions,int> max_kernel_sizes; bool normalise; @@ -67,13 +67,14 @@ class SeparableGaussianImageFilter : virtual void set_defaults(); virtual void initialise_keymap(); - virtual bool post_processing(); + + //virtual bool post_processing(); Succeeded virtual_set_up(const DiscretisedDensity& image); // new void virtual_apply(DiscretisedDensity& out_density, const DiscretisedDensity& in_density) const; void virtual_apply(DiscretisedDensity& density) const ; - + private: }; #undef num_dimensions diff --git a/src/swig/stir.i b/src/swig/stir.i index 01eeaa9208..c95a79e26c 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -79,7 +79,8 @@ #include "stir/ChainedDataProcessor.h" #include "stir/SeparableCartesianMetzImageFilter.h" - +#include "stir/SeparableGaussianImageFilter.h" + #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" #include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" #include "stir/OSSPS/OSSPSReconstruction.h" @@ -1440,12 +1441,18 @@ namespace stir { stir::DataProcessor >, stir::DataProcessor > >) %shared_ptr(stir::SeparableCartesianMetzImageFilter) + +%shared_ptr(stir::RegisteredParsingObject, + stir::DataProcessor >, + stir::DataProcessor > >) +%shared_ptr(stir::SeparableGaussianImageFilter) #undef elemT #endif %include "stir/DataProcessor.h" %include "stir/ChainedDataProcessor.h" %include "stir/SeparableCartesianMetzImageFilter.h" +%include "stir/SeparableGaussianImageFilter.h" #define elemT float %template(DataProcessor3DFloat) stir::DataProcessor >; @@ -1460,6 +1467,15 @@ namespace stir { stir::DataProcessor > >; %template(SeparableCartesianMetzImageFilter3DFloat) stir::SeparableCartesianMetzImageFilter; + +%template(RPSeparableGaussianImageFilter3DFloat) stir::RegisteredParsingObject< + stir::SeparableGaussianImageFilter, + stir::DataProcessor >, + stir::DataProcessor > >; + +%template(SeparableGaussianImageFilter3DFloat) stir::SeparableGaussianImageFilter; + + #undef elemT %include "stir/GeneralisedPoissonNoiseGenerator.h" From 2447ab9ceb8c1252b4d16d7a57c0e3215022c657 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 20 Jul 2018 14:34:12 +0100 Subject: [PATCH 029/274] filter_ok --- .../SeparableGaussianArrayFilter.cxx | 30 +++++++++++-------- .../stir/SeparableGaussianArrayFilter.h | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/buildblock/SeparableGaussianArrayFilter.cxx b/src/buildblock/SeparableGaussianArrayFilter.cxx index 8e75616092..e14d916376 100644 --- a/src/buildblock/SeparableGaussianArrayFilter.cxx +++ b/src/buildblock/SeparableGaussianArrayFilter.cxx @@ -2,6 +2,7 @@ #include "stir/SeparableGaussianArrayFilter.h" #include "stir/ArrayFilter1DUsingConvolution.h" #include "stir/ArrayFilter1DUsingConvolutionSymmetricKernel.h" +#include "stir/VectorWithOffset.h" #include "stir/info.h" #include @@ -24,9 +25,10 @@ START_NAMESPACE_STIR template SeparableGaussianArrayFilter:: SeparableGaussianArrayFilter() -:fwhm(0),max_kernel_sizes(0) +:fwhms(0),max_kernel_sizes(0) { + for (int i=1;i<=num_dimensions;i++) { this->all_1d_array_filters[i-1]. @@ -36,8 +38,8 @@ SeparableGaussianArrayFilter() template SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter(const float fwhm_v,const float max_kernel_sizes_v, bool normalise) -:fwhm(fwhm_v),max_kernel_sizes(max_kernel_sizes_v) +SeparableGaussianArrayFilter(const float fwhms_v,const float max_kernel_sizes_v, bool normalise) +:fwhms(fwhms_v),max_kernel_sizes(max_kernel_sizes_v) { //normalisation to 1 is optinal @@ -48,10 +50,10 @@ SeparableGaussianArrayFilter(const float fwhm_v,const float max_kernel_sizes_v, template SeparableGaussianArrayFilter:: -SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& fwhm_v, +SeparableGaussianArrayFilter(const BasicCoordinate< num_dimensions,float>& fwhms_v, const BasicCoordinate< num_dimensions,int>& max_kernel_sizes_v, bool normalise) -:fwhm(fwhm_v),max_kernel_sizes(max_kernel_sizes_v) +:fwhms(fwhms_v),max_kernel_sizes(max_kernel_sizes_v) { //normalisation to 1 is optinal @@ -65,14 +67,14 @@ SeparableGaussianArrayFilter:: construct_filter(bool normalise) { VectorWithOffset filter_coefficients; - for (int i = 1; i<=max_kernel_sizes.size();i++) + for (int i = 1; i<=num_dimensions;i++) { calculate_coefficients(filter_coefficients, max_kernel_sizes[i], - fwhm[i],normalise); + fwhms[i],normalise); - this->all_1d_array_filters[i]. + this->all_1d_array_filters[i-1]. reset(new ArrayFilter1DUsingConvolution(filter_coefficients)); } @@ -82,11 +84,11 @@ template void SeparableGaussianArrayFilter:: calculate_coefficients(VectorWithOffset& filter_coefficients, const int max_kernel_sizes, - const float fwhm, bool normalise) + const float fwhms, bool normalise) { - float standard_deviation = sqrt(fwhm*fwhm/(8*log(2.F))); + float standard_deviation = sqrt(fwhms*fwhms/(8*log(2.F))); if (standard_deviation==0) { @@ -132,11 +134,13 @@ if (normalise) } cerr << " here - rescaled" << endl; - cerr << "Printing filter coefficients" << endl; - for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) - cerr << i<<" "<< filter_coefficients[i] <<" " << endl; + + /* cerr << "Printing filter coefficients" << endl; + for (int i =filter_coefficients.get_min_index();i<=filter_coefficients.get_max_index();i++) + cerr << i<<" "<< filter_coefficients[i] <<" " << endl;*/ } + } diff --git a/src/include/stir/SeparableGaussianArrayFilter.h b/src/include/stir/SeparableGaussianArrayFilter.h index 66d56e54ed..2576f296d8 100644 --- a/src/include/stir/SeparableGaussianArrayFilter.h +++ b/src/include/stir/SeparableGaussianArrayFilter.h @@ -57,7 +57,7 @@ class SeparableGaussianArrayFilter: const float fwhm, bool normalise); - BasicCoordinate< num_dimensions,float> fwhm; + BasicCoordinate< num_dimensions,float> fwhms; BasicCoordinate< num_dimensions,int> max_kernel_sizes; }; From 61f74c7dcabeb2aeee2eb14072b6324333da7853 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Jul 2018 13:26:07 +0100 Subject: [PATCH 030/274] swig_bug --- src/buildblock/zoom.cxx | 31 +++++++++++++++++-- src/include/stir/scatter/ScatterSimulation.h | 2 ++ .../SingleScatterLikelihoodAndGradient.h | 2 +- .../stir/scatter/SingleScatterSimulation.h | 1 + src/include/stir/zoom.h | 11 +++++-- src/scatter_buildblock/ScatterSimulation.cxx | 10 ++++++ .../SingleScatterLikelihoodAndGradient.cxx | 1 - src/swig/stir.i | 17 +++++++++- 8 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 8130bdb576..bc1b64c8bf 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -39,6 +39,7 @@ #include "stir/interpolate.h" #include "stir/zoom.h" +#include "stir/PostFiltering.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -367,7 +368,7 @@ zoom_image(const VoxelsOnCartesianGrid &image, } -void +/*void zoom_image(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, bool rescale, bool apply_filter, shared_ptr > > filter_ptr) { @@ -393,11 +394,27 @@ zoom_image(VoxelsOnCartesianGrid &image_out, { filter_ptr->apply(image_out); } + +}*/ + + + +void +zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, DataProcessor > &filter, bool rescale) +{ + + zoom_image(image_out, image_in,rescale); + + //apply filter + filter.apply(image_out); + } + void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in) + const VoxelsOnCartesianGrid &image_in, bool rescale) { /* @@ -475,6 +492,16 @@ zoom_image(VoxelsOnCartesianGrid &image_out, overlap_interpolate(image_out, temp2, zoom_z, z_offset); + if (rescale) + + { + BasicCoordinate<3,float> orig_grid = image_in.get_grid_spacing(); + BasicCoordinate<3,float> new_grid = image_out.get_grid_spacing(); + float scale_image = (orig_grid[3]/new_grid[3]) * (orig_grid[2]/new_grid[2]) * (orig_grid[1]/new_grid[1]); + + image_out*= scale_image; + } + } diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 739635dca5..9f006dfc82 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -28,6 +28,7 @@ */ #include "stir/ParsingObject.h" +#include "stir/DataProcessor.h" #include "stir/RegisteredObject.h" #include "stir/ProjData.h" #include "stir/VoxelsOnCartesianGrid.h" @@ -203,6 +204,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} + protected: //! computes scatter for one viewgram diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index fefedf1b0f..445d861c41 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -29,7 +29,7 @@ #include "stir/scatter/ScatterSimulation.h" #include "stir/scatter/SingleScatterSimulation.h" #include "stir/RegisteredParsingObject.h" - +#include "stir/zoom.h" START_NAMESPACE_STIR diff --git a/src/include/stir/scatter/SingleScatterSimulation.h b/src/include/stir/scatter/SingleScatterSimulation.h index b29b93e101..1c512642ff 100644 --- a/src/include/stir/scatter/SingleScatterSimulation.h +++ b/src/include/stir/scatter/SingleScatterSimulation.h @@ -77,6 +77,7 @@ class SingleScatterSimulation : public //! used to check acceptable parameter ranges, etc... virtual bool post_processing(); + protected: //! diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 1e3983c6c9..7406800fa1 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -92,6 +92,7 @@ #include "stir/common.h" #include "stir/DiscretisedDensity.h" #include "stir/DataProcessor.h" +#include "stir/SeparableGaussianImageFilter.h" START_NAMESPACE_STIR @@ -192,13 +193,17 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, remain the same. */ -void +/*void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale , bool apply_filter, shared_ptr > > filter_ptr); + const VoxelsOnCartesianGrid &image_in, bool rescale , bool apply_filter, shared_ptr > > filter_ptr);*/ void +zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, DataProcessor > &filter, bool rescale = false); +void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in); + const VoxelsOnCartesianGrid &image_in, bool rescale = false); + //------------------ 2D zooms--------------------- diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 7bfd0479cf..a1ed4f2fdd 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -621,6 +621,16 @@ set_cache_enabled(const bool arg) } +/*void +ScatterSimulation:: +upsample_and_apply_filter(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, bool rescale, bool apply_filter, shared_ptr > > filter_ptr) +{ + // shared_ptr > > filter_ptr; + + + zoom_image(image_out, image_in, rescale, apply_filter, filter_ptr); +}*/ END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 2bc22c9b1a..903af6f60f 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -32,7 +32,6 @@ #include "stir/SSRB.h" #include "stir/stir_math.h" -#include "stir/zoom.h" #include "stir/NumericInfo.h" START_NAMESPACE_STIR diff --git a/src/swig/stir.i b/src/swig/stir.i index c95a79e26c..5316571f51 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -80,7 +80,7 @@ #include "stir/ChainedDataProcessor.h" #include "stir/SeparableCartesianMetzImageFilter.h" #include "stir/SeparableGaussianImageFilter.h" - +#include "stir/PostFiltering.h" #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" #include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" #include "stir/OSSPS/OSSPSReconstruction.h" @@ -1280,6 +1280,7 @@ namespace stir { %include "stir/IO/write_to_file.h" %template(write_image_to_file) stir::write_to_file >; +%include "stir/zoom.h" #ifdef STIRSWIG_SHARED_PTR #define DataT stir::DiscretisedDensity<3,float> %shared_ptr(stir::OutputFileFormat >); @@ -1293,6 +1294,8 @@ namespace stir { #endif #endif +%template(write_image_to_file) stir::write_to_file >; + %include "stir/IO/OutputFileFormat.h" #define DataT stir::DiscretisedDensity<3,float> @@ -1310,6 +1313,7 @@ namespace stir { /* Now do ProjDataInfo, Sinogram et al */ %include "stir/TimeFrameDefinitions.h" +%include "stir/zoom.h" %include "stir/ExamInfo.h" %include "stir/IO/ExamData.h" %include "stir/Verbosity.h" @@ -1476,6 +1480,13 @@ namespace stir { %template(SeparableGaussianImageFilter3DFloat) stir::SeparableGaussianImageFilter; +%extend stir::DataProcessor { + stir::DataProcessor >* ptr() const { + return this; + } +} + + #undef elemT %include "stir/GeneralisedPoissonNoiseGenerator.h" @@ -1666,3 +1677,7 @@ stir::ScatterSimulation %include "stir/scatter/SingleScatterLikelihoodAndGradient.h" + + + + From cc763f42d04a9d1c0c5569eed2c06127b1fd6cab Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Jul 2018 14:46:08 +0100 Subject: [PATCH 031/274] add --- src/swig/stir.i | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/swig/stir.i b/src/swig/stir.i index 5316571f51..e5a2d522ab 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -1450,15 +1450,29 @@ namespace stir { stir::DataProcessor >, stir::DataProcessor > >) %shared_ptr(stir::SeparableGaussianImageFilter) + + +%shared_ptr(stir::PostFiltering >); + #undef elemT #endif +/*#define elemT float +extend stir::DataProcessor { + stir::DataProcessor >* ptr() const { + return this; }} +#undef elemT*/ + %include "stir/DataProcessor.h" %include "stir/ChainedDataProcessor.h" %include "stir/SeparableCartesianMetzImageFilter.h" %include "stir/SeparableGaussianImageFilter.h" +%include "stir/PostFiltering.h" + #define elemT float + + %template(DataProcessor3DFloat) stir::DataProcessor >; %template(RPChainedDataProcessor3DFloat) stir::RegisteredParsingObject< stir::ChainedDataProcessor >, @@ -1479,13 +1493,10 @@ namespace stir { %template(SeparableGaussianImageFilter3DFloat) stir::SeparableGaussianImageFilter; - -%extend stir::DataProcessor { +%template(PostFiltering3DFloat) stir::PostFiltering >; +/*%extend stir::DataProcessor { stir::DataProcessor >* ptr() const { - return this; - } -} - + return this; }}*/ #undef elemT From 824bce2c977eb82471e07987fe78b973445f9fe8 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Jul 2018 15:35:40 +0100 Subject: [PATCH 032/274] bug_filter --- src/buildblock/zoom.cxx | 21 +++++++++++++++++++-- src/include/stir/zoom.h | 7 ++++++- src/swig/stir.i | 2 ++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index bc1b64c8bf..49ff55ee80 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -398,8 +398,25 @@ zoom_image(VoxelsOnCartesianGrid &image_out, }*/ - void +zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const std::string& filter_parameter_filename, bool rescale) +{ + + + zoom_image(image_out, image_in,rescale); + + //apply filter + shared_ptr > > filter_sptr; + filter_sptr.reset(new PostFiltering >); + filter_sptr->parse(filter_parameter_filename.c_str()); + filter_sptr->process_data(image_out); + +} + + + +/*void zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, DataProcessor > &filter, bool rescale) { @@ -409,7 +426,7 @@ zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, //apply filter filter.apply(image_out); -} +}*/ void diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 7406800fa1..1e7364e606 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -91,6 +91,7 @@ #include "stir/common.h" #include "stir/DiscretisedDensity.h" +#include "stir/PostFiltering.h" #include "stir/DataProcessor.h" #include "stir/SeparableGaussianImageFilter.h" @@ -197,9 +198,13 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, zoom_image(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, bool rescale , bool apply_filter, shared_ptr > > filter_ptr);*/ +/*void +zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, DataProcessor > &filter, bool rescale = false);*/ + void zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, DataProcessor > &filter, bool rescale = false); + const VoxelsOnCartesianGrid &image_in, const std::string& filter_parameter_filename, bool rescale = false); void zoom_image(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, bool rescale = false); diff --git a/src/swig/stir.i b/src/swig/stir.i index e5a2d522ab..a4eb3e04ab 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -1493,7 +1493,9 @@ extend stir::DataProcessor { %template(SeparableGaussianImageFilter3DFloat) stir::SeparableGaussianImageFilter; + %template(PostFiltering3DFloat) stir::PostFiltering >; + /*%extend stir::DataProcessor { stir::DataProcessor >* ptr() const { return this; }}*/ From 08466ccf27a7b8e976b603191cb71db6fb5d48f6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Jul 2018 10:23:49 +0100 Subject: [PATCH 033/274] zoomoption --- src/buildblock/zoom.cxx | 100 ++++++++++++++------------------- src/include/stir/ZoomOptions.h | 27 +++++++++ src/include/stir/zoom.h | 16 ++---- src/swig/stir.i | 2 + 4 files changed, 78 insertions(+), 67 deletions(-) create mode 100644 src/include/stir/ZoomOptions.h diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 49ff55ee80..647a3c04c0 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -50,6 +50,7 @@ #include "stir/IndexRange3D.h" #include "stir/IndexRange2D.h" #include "stir/SeparableGaussianImageFilter.h" +#include "stir/ZoomOptions.h" #include START_NAMESPACE_STIR @@ -368,72 +369,28 @@ zoom_image(const VoxelsOnCartesianGrid &image, } -/*void -zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale, bool apply_filter, shared_ptr > > filter_ptr) -{ - - zoom_image(image_out, image_in); - -//The image is rescaled to preserve the voxel values - - if (rescale) - - { - BasicCoordinate<3,float> orig_grid = image_in.get_grid_spacing(); - BasicCoordinate<3,float> new_grid = image_out.get_grid_spacing(); - float scale_image = (orig_grid[3]/new_grid[3]) * (orig_grid[2]/new_grid[2]) * (orig_grid[1]/new_grid[1]); - - image_out*= scale_image; - } - - -//Filter output image - - if (apply_filter) - { - filter_ptr->apply(image_out); - } - -}*/ - void -zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& filter_parameter_filename, bool rescale) +zoom_image(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO zo) { - - - zoom_image(image_out, image_in,rescale); + zoom_image(image_out, image_in, zo); //apply filter - shared_ptr > > filter_sptr; - filter_sptr.reset(new PostFiltering >); - filter_sptr->parse(filter_parameter_filename.c_str()); - filter_sptr->process_data(image_out); + PostFiltering > filter; + filter.parse(postfilter_parameter_filename.c_str()); + filter.process_data(image_out); } -/*void -zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, DataProcessor > &filter, bool rescale) -{ - - zoom_image(image_out, image_in,rescale); - - //apply filter - filter.apply(image_out); - -}*/ - - void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale) + const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO zo) { + /* interpolation routine uses the following relation: x_in_index = x_out_index/zoom + offset @@ -509,16 +466,45 @@ zoom_image(VoxelsOnCartesianGrid &image_out, overlap_interpolate(image_out, temp2, zoom_z, z_offset); - if (rescale) + /* The code provides for three possible rescaling options: + * preserving the image values, + * preserving the image projectors, + * preserving the image sum + + DEFAULT: Preserve image sum*/ + + float scale_image = 1.F; + + switch (zo) + { + case ZoomOptions::preserve_values: + { + std::cerr << "Zoom - Rescaling Factor: preserve values\n"; + + scale_image = zoom_x*zoom_y*zoom_z; + break; + } + + case ZoomOptions::preserve_projections: { - BasicCoordinate<3,float> orig_grid = image_in.get_grid_spacing(); - BasicCoordinate<3,float> new_grid = image_out.get_grid_spacing(); - float scale_image = (orig_grid[3]/new_grid[3]) * (orig_grid[2]/new_grid[2]) * (orig_grid[1]/new_grid[1]); + std::cerr << "Zoom - Rescaling Factor: preserve projectors\n"; + + scale_image = zoom_y*zoom_z; + break; + } - image_out*= scale_image; + case ZoomOptions::preserve_sum: + { + std::cerr << "Zoom - Rescaling Factor: preserve sum\n"; + return; // no need to scale } + } + + + image_out*= scale_image; + } diff --git a/src/include/stir/ZoomOptions.h b/src/include/stir/ZoomOptions.h new file mode 100644 index 0000000000..242912f5ce --- /dev/null +++ b/src/include/stir/ZoomOptions.h @@ -0,0 +1,27 @@ +#ifndef ZOOMOPTIONS_H +#define ZOOMOPTIONS_H + +#include "stir/common.h" + +START_NAMESPACE_STIR + +/*! + \brief + a class containing an enumeration type that can be used by functions to signal + successful operation or not + + Example: + \code + Succeeded f() { do_something; return Succeeded::yes; } + void g() { if (f() == Succeeded::no) error("Error calling f"); } + \endcode +*/ +class ZoomOptions{ + public: + enum ZO {preserve_sum, preserve_values, preserve_projections}; +}; + +END_NAMESPACE_STIR + + +#endif // ZOOMOPTIONS_H diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 1e7364e606..3cdeda3500 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -94,6 +94,7 @@ #include "stir/PostFiltering.h" #include "stir/DataProcessor.h" #include "stir/SeparableGaussianImageFilter.h" +#include "stir/ZoomOptions.h" START_NAMESPACE_STIR @@ -194,20 +195,15 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, remain the same. */ -/*void -zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale , bool apply_filter, shared_ptr > > filter_ptr);*/ - -/*void -zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, DataProcessor > &filter, bool rescale = false);*/ void -zoom_image_and_filter(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& filter_parameter_filename, bool rescale = false); +zoom_image(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO zo = ZoomOptions::preserve_sum); + + void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, bool rescale = false); + const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO zo = ZoomOptions::preserve_sum); //------------------ 2D zooms--------------------- diff --git a/src/swig/stir.i b/src/swig/stir.i index a4eb3e04ab..be8133d240 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -1281,6 +1281,7 @@ namespace stir { %template(write_image_to_file) stir::write_to_file >; %include "stir/zoom.h" +%include "stir/ZoomOptions.h" #ifdef STIRSWIG_SHARED_PTR #define DataT stir::DiscretisedDensity<3,float> %shared_ptr(stir::OutputFileFormat >); @@ -1314,6 +1315,7 @@ namespace stir { */ %include "stir/TimeFrameDefinitions.h" %include "stir/zoom.h" +%include "stir/ZoomOptions.h" %include "stir/ExamInfo.h" %include "stir/IO/ExamData.h" %include "stir/Verbosity.h" From d24283f65d9609f163df4f6f47abbe54bb6f7db4 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Jul 2018 15:40:03 +0100 Subject: [PATCH 034/274] zoomoptions --- src/buildblock/zoom.cxx | 21 +++++++++++++++++++-- src/include/stir/ZoomOptions.h | 3 +++ src/include/stir/zoom.h | 13 +++++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 647a3c04c0..2736300fe1 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -370,9 +370,26 @@ zoom_image(const VoxelsOnCartesianGrid &image, +void +zoom_image_matlab(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const int &zoom_option) +{ + ZoomOptions::ZO zo = ZoomOptions::ZO(zoom_option); + zoom_image(image_out, image_in, postfilter_parameter_filename, zo); +} + +void +zoom_image_matlab(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const int &zoom_option) +{ + ZoomOptions::ZO zo = ZoomOptions::ZO(zoom_option); + zoom_image(image_out, image_in, zo); +} + + void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO zo) + const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO &zo) { zoom_image(image_out, image_in, zo); @@ -387,7 +404,7 @@ zoom_image(VoxelsOnCartesianGrid &image_out, void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO zo) + const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO &zo) { diff --git a/src/include/stir/ZoomOptions.h b/src/include/stir/ZoomOptions.h index 242912f5ce..323b3b5825 100644 --- a/src/include/stir/ZoomOptions.h +++ b/src/include/stir/ZoomOptions.h @@ -19,6 +19,9 @@ START_NAMESPACE_STIR class ZoomOptions{ public: enum ZO {preserve_sum, preserve_values, preserve_projections}; + ZoomOptions(const ZO& v) : v(v) {} + private: + ZO v; }; END_NAMESPACE_STIR diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 3cdeda3500..99bd6bb442 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -198,14 +198,23 @@ zoom_image_in_place(VoxelsOnCartesianGrid &image, void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO zo = ZoomOptions::preserve_sum); + const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO &zo = ZoomOptions::preserve_sum); void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO zo = ZoomOptions::preserve_sum); + const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO &zo = ZoomOptions::preserve_sum); + +void +zoom_image_matlab(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const int &zoom_option = 0); + + +void +zoom_image_matlab(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const int &zoom_option = 0); //------------------ 2D zooms--------------------- /*! From 54ee7def48eae706dd746fe41ffedd935c7aa0f1 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 1 Oct 2018 08:55:21 +0100 Subject: [PATCH 035/274] edit_single_scatter_gradient --- .../SingleScatterLikelihoodAndGradient.h | 6 + .../SingleScatterLikelihoodAndGradient.cxx | 201 +++++++++++++++++- 2 files changed, 204 insertions(+), 3 deletions(-) diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 445d861c41..3e7c1d3e5d 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -65,6 +65,8 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale , bool isgradient = true); + double L_G_function_from_est_data(ProjData& data,ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale); + protected: @@ -93,6 +95,10 @@ class SingleScatterLikelihoodAndGradient : public double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool isgradient); + double L_G_for_view_segment_number_from_est_data(ProjData&data,ProjData&est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale); + + double L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale); + }; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 903af6f60f..5cc945c718 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -69,6 +69,10 @@ SingleScatterLikelihoodAndGradient:: L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale, bool isgradient) { +if (isgradient) + std::cerr <<"IS GRADIENT"<< "\n"; + +else std::cerr <<"IS JACOBIAN"<< "\n"; this->output_proj_data_sptr->fill(0.f); @@ -242,14 +246,207 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes if (isgradient) + { + gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)-1); + } + else + { + + gradient_image += tmp_gradient_image; + } + } + + return sum; +} + + +double +SingleScatterLikelihoodAndGradient:: +L_G_function_from_est_data(ProjData& data,ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale) +{ + + + this->output_proj_data_sptr->fill(0.f); + + + std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + + if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) + { + std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + + } + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + std::cerr << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + double sum = 0; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + sum+=this->L_G_for_view_segment_number_from_est_data(data, est_data,gradient_image,vs_num,rescale); + + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + std::cout<< bin_counter << " / "<< total_bins <output_proj_data_sptr->fill(0.f); @@ -156,7 +156,7 @@ else std::cerr <<"IS JACOBIAN"<< "\n"; //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,isgradient); + sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * @@ -168,33 +168,30 @@ else std::cerr <<"IS JACOBIAN"<< "\n"; } } - int max_x = gradient_image.get_max_x(); - int min_x = gradient_image.get_min_x(); + std::cerr << "LIKELIHOOD:= " << sum << '\n'; - std::cerr << "MIN_GRADIENT_X:= " << min_x << '\n'; - std::cerr << "MAX_GRADIENT_X:= " << max_x << '\n'; return sum; } double SingleScatterLikelihoodAndGradient:: -L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool isgradient) +L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale,bool compute_gradient,bool isgradient_mu) { Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); - double sum = L_G_for_viewgram(viewgram,v_est,gradient_image, rescale, isgradient); + double sum = L_G_for_viewgram(viewgram,v_est,gradient_image, rescale, compute_gradient,isgradient_mu); return sum; } double SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool isgradient) +L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,bool compute_gradient, bool isgradient_mu) { const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); @@ -237,7 +234,7 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes const Bin bin = all_bins[i]; //forward model - const double y = L_G_estimate(tmp_gradient_image,bin,isgradient); + const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); @@ -245,16 +242,10 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-0.000000000000000000001; - if (isgradient) - { - gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)-1); - } - else - { - gradient_image += tmp_gradient_image; - } + gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)-1); + } return sum; @@ -430,7 +421,7 @@ L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est, const Bin bin = all_bins[i]; //forward model - const double y = L_G_estimate(tmp_gradient_image,bin,true); + const double y = L_G_estimate(tmp_gradient_image,bin,true,true); @@ -449,7 +440,7 @@ L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est, double SingleScatterLikelihoodAndGradient:: -L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool isgradient) +L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool compute_gradient,bool isgradient_mu) { double scatter_ratio_singles = 0; unsigned det_num_B=0; @@ -468,7 +459,7 @@ L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, boo scatter_ratio_singles += L_G_for_one_scatter_point(gradient_image_bin, scatter_point_num, - det_num_A, det_num_B, isgradient); + det_num_A, det_num_B,compute_gradient, isgradient_mu); } @@ -482,7 +473,7 @@ SingleScatterLikelihoodAndGradient:: L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, const std::size_t scatter_point_num, const unsigned det_num_A, - const unsigned det_num_B, bool isgradient) + const unsigned det_num_B, bool compute_gradient,bool isgradient_mu) { // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. @@ -552,10 +543,9 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); - if (detection_efficiency_scattered[i]==0) - return 0; - if (detection_efficiency_unscattered[i]==0) - return 0; + //if (detection_efficiency_scattered[i]==0&&detection_efficiency_unscattered[i]==0) + //return 0; + } //compute the probability of detection for two given energy windows X and Y @@ -694,10 +684,10 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, *dif_Compton_cross_section_value *common_factor; - /*Single Scatter Forward model Jacobian: - * The derivative is given by three term, respectively in [A,S], [B,S] and [S] */ + /*Single Scatter Forward model Jacobian w.r.t. attenuation: + * The derivative is given by three terms, respectively in [A,S], [B,S] and [S] */ - float contribution_AS = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + float contribution_AS_mu = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* total_Compton_cross_section_relative_to_511keV(new_energy)) *atten_to_detB @@ -708,7 +698,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, *dif_Compton_cross_section_value *common_factor; - float contribution_BS = (detection_probability_XY*emiss_to_detA* + float contribution_BS_mu = (detection_probability_XY*emiss_to_detA* (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* (total_Compton_cross_section_relative_to_511keV(new_energy)) +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* @@ -730,17 +720,63 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, *dif_Compton_cross_section_value *common_factor; + + /*Single Scatter Forward model Jacobian w.r.t. activity: + * + * The derivative is given by two terms, respectively in [A,S] and [B,S] */ + + + float contribution_AS_act = (detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + float contribution_BS_act = (detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + //Fill gradient image along [A,S], [B,S] and in [S] - line_contribution(gradient,rescale,scatter_point, - detector_coord_B,contribution_BS); +if(compute_gradient) +{ + if (isgradient_mu) + + { + line_contribution(gradient,rescale,scatter_point, + detector_coord_B,contribution_BS_mu); + + line_contribution(gradient,rescale,scatter_point, + detector_coord_A,contribution_AS_mu); + + s_contribution(gradient,scatter_point, + contribution_S); + + } - line_contribution(gradient,rescale,scatter_point, - detector_coord_A,contribution_AS); + else + + { + + line_contribution_act(gradient,scatter_point, + detector_coord_B,contribution_BS_act); + + line_contribution_act(gradient,scatter_point, + detector_coord_A,contribution_AS_act); + } + +} - s_contribution(gradient,scatter_point, - contribution_S); return scatter_ratio; diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index ffd6adbb5d..412f13948d 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -103,7 +103,7 @@ SingleScatterSimulation:: // note: costheta is identical for scatter to A or scatter to B // Hence, the Compton_cross_section and energy are identical for both cases as well. if(max_single_scatter_cos_angle>costheta) - return 0; + return 0; const float new_energy = photon_energy_after_Compton_scatter_511keV(costheta); @@ -125,16 +125,13 @@ std::vectordetection_efficiency_unscattered; } - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); - detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); - - if (detection_efficiency_scattered[i]==0) - return 0; - if (detection_efficiency_unscattered[i]==0) - return 0; - } + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); + detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); + // if (detection_efficiency_scattered[i]==0&&detection_efficiency_unscattered[i]==0) + //return 0; + } diff --git a/src/scatter_buildblock/single_scatter_integrals.cxx b/src/scatter_buildblock/single_scatter_integrals.cxx index d271634b2a..381f297d0f 100644 --- a/src/scatter_buildblock/single_scatter_integrals.cxx +++ b/src/scatter_buildblock/single_scatter_integrals.cxx @@ -145,12 +145,13 @@ integral_between_2_points(const DiscretisedDensity<3,float>& density, } + void SingleScatterLikelihoodAndGradient:: line_contribution(VoxelsOnCartesianGrid& gradient_image,const float rescale, const CartesianCoordinate3D& scatter_point, const CartesianCoordinate3D& detector_coord, - const float C) + const float C) { @@ -214,6 +215,8 @@ line_contribution(VoxelsOnCartesianGrid& gradient_image,const float resca + + void SingleScatterLikelihoodAndGradient:: s_contribution(VoxelsOnCartesianGrid& gradient_image, @@ -249,5 +252,27 @@ gradient_image[coords] += D; } + +void +SingleScatterLikelihoodAndGradient:: +line_contribution_act(VoxelsOnCartesianGrid& gradient_image, + const CartesianCoordinate3D& scatter_point, + const CartesianCoordinate3D& detector_coord, + const float C) +{ + + const CartesianCoordinate3D dist_vector = scatter_point - detector_coord ; + const float dist_sp1_det_squared = norm_squared(dist_vector); + const float solid_angle_factor = + std::min(static_cast(_PI/2), 1.F / dist_sp1_det_squared) ; + + line_contribution(gradient_image,solid_angle_factor, + scatter_point, + detector_coord, + -C); + +} + + END_NAMESPACE_STIR diff --git a/src/swig/stir.i b/src/swig/stir.i index be8133d240..b78ae701eb 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -87,7 +87,7 @@ #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" #include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" - +#include "stir/recon_buildblock/QuadraticPrior.h" #include "stir/analytic/FBP2D/FBP2DReconstruction.h" #include "stir/analytic/FBP3DRP/FBP3DRPReconstruction.h" @@ -1695,4 +1695,7 @@ stir::ScatterSimulation +%include "stir/recon_buildblock/QuadraticPrior.h" +#define elemT float +%template (QuadraticPrior3DFloat) stir::QuadraticPrior; From 37bc9e43b79e4e3e718ac7a65a9a08d8b93afc6b Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 30 Nov 2018 13:43:19 +0000 Subject: [PATCH 037/274] tested_detection_modelling --- .../scatter_detection_modelling.cxx | 2 +- .../scatter_estimate_for_one_scatter_point.cxx | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 6ef5b36b35..7658849e5f 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -138,7 +138,7 @@ detection_efficiency_no_scatter(const unsigned det_num_A, { // TODO: slightly dangerous to use a static here // it would give wrong results when the energy_thresholds are changed... - static const float detector_efficiency_no_scatter = 1 ; + static const float detector_efficiency_no_scatter = 1; /*detection_efficiency(511.F, en_window) > 0 ? detection_efficiency(511.F, en_window) : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F);*/ diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 412f13948d..c55af70b3d 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -230,19 +230,19 @@ std::vectordetection_efficiency_unscattered; int index_photopeak = 0; //default for one energy window - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) { - if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) + if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) - { + { - index_photopeak = i; - } + index_photopeak = i; + } - } - } + } + } //normalisation factor between trues and scattered counts From a36160c588939bd8197ba13dbf79bf0577878b5d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 3 Dec 2018 14:06:56 +0000 Subject: [PATCH 038/274] swig_cmakelist --- src/swig/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt index 95ac694476..bed896f802 100644 --- a/src/swig/CMakeLists.txt +++ b/src/swig/CMakeLists.txt @@ -133,7 +133,7 @@ if (BUILD_SWIG_MATLAB) set(MATLAB_DEST ${CMAKE_INSTALL_PREFIX}/matlab CACHE PATH "Destination for Matlab module (relative to CMAKE_INSTALL_PREFIX)") INSTALL(TARGETS ${SWIG_MODULE_stirMATLAB_REAL_NAME} DESTINATION ${MATLAB_DEST}) INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/+${module_name} DESTINATION ${MATLAB_DEST}) - file(GLOB SwigMatlabFiles "${CMAKE_CURRENT_BINARY_DIR}/Swig*.m") + file(GLOB SwigMatlabFiles "${CMAKE_CURRENT_BINARY_DIR}/*.m") INSTALL(FILES ${SwigMatlabFiles} DESTINATION ${MATLAB_DEST}) endif (BUILD_SWIG_MATLAB) \ No newline at end of file From bf01762d6a95538e9b23b004a5da922d285943ec Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 18 Jan 2019 14:34:34 +0000 Subject: [PATCH 039/274] check_NaN --- .../SingleScatterLikelihoodAndGradient.h | 4 +- src/scatter_buildblock/ScatterSimulation.cxx | 2 +- .../SingleScatterLikelihoodAndGradient.cxx | 68 ++++++++++++------- ...scatter_estimate_for_one_scatter_point.cxx | 6 +- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 09366a5057..255c8314e0 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -97,14 +97,14 @@ class SingleScatterLikelihoodAndGradient : public double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool compute_gradient,bool isgradient_mu); - double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool compute_gradient,bool isgradient_mu); + inline float KL(const double a, const float b, const float threshold_a = 0); + double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool compute_gradient,bool isgradient_mu); double L_G_for_view_segment_number_from_est_data(ProjData&data,ProjData&est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale); double L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale); - }; END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index a1ed4f2fdd..477ae61b90 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -168,7 +168,7 @@ process_data() } - std::cerr << "TOTAL SCATTER:= " << total_scatter << '\n'; + std::cout << "TOTAL SCATTER:= " << total_scatter << '\n'; return Succeeded::yes; } diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index c6bc0ad385..1b5149ee3d 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -70,27 +70,27 @@ L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const { if (isgradient_mu) - std::cerr <<"IS GRADIENT W.R.T. ATTENUATION"<< "\n"; + std::cout <<"IS GRADIENT W.R.T. ATTENUATION"<< "\n"; -else std::cerr <<"IS GRADIENT W.R.T. ACTIVITY"<< "\n"; +else std::cout <<"IS GRADIENT W.R.T. ACTIVITY"<< "\n"; this->output_proj_data_sptr->fill(0.f); - std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) { - std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + std::cout << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; } for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) { - std::cerr << "energy window lower level"<<"["< 1.E20) + warning("KL large at a=%g b=%g, threshold %g\n",a,b,threshold_a); +#ifdef ICHANGEDIT +#undef NDEBUG +#endif +#endif + assert(res>=-1.e-4); + return res; +} + + double SingleScatterLikelihoodAndGradient:: L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,bool compute_gradient, bool isgradient_mu) @@ -236,16 +258,12 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes //forward model const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); - v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); - - - sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-0.000000000000000000001; - - - - - gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+0.000000000000000000001)-1); + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); + float eps = 0.000000000000000000001; + sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-eps; + gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)-1); + if (sum != sum) error('Nan Here'); } return sum; @@ -424,13 +442,8 @@ L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est, const double y = L_G_estimate(tmp_gradient_image,bin,true,true); - sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()])- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]; - - - - - gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()])-1); + gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()])-1); } @@ -464,6 +477,7 @@ L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, boo } return scatter_ratio_singles; + //if (scatter_ratio_singles<0) std::cerr << "scatter_ratio_singles<0:" <& gradient, detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); - //if (detection_efficiency_scattered[i]==0&&detection_efficiency_unscattered[i]==0) - //return 0; - } //compute the probability of detection for two given energy windows X and Y @@ -603,6 +614,9 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, cos_angle(scatter_point - detector_coord_B, detB_to_ring_center)); + if (cos_incident_angle_AS*cos_incident_angle_BS<0) + return 0; + #ifndef NDEBUG { // check if mu-value ok @@ -684,6 +698,8 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, *dif_Compton_cross_section_value *common_factor; + + /*Single Scatter Forward model Jacobian w.r.t. attenuation: * The derivative is given by three terms, respectively in [A,S], [B,S] and [S] */ @@ -783,5 +799,7 @@ if(compute_gradient) } + + END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index c55af70b3d..eaa139dde4 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -194,10 +194,12 @@ std::vectordetection_efficiency_unscattered; const float cos_incident_angle_AS = static_cast( cos_angle(scatter_point - detector_coord_A, detA_to_ring_center)) ; + const float cos_incident_angle_BS = static_cast( cos_angle(scatter_point - detector_coord_B, detB_to_ring_center)) ; - + if (cos_incident_angle_AS*cos_incident_angle_BS<0) + return 0; #ifndef NDEBUG { // check if mu-value ok @@ -267,6 +269,8 @@ std::vectordetection_efficiency_unscattered; return scatter_ratio; + + } From 0afbdf6fec27cc71d83bc46d3d7fcef3d95bd805 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 22 Jan 2019 14:49:14 +0000 Subject: [PATCH 040/274] add_const --- .../SingleScatterLikelihoodAndGradient.h | 18 ++++++++++-------- .../SingleScatterLikelihoodAndGradient.cxx | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 255c8314e0..2d67449dde 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -63,9 +63,9 @@ class SingleScatterLikelihoodAndGradient : public - double L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale , bool compute_gradient = true ,bool isgradient_mu = true); + double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale , const bool compute_gradient = true ,const bool isgradient_mu = true); - double L_G_function_from_est_data(ProjData& data,ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale); + double L_G_function_from_est_data(const ProjData& data, ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale); @@ -91,19 +91,21 @@ class SingleScatterLikelihoodAndGradient : public L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, const std::size_t scatter_point_num, const unsigned det_num_A, - const unsigned det_num_B, bool compute_gradient,bool isgradient_mu); + const unsigned det_num_B, + const bool compute_gradient, + const bool isgradient_mu); - double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool compute_gradient,bool isgradient_mu); + double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, const bool compute_gradient, const bool isgradient_mu); - double L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, bool compute_gradient,bool isgradient_mu); + double L_G_for_view_segment_number(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu); inline float KL(const double a, const float b, const float threshold_a = 0); - double L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, bool compute_gradient,bool isgradient_mu); + double L_G_for_viewgram(const Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - double L_G_for_view_segment_number_from_est_data(ProjData&data,ProjData&est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale); + double L_G_for_view_segment_number_from_est_data(const ProjData&data,ProjData&est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale); - double L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale); + double L_G_for_viewgram_from_est_data(const Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale); }; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 1b5149ee3d..e52566c296 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -66,7 +66,7 @@ total_Compton_cross_section(511.F); double SingleScatterLikelihoodAndGradient:: -L_G_function(ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale,bool compute_gradient, bool isgradient_mu) +L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale, const bool compute_gradient, const bool isgradient_mu) { if (isgradient_mu) @@ -178,7 +178,7 @@ else std::cout <<"IS GRADIENT W.R.T. ACTIVITY"<< "\n"; double SingleScatterLikelihoodAndGradient:: -L_G_for_view_segment_number(ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale,bool compute_gradient,bool isgradient_mu) +L_G_for_view_segment_number(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu) { Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); @@ -213,7 +213,7 @@ inline float KL(const double a, const float b, const float threshold_a = 0) double SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,bool compute_gradient, bool isgradient_mu) +L_G_for_viewgram(const Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) { const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); @@ -258,7 +258,8 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes //forward model const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); - v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); + //in case a scaling factor for the data is needed. Currently not used and set to 1. float eps = 0.000000000000000000001; sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-eps; @@ -272,7 +273,7 @@ L_G_for_viewgram(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartes double SingleScatterLikelihoodAndGradient:: -L_G_function_from_est_data(ProjData& data,ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale) +L_G_function_from_est_data(const ProjData& data, ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale) { @@ -383,7 +384,7 @@ L_G_function_from_est_data(ProjData& data,ProjData& est_data,VoxelsOnCartesianGr double SingleScatterLikelihoodAndGradient:: -L_G_for_view_segment_number_from_est_data(ProjData&data,ProjData&est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale) +L_G_for_view_segment_number_from_est_data(const ProjData&data,ProjData&est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale) { Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); @@ -396,7 +397,7 @@ L_G_for_view_segment_number_from_est_data(ProjData&data,ProjData&est_data,Voxels } double SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale) +L_G_for_viewgram_from_est_data(const Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale) { const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); @@ -453,7 +454,7 @@ L_G_for_viewgram_from_est_data(Viewgram& viewgram,Viewgram& v_est, double SingleScatterLikelihoodAndGradient:: -L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, bool compute_gradient,bool isgradient_mu) +L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, const bool compute_gradient,const bool isgradient_mu) { double scatter_ratio_singles = 0; unsigned det_num_B=0; @@ -487,7 +488,7 @@ SingleScatterLikelihoodAndGradient:: L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, const std::size_t scatter_point_num, const unsigned det_num_A, - const unsigned det_num_B, bool compute_gradient,bool isgradient_mu) + const unsigned det_num_B, const bool compute_gradient,const bool isgradient_mu) { // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. From f7f80826c07af10a0d886e8d12dc14b54688f83b Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 25 Jan 2019 23:34:12 +0000 Subject: [PATCH 041/274] checks --- .../SingleScatterLikelihoodAndGradient.cxx | 45 ++++++++++--------- ...scatter_estimate_for_one_scatter_point.cxx | 24 +++------- .../scatter_likelihood_and_gradient.cxx | 2 +- 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index e52566c296..deeeea0721 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -543,38 +543,43 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, //The code can now compute the scatter for a combination of two windows X and Y //Default: one window -> The code will combine the window with itself + + //compute the probability of detection for two given energy windows X and Y + + std::vectordetection_efficiency_scattered; std::vectordetection_efficiency_unscattered; - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - detection_efficiency_scattered.push_back(0); - detection_efficiency_unscattered.push_back(0); - } + detection_efficiency_scattered.push_back(0); + detection_efficiency_unscattered.push_back(0); - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); - detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); - } - //compute the probability of detection for two given energy windows X and Y + //detection efficiency of each window for that energy + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); + detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); + } - int index0 = 0; - int index1 = 0; - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { + int index0 = 0; + int index1 = 0; + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; + index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; + + } + + + float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; + float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; - index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; - index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; - } - float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; - float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; const float emiss_to_detA = cached_integral_over_activity_image_between_scattpoint_det diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index eaa139dde4..660d1edaf1 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -117,43 +117,31 @@ SingleScatterSimulation:: std::vectordetection_efficiency_scattered; std::vectordetection_efficiency_unscattered; - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - detection_efficiency_scattered.push_back(0); - detection_efficiency_unscattered.push_back(0); - } +detection_efficiency_scattered.push_back(0); +detection_efficiency_unscattered.push_back(0); + +//detection efficiency of each window for that energy for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) { detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); - // if (detection_efficiency_scattered[i]==0&&detection_efficiency_unscattered[i]==0) - //return 0; } - -//Set the probability of detection for one energy window (Default) - int index0 = 0; int index1 = 0; if (this->template_exam_info_sptr->get_num_energy_windows()>1) { - //TODO: check if the values are insered correctly (i.e. index<=num_windows) - - /*if (this->template_exam_info_sptr->get_energy_window_pair().first!=-1 && - this->template_exam_info_sptr->get_energy_window_pair().second!=-1) - {*/ - index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; - index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; + index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; + index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; } - //compute the probability of detection for two given energy windows X and Y float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; diff --git a/src/scatter_utilities/scatter_likelihood_and_gradient.cxx b/src/scatter_utilities/scatter_likelihood_and_gradient.cxx index 13ebd73825..9f845ac15b 100644 --- a/src/scatter_utilities/scatter_likelihood_and_gradient.cxx +++ b/src/scatter_utilities/scatter_likelihood_and_gradient.cxx @@ -89,7 +89,7 @@ int main(int argc, const char *argv[]) shared_ptr data = ProjData::read_from_file("simulated_scatter_sino.hs"); const float rescale = 1; - shared_ptr > a(read_from_file >("initial_atn_image_LR.hv")); + shared_ptr > a(read_from_file >("true_atn_image.hv")); VoxelsOnCartesianGrid& gradient_image = dynamic_cast< VoxelsOnCartesianGrid& > (*a); gradient_image.fill(0); From e461ee2244f28c3b13bba056d9ab5bb7c6e7eefb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 4 Feb 2019 10:28:33 +0000 Subject: [PATCH 042/274] src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 4 ++-- src/scatter_utilities/scatter_likelihood_and_gradient.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index deeeea0721..d9951a94cb 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -66,7 +66,7 @@ total_Compton_cross_section(511.F); double SingleScatterLikelihoodAndGradient:: -L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale, const bool compute_gradient, const bool isgradient_mu) +L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient, const bool isgradient_mu, const float rescale) { if (isgradient_mu) @@ -259,7 +259,7 @@ L_G_for_viewgram(const Viewgram& viewgram,Viewgram& v_est,VoxelsOn const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); - //in case a scaling factor for the data is needed. Currently not used and set to 1. + //in case a scaling factor for the data is needed,i.e. for adding different level of noise. By default is set to 1. float eps = 0.000000000000000000001; sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-eps; diff --git a/src/scatter_utilities/scatter_likelihood_and_gradient.cxx b/src/scatter_utilities/scatter_likelihood_and_gradient.cxx index 9f845ac15b..cd5ebfc0ca 100644 --- a/src/scatter_utilities/scatter_likelihood_and_gradient.cxx +++ b/src/scatter_utilities/scatter_likelihood_and_gradient.cxx @@ -88,12 +88,12 @@ int main(int argc, const char *argv[]) parser.parse(argv[1]); shared_ptr data = ProjData::read_from_file("simulated_scatter_sino.hs"); - const float rescale = 1; + //const float rescale = 1; shared_ptr > a(read_from_file >("true_atn_image.hv")); VoxelsOnCartesianGrid& gradient_image = dynamic_cast< VoxelsOnCartesianGrid& > (*a); gradient_image.fill(0); - double g= simulation_method_sptr->L_G_function(*data,gradient_image, rescale, false); + double g= simulation_method_sptr->L_G_function(*data,gradient_image, false); t.stop(); cout << "Total Wall clock timetime: " << t.value() << " seconds" << endl; From 73162b12824cef4b15e94ba1dc531ad5906d0a37 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 4 Feb 2019 10:28:53 +0000 Subject: [PATCH 043/274] sedit --- src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 2d67449dde..cfbcfb57cd 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -63,7 +63,7 @@ class SingleScatterLikelihoodAndGradient : public - double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const float rescale , const bool compute_gradient = true ,const bool isgradient_mu = true); + double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); double L_G_function_from_est_data(const ProjData& data, ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale); From bc52c9e280e1b57ed49a0949040daa52f4cc2324 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 8 Feb 2019 09:11:54 +0000 Subject: [PATCH 044/274] new --- .../SingleScatterLikelihoodAndGradient.h | 12 +- .../SingleScatterLikelihoodAndGradient.cxx | 205 ++---------------- .../scatter_likelihood_and_gradient.cxx | 1 + 3 files changed, 21 insertions(+), 197 deletions(-) diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index cfbcfb57cd..709a4259b4 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -62,11 +62,8 @@ class SingleScatterLikelihoodAndGradient : public virtual ~SingleScatterLikelihoodAndGradient(); - double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); - - double L_G_function_from_est_data(const ProjData& data, ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale); - + double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); protected: @@ -97,15 +94,12 @@ class SingleScatterLikelihoodAndGradient : public double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, const bool compute_gradient, const bool isgradient_mu); - double L_G_for_view_segment_number(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu); + double L_G_for_view_segment_number(const ProjData&data,const ProjData&add_sino,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu); inline float KL(const double a, const float b, const float threshold_a = 0); - double L_G_for_viewgram(const Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - - double L_G_for_view_segment_number_from_est_data(const ProjData&data,ProjData&est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale); + double L_G_for_viewgram(const Viewgram& viewgram,const Viewgram& v_add,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - double L_G_for_viewgram_from_est_data(const Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale); }; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index d9951a94cb..5a0bf41494 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -69,13 +69,19 @@ SingleScatterLikelihoodAndGradient:: L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient, const bool isgradient_mu, const float rescale) { -if (isgradient_mu) - std::cout <<"IS GRADIENT W.R.T. ATTENUATION"<< "\n"; + shared_ptr add_sino(new ProjDataInMemory(this->output_proj_data_sptr->get_exam_info_sptr(), + this->output_proj_data_sptr->get_proj_data_info_ptr()->create_shared_clone())); + add_sino->fill(0.000000000000000000001); -else std::cout <<"IS GRADIENT W.R.T. ACTIVITY"<< "\n"; + L_G_function(data,*add_sino,gradient_image,compute_gradient,isgradient_mu,rescale); +} - this->output_proj_data_sptr->fill(0.f); +double +SingleScatterLikelihoodAndGradient:: +L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) +{ + this->output_proj_data_sptr->fill(0.f); std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; @@ -156,7 +162,7 @@ else std::cout <<"IS GRADIENT W.R.T. ACTIVITY"<< "\n"; //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - sum+=this->L_G_for_view_segment_number(data, gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); + sum+=this->L_G_for_view_segment_number(data, add_sino,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * @@ -178,13 +184,14 @@ else std::cout <<"IS GRADIENT W.R.T. ACTIVITY"<< "\n"; double SingleScatterLikelihoodAndGradient:: -L_G_for_view_segment_number(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu) +L_G_for_view_segment_number(const ProjData&data, const ProjData&add_sino,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu) { Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + Viewgram v_add=add_sino.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); - double sum = L_G_for_viewgram(viewgram,v_est,gradient_image, rescale, compute_gradient,isgradient_mu); + double sum = L_G_for_viewgram(viewgram,v_add,v_est,gradient_image, rescale, compute_gradient,isgradient_mu); return sum; @@ -213,7 +220,7 @@ inline float KL(const double a, const float b, const float threshold_a = 0) double SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram(const Viewgram& viewgram,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) +L_G_for_viewgram(const Viewgram& viewgram, const Viewgram& v_add,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) { const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); @@ -261,7 +268,8 @@ L_G_for_viewgram(const Viewgram& viewgram,Viewgram& v_est,VoxelsOn v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); //in case a scaling factor for the data is needed,i.e. for adding different level of noise. By default is set to 1. - float eps = 0.000000000000000000001; + float eps = v_add[bin.axial_pos_num()][bin.tangential_pos_num()]; + //float eps = 0.000000000000000000001; sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-eps; gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)-1); if (sum != sum) error('Nan Here'); @@ -271,185 +279,6 @@ L_G_for_viewgram(const Viewgram& viewgram,Viewgram& v_est,VoxelsOn } -double -SingleScatterLikelihoodAndGradient:: -L_G_function_from_est_data(const ProjData& data, ProjData& est_data,VoxelsOnCartesianGrid& gradient_image, const float rescale) -{ - - - this->output_proj_data_sptr->fill(0.f); - - - std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; - - if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && - this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) - { - std::cerr << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; - - } - - - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - std::cerr << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); - this->remove_cache_for_integrals_over_attenuation(); - this->sample_scatter_points(); - this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - - ViewSegmentNumbers vs_num; - - int bin_counter = 0; - int axial_bins = 0 ; - double sum = 0; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns - coordinate in a coordinate system where z=0 in the first ring of the scanner. - We want to shift this to a coordinate system where z=0 in the middle - of the scanner. - We can use get_m() as that uses the 'middle of the scanner' system. - (sorry) - */ -#ifndef NDEBUG - { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( - detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - assert(detector_coord_A.z() == 0); - assert(detector_coord_B.z() == 0); - // check that get_m refers to the middle of the scanner - const float m_first = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); - assert(fabs(m_last + m_first) < m_last * 10E-4); - } -#endif - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - - info("ScatterSimulator: Initialization finished ..."); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); - ++vs_num.view_num()) - { - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - - sum+=this->L_G_for_view_segment_number_from_est_data(data, est_data,gradient_image,vs_num,rescale); - - bin_counter += - this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - std::cout<< bin_counter << " / "<< total_bins <time_frame_definitions; + const TimeFrameDefinitions& time_frame_defs = emission_proj_data.get_exam_info_sptr()->time_frame_definitions; - if (min_scale_factor != 1 || max_scale_factor != 1 || !scatter_normalisation.is_trivial()) + if (min_scale_factor != 1 || max_scale_factor != 1 || !scatter_normalisation.is_trivial()) { ProjDataInMemory interpolated_scatter(emission_proj_data.get_exam_info_sptr(), emission_proj_data.get_proj_data_info_ptr()->create_shared_clone()); @@ -128,29 +127,48 @@ ScatterEstimation:: upsample_scatter_estimate(ProjData& scaled_scatter_proj_data, const ProjData& emission_proj_data, const ProjData& scatter_proj_data, - //BinNormalisation& scatter_normalisation, - // const ProjData& weights_proj_data, - //const float min_scale_factor, - //const float max_scale_factor, - //const unsigned half_filter_width, - //BSpline::BSplineType spline_type, const bool remove_interleaving) { stir::BSpline::BSplineType spline_type = stir::BSpline::linear; - shared_ptr - interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); - info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); - ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), interpolated_direct_scatter_proj_data_info_sptr); - interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); + // interpolate projdata + interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); + + // Perform Inverse Single Slice Rebinning + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + +} + + + +void +ScatterEstimation:: +downsample_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const bool remove_interleaving) +{ + stir::BSpline::BSplineType spline_type = stir::BSpline::linear; + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + // interpolate projdata + interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); - inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + // Perform Inverse Single Slice Rebinning + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); } diff --git a/src/swig/stir.i b/src/swig/stir.i index b78ae701eb..96dfd06107 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -58,6 +58,7 @@ #include "stir/ProjData.h" #include "stir/ProjDataInMemory.h" #include "stir/ProjDataInterfile.h" + #include "stir/CartesianCoordinate2D.h" #include "stir/CartesianCoordinate3D.h" From ad499bf15def55940ec13e1857dffa60a5da32a6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 4 Jun 2019 16:15:04 +0100 Subject: [PATCH 046/274] first test for upsampling --- src/buildblock/interpolate_projdata.cxx | 141 ++++++ .../interpolate_projdata.cxx.autosave | 464 ++++++++++++++++++ src/include/stir/interpolate_projdata.h | 7 + .../stir/numerics/sampling_functions.h | 7 + .../stir/numerics/sampling_functions.inl | 38 ++ .../upsample_and_fit_scatter_estimate.cxx | 4 +- 6 files changed, 659 insertions(+), 2 deletions(-) create mode 100644 src/buildblock/interpolate_projdata.cxx.autosave diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 8222c7b32a..84c214fff1 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -320,4 +320,145 @@ interpolate_projdata(ProjData& proj_data_out, return Succeeded::yes; } + + + +Succeeded +interpolate_projdata_test(ProjData& proj_data_out, + const ProjData& proj_data_in, + const bool remove_interleaving, + const bool use_view_offset) +{ + + //construct interpolator + stir::BSpline::BSplineType spline_type = stir::BSpline::linear; + BasicCoordinate<3, BSpline::BSplineType> these_types; + these_types[1]=these_types[2]=these_types[3]=spline_type; + BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); + + + if (use_view_offset) + warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); + + const ProjDataInfo & proj_data_in_info = + *proj_data_in.get_proj_data_info_ptr(); + const ProjDataInfo & proj_data_out_info = + *proj_data_out.get_proj_data_info_ptr(); + + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) + { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } + // check for the same ring radius + // This is strictly speaking only necessary for non-arccorrected data, but + // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) + { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } + + + + BasicCoordinate<3, double> offset, step ; + + // find relation between out_index and in_index such that they correspond to the same physical position + // out_index * m_zoom + m_offset = in_index + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + // offset in 'in' index units + offset[1] = + (proj_data_in_info.get_m(Bin(0,0,0,0)) - + proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; + step[1]= + out_sampling_m/in_sampling_m; + + const float in_sampling_phi = + (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / + (remove_interleaving ? 2 : 1); + + const float out_sampling_phi = + proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); + + const float out_view_offset = + use_view_offset + ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + const float in_view_offset = + use_view_offset + ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + offset[2] = + (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; + step[2] = + out_sampling_phi/in_sampling_phi; + + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + offset[3] = + (proj_data_out_info.get_s(Bin(0,0,0,0)) - + proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; + step[3]= + out_sampling_s/in_sampling_s; + + // initialise interpolator + if (remove_interleaving) + + { + + + shared_ptr non_interleaved_proj_data_info_sptr = + make_non_interleaved_proj_data_info(proj_data_in_info); + + const SegmentBySinogram non_interleaved_segment = + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_in.get_segment_by_sinogram(0)); + // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + + Array<3,float> extended = + extend_segment_in_views(non_interleaved_segment, 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + proj_data_interpolator.set_coef(extended); + } + else + { + Array<3,float> extended = + extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + proj_data_interpolator.set_coef(extended); + } + + // now do interpolation + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + sample_function_on_regular_grid_test(sino_3D_out, proj_data_interpolator, offset, step); + + proj_data_out.set_segment(sino_3D_out); + + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; + return Succeeded::yes; +} + END_NAMESPACE_STIR diff --git a/src/buildblock/interpolate_projdata.cxx.autosave b/src/buildblock/interpolate_projdata.cxx.autosave new file mode 100644 index 0000000000..4f6a21f34e --- /dev/null +++ b/src/buildblock/interpolate_projdata.cxx.autosave @@ -0,0 +1,464 @@ +// +// +/* + Copyright (C) 2005 - 2009-10-27, Hammersmith Imanet Ltd + Copyright (C) 2011-07-01 - 2011, Kris Thielemans + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +/*! + \file + \ingroup projdata + \brief Perform B-Splines Interpolation of sinograms + + \author Charalampos Tsoumpas + \author Kris Thielemans + +*/ +#include "stir/ProjData.h" +//#include "stir/display.h" +#include "stir/ProjDataInfo.h" +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/IndexRange.h" +#include "stir/BasicCoordinate.h" +#include "stir/Sinogram.h" +#include "stir/SegmentBySinogram.h" +#include "stir/Succeeded.h" +#include "stir/numerics/BSplines.h" +#include "stir/numerics/BSplinesRegularGrid.h" +#include "stir/interpolate_projdata.h" +#include "stir/extend_projdata.h" +#include "stir/numerics/sampling_functions.h" +#include + +START_NAMESPACE_STIR + +namespace detail_interpolate_projdata +{ + /* Collection of functions to remove interleaving in non-arccorrected data. + + It does this by doubling the number of views, and filling in the new + tangential positions by averaging the 4 neighbouring bins. + + WARNING: most of STIR will get confused by the resulting sinograms, + so only use them here for the interpolate_projdata implementation. + */ + + static shared_ptr + make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) + { + + if (dynamic_cast(&proj_data_info) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + shared_ptr new_proj_data_info_sptr( + proj_data_info.clone()); + new_proj_data_info_sptr-> + set_num_views(proj_data_info.get_num_views()*2); + return new_proj_data_info_sptr; + } + + static void + make_non_interleaved_sinogram(Sinogram& out_sinogram, + const Sinogram& in_sinogram) + { + if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + assert(out_sinogram.get_min_view_num() == 0); + assert(in_sinogram.get_min_view_num() == 0); + assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()*2); + assert(in_sinogram.get_segment_num() == 0); + assert(out_sinogram.get_segment_num() == 0); + + const int in_num_views = in_sinogram.get_num_views(); + + for (int view_num = out_sinogram.get_min_view_num(); + view_num <= out_sinogram.get_max_view_num(); + ++view_num) + { + // TODO don't put in outer tangential poss for now to avoid boundary stuff + for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; + tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; + ++tangential_pos_num) + { + if ((view_num+tangential_pos_num)%2 == 0) + { + const int in_view_num = + view_num%2==0 ? view_num/2 : (view_num+1)/2; + out_sinogram[view_num][tangential_pos_num] = + in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; + } + else + { + const int next_in_view = view_num/2+1; + const int other_in_view = (view_num+1)/2; + + out_sinogram[view_num][tangential_pos_num] = + (in_sinogram[view_num/2][tangential_pos_num] + + in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] + )/4; + } + } + } + } + +#if 0 + // not needed for now + static Sinogram + make_non_interleaved_sinogram(const ProjDataInfo& non_interleaved_proj_data_info, + const Sinogram& in_sinogram) + { + Sinogram out_sinogram = + non_interleaved_proj_data_info.get_empty_sinogram(in_sinogram.get_axial_pos_num(), + in_sinogram.get_segment_num()); + + make_non_interleaved_sinogram(out_sinogram, in_sinogram); + return out_sinogram; + } +#endif + + static void + make_non_interleaved_segment(SegmentBySinogram& out_segment, + const SegmentBySinogram& in_segment) + { + if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + for (int axial_pos_num = out_segment.get_min_axial_pos_num(); + axial_pos_num <= out_segment.get_max_axial_pos_num(); + ++axial_pos_num) + { + Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); + make_non_interleaved_sinogram(out_sinogram, + in_segment.get_sinogram(axial_pos_num)); + out_segment.set_sinogram(out_sinogram); + } + } + + static SegmentBySinogram + make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, + const SegmentBySinogram& in_segment) + { + + SegmentBySinogram out_segment = + non_interleaved_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); + + make_non_interleaved_segment(out_segment, in_segment); + + return out_segment; + } + +} // end namespace detail_interpolate_projdata + + +using namespace detail_interpolate_projdata; + +Succeeded +interpolate_projdata(ProjData& proj_data_out, + const ProjData& proj_data_in, const BSpline::BSplineType these_types, + const bool remove_interleaving, + const bool use_view_offset) +{ + + BasicCoordinate<3, BSpline::BSplineType> these_types_3; + + these_types_3[1]=these_types_3[2]=these_types_3[3]=these_types; + + interpolate_projdata(proj_data_out,proj_data_in,these_types_3, remove_interleaving, use_view_offset); + + + return Succeeded::yes; +} + +Succeeded +interpolate_projdata(ProjData& proj_data_out, + const ProjData& proj_data_in, + const BasicCoordinate<3, BSpline::BSplineType> & these_types, + const bool remove_interleaving, + const bool use_view_offset) +{ + + + + if (use_view_offset) + warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); + + const ProjDataInfo & proj_data_in_info = + *proj_data_in.get_proj_data_info_ptr(); + const ProjDataInfo & proj_data_out_info = + *proj_data_out.get_proj_data_info_ptr(); + + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) + { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } + // check for the same ring radius + // This is strictly speaking only necessary for non-arccorrected data, but + // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) + { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } + + + + BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); + + BasicCoordinate<3, double> offset, step ; + + // find relation between out_index and in_index such that they correspond to the same physical position + // out_index * m_zoom + m_offset = in_index + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + // offset in 'in' index units + offset[1] = + (proj_data_in_info.get_m(Bin(0,0,0,0)) - + proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; + step[1]= + out_sampling_m/in_sampling_m; + + const float in_sampling_phi = + (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / + (remove_interleaving ? 2 : 1); + + const float out_sampling_phi = + proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); + + const float out_view_offset = + use_view_offset + ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + const float in_view_offset = + use_view_offset + ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + offset[2] = + (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; + step[2] = + out_sampling_phi/in_sampling_phi; + + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + offset[3] = + (proj_data_out_info.get_s(Bin(0,0,0,0)) - + proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; + step[3]= + out_sampling_s/in_sampling_s; + + // initialise interpolator + if (remove_interleaving) + + { + + + shared_ptr non_interleaved_proj_data_info_sptr = + make_non_interleaved_proj_data_info(proj_data_in_info); + + const SegmentBySinogram non_interleaved_segment = + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_in.get_segment_by_sinogram(0)); + // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + + Array<3,float> extended = + extend_segment_in_views(non_interleaved_segment, 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + proj_data_interpolator.set_coef(extended); + } + else + { + Array<3,float> extended = + extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + proj_data_interpolator.set_coef(extended); + } + + // now do interpolation + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); + + proj_data_out.set_segment(sino_3D_out); + + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; + return Succeeded::yes; +} + + + + +Succeeded +interpolate_projdata_test(ProjData& proj_data_out, + const ProjData& proj_data_in, + const bool remove_interleaving, + const bool use_view_offset) +{ + + //construct Bspline sinterpolator + stir::BSpline::BSplineType spline_type = stir::BSpline::linear; + BasicCoordinate<3, BSpline::BSplineType> these_types; + these_types[1]=these_types[2]=these_types[3]=spline_type; + BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); + + + if (use_view_offset) + warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); + + const ProjDataInfo & proj_data_in_info = + *proj_data_in.get_proj_data_info_ptr(); + const ProjDataInfo & proj_data_out_info = + *proj_data_out.get_proj_data_info_ptr(); + + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) + { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } + // check for the same ring radius + // This is strictly speaking only necessary for non-arccorrected data, but + // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) + { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } + + + + BasicCoordinate<3, double> offset, step ; + + // find relation between out_index and in_index such that they correspond to the same physical position + // out_index * m_zoom + m_offset = in_index + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + // offset in 'in' index units + offset[1] = + (proj_data_in_info.get_m(Bin(0,0,0,0)) - + proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; + step[1]= + out_sampling_m/in_sampling_m; + + const float in_sampling_phi = + (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / + (remove_interleaving ? 2 : 1); + + const float out_sampling_phi = + proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); + + const float out_view_offset = + use_view_offset + ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + const float in_view_offset = + use_view_offset + ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + offset[2] = + (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; + step[2] = + out_sampling_phi/in_sampling_phi; + + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + offset[3] = + (proj_data_out_info.get_s(Bin(0,0,0,0)) - + proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; + step[3]= + out_sampling_s/in_sampling_s; + + // initialise interpolator + if (remove_interleaving) + + { + + + shared_ptr non_interleaved_proj_data_info_sptr = + make_non_interleaved_proj_data_info(proj_data_in_info); + + const SegmentBySinogram non_interleaved_segment = + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_in.get_segment_by_sinogram(0)); + // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + + Array<3,float> extended = + extend_segment_in_views(non_interleaved_segment, 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + proj_data_interpolator.set_coef(extended); + } + else + { + Array<3,float> extended = + extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + proj_data_interpolator.set_coef(extended); + } + + // now do interpolation + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + sample_function_on_regular_grid_test(sino_3D_out, proj_data_interpolator, offset, step); + + proj_data_out.set_segment(sino_3D_out); + + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; + return Succeeded::yes; +} + +END_NAMESPACE_STIR diff --git a/src/include/stir/interpolate_projdata.h b/src/include/stir/interpolate_projdata.h index c74125dbc7..d3b529e2c7 100644 --- a/src/include/stir/interpolate_projdata.h +++ b/src/include/stir/interpolate_projdata.h @@ -69,6 +69,13 @@ interpolate_projdata(ProjData& proj_data_out, const BasicCoordinate<3, BSpline::BSplineType> & spline_type, const bool remove_interleaving = false, const bool use_view_offset = false); + +Succeeded +interpolate_projdata_test(ProjData& proj_data_out, + const ProjData& proj_data_in, + const bool remove_interleaving = false, + const bool use_view_offset = false); + //@} END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index dab9a2be8c..bcea873905 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -57,6 +57,13 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step); +template +inline +void sample_function_on_regular_grid_test(Array<3,elemT>& out, + FunctionType func, + const BasicCoordinate<3, positionT>& offset, + const BasicCoordinate<3, positionT>& step); + END_NAMESPACE_STIR #include "stir/numerics/sampling_functions.inl" diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 4ac29f321a..4c69ab5f62 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -62,4 +62,42 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, } } +template +void sample_function_on_regular_grid_test(Array<3,elemT>& out, + FunctionType func, + const BasicCoordinate<3, positionT>& offset, + const BasicCoordinate<3, positionT>& step) +{ + BasicCoordinate<3,int> min_out, max_out; + IndexRange<3> out_range = out.get_index_range(); + if (!out_range.get_regular_range(min_out,max_out)) + warning("Output must be regular range!"); + + BasicCoordinate<3, int> index_out; + BasicCoordinate<3, positionT> relative_positions; + index_out[1]=min_out[1]; + relative_positions[1]= index_out[1] * step[1] - offset[1] ; + const BasicCoordinate<3, positionT> max_relative_positions= + (BasicCoordinate<3,positionT>(max_out)+static_cast(.001)) * step + offset; + for (; + index_out[1]<=max_out[1] && relative_positions[1]<=max_relative_positions[1]; + ++index_out[1], relative_positions[1]+= step[1]) + { + index_out[2]=min_out[2]; + relative_positions[2]= index_out[2] * step[2] + offset[2] ; + for (; + index_out[2]<=max_out[2] && relative_positions[2]<=max_relative_positions[2]; + ++index_out[2], relative_positions[2]+= step[2]) + { + index_out[3]=min_out[3]; + relative_positions[3]= index_out[3] * step[3] + offset[3] ; + for (; + index_out[3]<=max_out[3] && relative_positions[3]<=max_relative_positions[3]; + ++index_out[3], relative_positions[3]+= step[3]) + out[index_out] = func(relative_positions) ; + } + } +} + + END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index ded584f66e..cac4d5e5ae 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -155,7 +155,7 @@ downsample_scatter_estimate(ProjData& scaled_scatter_proj_data, const ProjData& scatter_proj_data, const bool remove_interleaving) { - stir::BSpline::BSplineType spline_type = stir::BSpline::linear; + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); @@ -165,7 +165,7 @@ downsample_scatter_estimate(ProjData& scaled_scatter_proj_data, interpolated_direct_scatter_proj_data_info_sptr); // interpolate projdata - interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); + interpolate_projdata_test(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); // Perform Inverse Single Slice Rebinning inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); From 7210f0da4e1bcc48ba5e1b4b02b423552551b95c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 4 Jun 2019 17:27:35 +0100 Subject: [PATCH 047/274] nonzero --- src/buildblock/interpolate_projdata.cxx | 9 ++++++++- src/include/stir/numerics/sampling_functions.inl | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 84c214fff1..d4729cfb0e 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -40,6 +40,9 @@ #include "stir/interpolate_projdata.h" #include "stir/extend_projdata.h" #include "stir/numerics/sampling_functions.h" +#include "stir_experimental/motion/Transform3DObjectImageProcessor.h" +#include "stir_experimental/motion/transform_3d_object.h" +#include "stir_experimental/numerics/more_interpolators.h" #include START_NAMESPACE_STIR @@ -452,7 +455,11 @@ interpolate_projdata_test(ProjData& proj_data_out, // now do interpolation SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sample_function_on_regular_grid_test(sino_3D_out, proj_data_interpolator, offset, step); + sino_3D_out.fill(20); + PushTransposeLinearInterpolator interpolator; + interpolator.set_output(sino_3D_out); + + sample_function_on_regular_grid_test(sino_3D_out, interpolator, offset, step); proj_data_out.set_segment(sino_3D_out); diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 4c69ab5f62..2ea2d1ebca 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -94,7 +94,8 @@ void sample_function_on_regular_grid_test(Array<3,elemT>& out, for (; index_out[3]<=max_out[3] && relative_positions[3]<=max_relative_positions[3]; ++index_out[3], relative_positions[3]+= step[3]) - out[index_out] = func(relative_positions) ; + func.add_to(relative_positions, + out[index_out]); } } } From 5d45e16a4144da8f12034926e5c25a3398fdf7aa Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 4 Jun 2019 18:10:18 +0100 Subject: [PATCH 048/274] output --- src/buildblock/interpolate_projdata.cxx | 3 +- .../interpolate_projdata.cxx.autosave | 464 ------------------ 2 files changed, 2 insertions(+), 465 deletions(-) delete mode 100644 src/buildblock/interpolate_projdata.cxx.autosave diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index d4729cfb0e..bc239aedc2 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -454,10 +454,11 @@ interpolate_projdata_test(ProjData& proj_data_out, // now do interpolation + SegmentBySinogram sino_3D_in = proj_data_in.get_empty_segment_by_sinogram(0) ; SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; sino_3D_out.fill(20); PushTransposeLinearInterpolator interpolator; - interpolator.set_output(sino_3D_out); + interpolator.set_output(sino_3D_in); sample_function_on_regular_grid_test(sino_3D_out, interpolator, offset, step); diff --git a/src/buildblock/interpolate_projdata.cxx.autosave b/src/buildblock/interpolate_projdata.cxx.autosave deleted file mode 100644 index 4f6a21f34e..0000000000 --- a/src/buildblock/interpolate_projdata.cxx.autosave +++ /dev/null @@ -1,464 +0,0 @@ -// -// -/* - Copyright (C) 2005 - 2009-10-27, Hammersmith Imanet Ltd - Copyright (C) 2011-07-01 - 2011, Kris Thielemans - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ -/*! - \file - \ingroup projdata - \brief Perform B-Splines Interpolation of sinograms - - \author Charalampos Tsoumpas - \author Kris Thielemans - -*/ -#include "stir/ProjData.h" -//#include "stir/display.h" -#include "stir/ProjDataInfo.h" -#include "stir/ProjDataInfoCylindricalNoArcCorr.h" -#include "stir/IndexRange.h" -#include "stir/BasicCoordinate.h" -#include "stir/Sinogram.h" -#include "stir/SegmentBySinogram.h" -#include "stir/Succeeded.h" -#include "stir/numerics/BSplines.h" -#include "stir/numerics/BSplinesRegularGrid.h" -#include "stir/interpolate_projdata.h" -#include "stir/extend_projdata.h" -#include "stir/numerics/sampling_functions.h" -#include - -START_NAMESPACE_STIR - -namespace detail_interpolate_projdata -{ - /* Collection of functions to remove interleaving in non-arccorrected data. - - It does this by doubling the number of views, and filling in the new - tangential positions by averaging the 4 neighbouring bins. - - WARNING: most of STIR will get confused by the resulting sinograms, - so only use them here for the interpolate_projdata implementation. - */ - - static shared_ptr - make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) - { - - if (dynamic_cast(&proj_data_info) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - shared_ptr new_proj_data_info_sptr( - proj_data_info.clone()); - new_proj_data_info_sptr-> - set_num_views(proj_data_info.get_num_views()*2); - return new_proj_data_info_sptr; - } - - static void - make_non_interleaved_sinogram(Sinogram& out_sinogram, - const Sinogram& in_sinogram) - { - if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - assert(out_sinogram.get_min_view_num() == 0); - assert(in_sinogram.get_min_view_num() == 0); - assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()*2); - assert(in_sinogram.get_segment_num() == 0); - assert(out_sinogram.get_segment_num() == 0); - - const int in_num_views = in_sinogram.get_num_views(); - - for (int view_num = out_sinogram.get_min_view_num(); - view_num <= out_sinogram.get_max_view_num(); - ++view_num) - { - // TODO don't put in outer tangential poss for now to avoid boundary stuff - for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; - tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; - ++tangential_pos_num) - { - if ((view_num+tangential_pos_num)%2 == 0) - { - const int in_view_num = - view_num%2==0 ? view_num/2 : (view_num+1)/2; - out_sinogram[view_num][tangential_pos_num] = - in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; - } - else - { - const int next_in_view = view_num/2+1; - const int other_in_view = (view_num+1)/2; - - out_sinogram[view_num][tangential_pos_num] = - (in_sinogram[view_num/2][tangential_pos_num] + - in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] - )/4; - } - } - } - } - -#if 0 - // not needed for now - static Sinogram - make_non_interleaved_sinogram(const ProjDataInfo& non_interleaved_proj_data_info, - const Sinogram& in_sinogram) - { - Sinogram out_sinogram = - non_interleaved_proj_data_info.get_empty_sinogram(in_sinogram.get_axial_pos_num(), - in_sinogram.get_segment_num()); - - make_non_interleaved_sinogram(out_sinogram, in_sinogram); - return out_sinogram; - } -#endif - - static void - make_non_interleaved_segment(SegmentBySinogram& out_segment, - const SegmentBySinogram& in_segment) - { - if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - for (int axial_pos_num = out_segment.get_min_axial_pos_num(); - axial_pos_num <= out_segment.get_max_axial_pos_num(); - ++axial_pos_num) - { - Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); - make_non_interleaved_sinogram(out_sinogram, - in_segment.get_sinogram(axial_pos_num)); - out_segment.set_sinogram(out_sinogram); - } - } - - static SegmentBySinogram - make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, - const SegmentBySinogram& in_segment) - { - - SegmentBySinogram out_segment = - non_interleaved_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); - - make_non_interleaved_segment(out_segment, in_segment); - - return out_segment; - } - -} // end namespace detail_interpolate_projdata - - -using namespace detail_interpolate_projdata; - -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, const BSpline::BSplineType these_types, - const bool remove_interleaving, - const bool use_view_offset) -{ - - BasicCoordinate<3, BSpline::BSplineType> these_types_3; - - these_types_3[1]=these_types_3[2]=these_types_3[3]=these_types; - - interpolate_projdata(proj_data_out,proj_data_in,these_types_3, remove_interleaving, use_view_offset); - - - return Succeeded::yes; -} - -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, - const BasicCoordinate<3, BSpline::BSplineType> & these_types, - const bool remove_interleaving, - const bool use_view_offset) -{ - - - - if (use_view_offset) - warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); - - const ProjDataInfo & proj_data_in_info = - *proj_data_in.get_proj_data_info_ptr(); - const ProjDataInfo & proj_data_out_info = - *proj_data_out.get_proj_data_info_ptr(); - - if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) - { - error("interpolate_projdata needs both projection data to be of the same type\n" - "(e.g. both arc-corrected or both not arc-corrected)"); - } - // check for the same ring radius - // This is strictly speaking only necessary for non-arccorrected data, but - // we leave it in for all cases. - if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - - proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) - { - error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); - } - - - - BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); - - BasicCoordinate<3, double> offset, step ; - - // find relation between out_index and in_index such that they correspond to the same physical position - // out_index * m_zoom + m_offset = in_index - const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); - const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); - // offset in 'in' index units - offset[1] = - (proj_data_in_info.get_m(Bin(0,0,0,0)) - - proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; - step[1]= - out_sampling_m/in_sampling_m; - - const float in_sampling_phi = - (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / - (remove_interleaving ? 2 : 1); - - const float out_sampling_phi = - proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); - - const float out_view_offset = - use_view_offset - ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - const float in_view_offset = - use_view_offset - ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - offset[2] = - (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; - step[2] = - out_sampling_phi/in_sampling_phi; - - const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); - const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); - offset[3] = - (proj_data_out_info.get_s(Bin(0,0,0,0)) - - proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; - step[3]= - out_sampling_s/in_sampling_s; - - // initialise interpolator - if (remove_interleaving) - - { - - - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); - - const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); - // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - - Array<3,float> extended = - extend_segment_in_views(non_interleaved_segment, 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - proj_data_interpolator.set_coef(extended); - } - else - { - Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - proj_data_interpolator.set_coef(extended); - } - - // now do interpolation - - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); - - proj_data_out.set_segment(sino_3D_out); - - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - return Succeeded::yes; -} - - - - -Succeeded -interpolate_projdata_test(ProjData& proj_data_out, - const ProjData& proj_data_in, - const bool remove_interleaving, - const bool use_view_offset) -{ - - //construct Bspline sinterpolator - stir::BSpline::BSplineType spline_type = stir::BSpline::linear; - BasicCoordinate<3, BSpline::BSplineType> these_types; - these_types[1]=these_types[2]=these_types[3]=spline_type; - BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); - - - if (use_view_offset) - warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); - - const ProjDataInfo & proj_data_in_info = - *proj_data_in.get_proj_data_info_ptr(); - const ProjDataInfo & proj_data_out_info = - *proj_data_out.get_proj_data_info_ptr(); - - if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) - { - error("interpolate_projdata needs both projection data to be of the same type\n" - "(e.g. both arc-corrected or both not arc-corrected)"); - } - // check for the same ring radius - // This is strictly speaking only necessary for non-arccorrected data, but - // we leave it in for all cases. - if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - - proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) - { - error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); - } - - - - BasicCoordinate<3, double> offset, step ; - - // find relation between out_index and in_index such that they correspond to the same physical position - // out_index * m_zoom + m_offset = in_index - const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); - const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); - // offset in 'in' index units - offset[1] = - (proj_data_in_info.get_m(Bin(0,0,0,0)) - - proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; - step[1]= - out_sampling_m/in_sampling_m; - - const float in_sampling_phi = - (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / - (remove_interleaving ? 2 : 1); - - const float out_sampling_phi = - proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); - - const float out_view_offset = - use_view_offset - ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - const float in_view_offset = - use_view_offset - ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - offset[2] = - (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; - step[2] = - out_sampling_phi/in_sampling_phi; - - const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); - const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); - offset[3] = - (proj_data_out_info.get_s(Bin(0,0,0,0)) - - proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; - step[3]= - out_sampling_s/in_sampling_s; - - // initialise interpolator - if (remove_interleaving) - - { - - - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); - - const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); - // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - - Array<3,float> extended = - extend_segment_in_views(non_interleaved_segment, 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - proj_data_interpolator.set_coef(extended); - } - else - { - Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - proj_data_interpolator.set_coef(extended); - } - - // now do interpolation - - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sample_function_on_regular_grid_test(sino_3D_out, proj_data_interpolator, offset, step); - - proj_data_out.set_segment(sino_3D_out); - - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - return Succeeded::yes; -} - -END_NAMESPACE_STIR From 8c5f0a50f32ec56548195592ebf1aa81eff5d833 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 4 Jun 2019 22:46:13 +0100 Subject: [PATCH 049/274] test --- src/buildblock/interpolate_projdata.cxx | 41 +++++++++++++------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index bc239aedc2..b0f7b12b63 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -291,6 +291,8 @@ interpolate_projdata(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; proj_data_interpolator.set_coef(extended); } else @@ -308,6 +310,8 @@ interpolate_projdata(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; proj_data_interpolator.set_coef(extended); } @@ -333,11 +337,12 @@ interpolate_projdata_test(ProjData& proj_data_out, const bool use_view_offset) { - //construct interpolator - stir::BSpline::BSplineType spline_type = stir::BSpline::linear; - BasicCoordinate<3, BSpline::BSplineType> these_types; - these_types[1]=these_types[2]=these_types[3]=spline_type; - BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); + SegmentBySinogram sino_3D_in = proj_data_in.get_empty_segment_by_sinogram(0) ; + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + sino_3D_out.fill(20); + PushTransposeLinearInterpolator interpolator; + interpolator.set_output(sino_3D_in); + if (use_view_offset) @@ -432,7 +437,12 @@ interpolate_projdata_test(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - proj_data_interpolator.set_coef(extended); + sample_function_on_regular_grid_test(extended, interpolator, offset, step); + std::cerr << "MAX D "<< extended.find_max() << '\n'; + std::cerr << "MIN D "<< extended.find_min() << '\n'; + proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; } else { @@ -449,23 +459,16 @@ interpolate_projdata_test(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - proj_data_interpolator.set_coef(extended); + sample_function_on_regular_grid_test(extended, interpolator, offset, step); + std::cerr << "MAX D "<< extended.find_max() << '\n'; + std::cerr << "MIN D "<< extended.find_min() << '\n'; + proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; } // now do interpolation - SegmentBySinogram sino_3D_in = proj_data_in.get_empty_segment_by_sinogram(0) ; - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sino_3D_out.fill(20); - PushTransposeLinearInterpolator interpolator; - interpolator.set_output(sino_3D_in); - - sample_function_on_regular_grid_test(sino_3D_out, interpolator, offset, step); - - proj_data_out.set_segment(sino_3D_out); - - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; return Succeeded::yes; } From f94a23fd9abc3fbd4df050a624294ccdf48a66ad Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 4 Jun 2019 23:17:30 +0100 Subject: [PATCH 050/274] okk --- src/buildblock/interpolate_projdata.cxx | 11 ++++-- .../stir/numerics/sampling_functions.inl | 3 +- .../numerics/more_interpolators.h | 2 ++ .../numerics/more_interpolators.inl | 36 ++++++++++--------- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index b0f7b12b63..8a4ca3cc9b 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -337,11 +337,16 @@ interpolate_projdata_test(ProjData& proj_data_out, const bool use_view_offset) { - SegmentBySinogram sino_3D_in = proj_data_in.get_empty_segment_by_sinogram(0) ; + PullLinearInterpolator interpolator; SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; sino_3D_out.fill(20); - PushTransposeLinearInterpolator interpolator; - interpolator.set_output(sino_3D_in); + for (int segment_num = proj_data_in.get_min_segment_num(); + segment_num <= proj_data_in.get_max_segment_num(); ++segment_num) + { + SegmentBySinogram sino_3D_in(proj_data_in.get_segment_by_sinogram(segment_num)) ; + Array<3,float> ext = sino_3D_in; + interpolator.set_input(ext); + } diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 2ea2d1ebca..288819f5c3 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -94,8 +94,7 @@ void sample_function_on_regular_grid_test(Array<3,elemT>& out, for (; index_out[3]<=max_out[3] && relative_positions[3]<=max_relative_positions[3]; ++index_out[3], relative_positions[3]+= step[3]) - func.add_to(relative_positions, - out[index_out]); + out[index_out] = func(relative_positions) ; } } } diff --git a/src/include/stir_experimental/numerics/more_interpolators.h b/src/include/stir_experimental/numerics/more_interpolators.h index 9be43b2001..bdfb7f3fc7 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.h +++ b/src/include/stir_experimental/numerics/more_interpolators.h @@ -17,6 +17,7 @@ */ #include "stir/BasicCoordinate.h" +#include "stir/ProjData.h" #include "stir/Array.h" @@ -80,6 +81,7 @@ PullLinearInterpolator this->_input_ptr = &input; } + template elemT operator()(const BasicCoordinate<3, positionT>& point_in_input_coords) const { diff --git a/src/include/stir_experimental/numerics/more_interpolators.inl b/src/include/stir_experimental/numerics/more_interpolators.inl index f965d1aa8a..83d568c5ce 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.inl +++ b/src/include/stir_experimental/numerics/more_interpolators.inl @@ -13,6 +13,7 @@ */ #include "stir/Coordinate3D.h" +#include "stir/ProjData.h" #include "stir/Array.h" #include "stir/round.h" #include @@ -65,16 +66,17 @@ push_nearest_neighbour_interpolate(Array& out, + template elemT -pull_linear_interpolate(const Array<3, elemT>& in, - const BasicCoordinate<3, positionT>& point_in_input_coords) +pull_linear_interpolate(const Array<3, elemT>& in, + const BasicCoordinate<3, positionT>& point_in_input_coords) { - // find left neighbour - const Coordinate3D + // find left neighbour + const Coordinate3D left_neighbour(round(std::floor(point_in_input_coords[1])), - round(std::floor(point_in_input_coords[2])), - round(std::floor(point_in_input_coords[3]))); + round(std::floor(point_in_input_coords[2])), + round(std::floor(point_in_input_coords[3]))); // TODO handle boundary conditions if (left_neighbour[1] < in.get_max_index() && @@ -97,17 +99,17 @@ pull_linear_interpolate(const Array<3, elemT>& in, const positionT iyc = 1 - iy; const positionT izc = 1 - iz; return - static_cast - ( - ixc * (iyc * (izc * in[z1][y1][x1] - + iz * in[z2][y1][x1]) - + iy * (izc * in[z1][y2][x1] - + iz * in[z2][y2][x1])) - + ix * (iyc * (izc * in[z1][y1][x2] - + iz * in[z2][y1][x2]) - + iy * (izc * in[z1][y2][x2] - + iz * in[z2][y2][x2])) - ); + static_cast + ( + ixc * (iyc * (izc * in[z1][y1][x1] + + iz * in[z2][y1][x1]) + + iy * (izc * in[z1][y2][x1] + + iz * in[z2][y2][x1])) + + ix * (iyc * (izc * in[z1][y1][x2] + + iz * in[z2][y1][x2]) + + iy * (izc * in[z1][y2][x2] + + iz * in[z2][y2][x2])) + ); } else return 0; From c8b0992939f5dc325e5b357de668c1bd82ec40c6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 4 Jun 2019 23:40:24 +0100 Subject: [PATCH 051/274] pull_done --- src/buildblock/interpolate_projdata.cxx | 41 ++++++++++--------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 8a4ca3cc9b..a85af0c56d 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -337,19 +337,8 @@ interpolate_projdata_test(ProjData& proj_data_out, const bool use_view_offset) { - PullLinearInterpolator interpolator; - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sino_3D_out.fill(20); - for (int segment_num = proj_data_in.get_min_segment_num(); - segment_num <= proj_data_in.get_max_segment_num(); ++segment_num) - { - SegmentBySinogram sino_3D_in(proj_data_in.get_segment_by_sinogram(segment_num)) ; - Array<3,float> ext = sino_3D_in; - interpolator.set_input(ext); - } - - + PullLinearInterpolator proj_data_interpolator; if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); @@ -374,6 +363,7 @@ interpolate_projdata_test(ProjData& proj_data_out, + BasicCoordinate<3, double> offset, step ; // find relation between out_index and in_index such that they correspond to the same physical position @@ -442,12 +432,10 @@ interpolate_projdata_test(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - sample_function_on_regular_grid_test(extended, interpolator, offset, step); - std::cerr << "MAX D "<< extended.find_max() << '\n'; - std::cerr << "MIN D "<< extended.find_min() << '\n'; - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; + proj_data_interpolator.set_input(extended); + //proj_data_interpolator.set_input(proj_data_in.get_empty_segment_by_sinogram(0)); } else { @@ -464,17 +452,20 @@ interpolate_projdata_test(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - sample_function_on_regular_grid_test(extended, interpolator, offset, step); - std::cerr << "MAX D "<< extended.find_max() << '\n'; - std::cerr << "MIN D "<< extended.find_min() << '\n'; - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; + proj_data_interpolator.set_input(extended); } // now do interpolation + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); + + proj_data_out.set_segment(sino_3D_out); + + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; return Succeeded::yes; } - END_NAMESPACE_STIR From c0c1bdba8b4749d1300262039c7c1b93bce26ab6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 4 Jun 2019 23:56:02 +0100 Subject: [PATCH 052/274] push to check --- src/buildblock/interpolate_projdata.cxx | 144 +++++++++++++++++- src/include/stir/interpolate_projdata.h | 8 +- .../stir/numerics/sampling_functions.h | 9 +- .../stir/numerics/sampling_functions.inl | 40 ++++- src/include/stir/scatter/ScatterEstimation.h | 8 +- .../upsample_and_fit_scatter_estimate.cxx | 28 +++- 6 files changed, 229 insertions(+), 8 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index a85af0c56d..4d3bd355c4 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -331,7 +331,7 @@ interpolate_projdata(ProjData& proj_data_out, Succeeded -interpolate_projdata_test(ProjData& proj_data_out, +interpolate_projdata_pull(ProjData& proj_data_out, const ProjData& proj_data_in, const bool remove_interleaving, const bool use_view_offset) @@ -460,7 +460,146 @@ interpolate_projdata_test(ProjData& proj_data_out, // now do interpolation SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); + sample_function_on_regular_grid_pull(sino_3D_out, proj_data_interpolator, offset, step); + + proj_data_out.set_segment(sino_3D_out); + + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; + return Succeeded::yes; +} + +Succeeded +interpolate_projdata_push(ProjData& proj_data_out, + const ProjData& proj_data_in, + const bool remove_interleaving, + const bool use_view_offset) +{ + + + PushTransposeLinearInterpolator proj_data_interpolator; + if (use_view_offset) + warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); + + const ProjDataInfo & proj_data_in_info = + *proj_data_in.get_proj_data_info_ptr(); + const ProjDataInfo & proj_data_out_info = + *proj_data_out.get_proj_data_info_ptr(); + + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) + { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } + // check for the same ring radius + // This is strictly speaking only necessary for non-arccorrected data, but + // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) + { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } + + + + + BasicCoordinate<3, double> offset, step ; + + // find relation between out_index and in_index such that they correspond to the same physical position + // out_index * m_zoom + m_offset = in_index + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + // offset in 'in' index units + offset[1] = + (proj_data_in_info.get_m(Bin(0,0,0,0)) - + proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; + step[1]= + out_sampling_m/in_sampling_m; + + const float in_sampling_phi = + (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / + (remove_interleaving ? 2 : 1); + + const float out_sampling_phi = + proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); + + const float out_view_offset = + use_view_offset + ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + const float in_view_offset = + use_view_offset + ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + offset[2] = + (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; + step[2] = + out_sampling_phi/in_sampling_phi; + + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + offset[3] = + (proj_data_out_info.get_s(Bin(0,0,0,0)) - + proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; + step[3]= + out_sampling_s/in_sampling_s; + + // initialise interpolator + if (remove_interleaving) + + { + + + shared_ptr non_interleaved_proj_data_info_sptr = + make_non_interleaved_proj_data_info(proj_data_in_info); + + const SegmentBySinogram non_interleaved_segment = + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_in.get_segment_by_sinogram(0)); + // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + + Array<3,float> extended = + extend_segment_in_views(non_interleaved_segment, 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; + proj_data_interpolator.set_output(extended); + //proj_data_interpolator.set_input(proj_data_in.get_empty_segment_by_sinogram(0)); + } + else + { + Array<3,float> extended = + extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; + proj_data_interpolator.set_output(extended); + } + + // now do interpolation + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + sample_function_on_regular_grid_push(sino_3D_out, proj_data_interpolator, offset, step); proj_data_out.set_segment(sino_3D_out); @@ -468,4 +607,5 @@ interpolate_projdata_test(ProjData& proj_data_out, return Succeeded::no; return Succeeded::yes; } + END_NAMESPACE_STIR diff --git a/src/include/stir/interpolate_projdata.h b/src/include/stir/interpolate_projdata.h index d3b529e2c7..db95fbb07c 100644 --- a/src/include/stir/interpolate_projdata.h +++ b/src/include/stir/interpolate_projdata.h @@ -71,7 +71,13 @@ interpolate_projdata(ProjData& proj_data_out, const bool use_view_offset = false); Succeeded -interpolate_projdata_test(ProjData& proj_data_out, +interpolate_projdata_pull(ProjData& proj_data_out, + const ProjData& proj_data_in, + const bool remove_interleaving = false, + const bool use_view_offset = false); + +Succeeded +interpolate_projdata_push(ProjData& proj_data_out, const ProjData& proj_data_in, const bool remove_interleaving = false, const bool use_view_offset = false); diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index bcea873905..63514fd721 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -59,7 +59,14 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, template inline -void sample_function_on_regular_grid_test(Array<3,elemT>& out, +void sample_function_on_regular_grid_pull(Array<3,elemT>& out, + FunctionType func, + const BasicCoordinate<3, positionT>& offset, + const BasicCoordinate<3, positionT>& step); + +template +inline +void sample_function_on_regular_grid_push(Array<3,elemT>& out, FunctionType func, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step); diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 288819f5c3..e8f5781599 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -63,7 +63,7 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, } template -void sample_function_on_regular_grid_test(Array<3,elemT>& out, +void sample_function_on_regular_grid_pull(Array<3,elemT>& out, FunctionType func, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step) @@ -100,4 +100,42 @@ void sample_function_on_regular_grid_test(Array<3,elemT>& out, } +template +void sample_function_on_regular_grid_push(Array<3,elemT>& out, + FunctionType func, + const BasicCoordinate<3, positionT>& offset, + const BasicCoordinate<3, positionT>& step) +{ + BasicCoordinate<3,int> min_out, max_out; + IndexRange<3> out_range = out.get_index_range(); + if (!out_range.get_regular_range(min_out,max_out)) + warning("Output must be regular range!"); + + BasicCoordinate<3, int> index_out; + BasicCoordinate<3, positionT> relative_positions; + index_out[1]=min_out[1]; + relative_positions[1]= index_out[1] * step[1] - offset[1] ; + const BasicCoordinate<3, positionT> max_relative_positions= + (BasicCoordinate<3,positionT>(max_out)+static_cast(.001)) * step + offset; + for (; + index_out[1]<=max_out[1] && relative_positions[1]<=max_relative_positions[1]; + ++index_out[1], relative_positions[1]+= step[1]) + { + index_out[2]=min_out[2]; + relative_positions[2]= index_out[2] * step[2] + offset[2] ; + for (; + index_out[2]<=max_out[2] && relative_positions[2]<=max_relative_positions[2]; + ++index_out[2], relative_positions[2]+= step[2]) + { + index_out[3]=min_out[3]; + relative_positions[3]= index_out[3] * step[3] + offset[3] ; + for (; + index_out[3]<=max_out[3] && relative_positions[3]<=max_relative_positions[3]; + ++index_out[3], relative_positions[3]+= step[3]) + func.add_to(relative_positions, out[index_out]); + } + } +} + + END_NAMESPACE_STIR diff --git a/src/include/stir/scatter/ScatterEstimation.h b/src/include/stir/scatter/ScatterEstimation.h index dde53d1626..f07b6d7bf1 100644 --- a/src/include/stir/scatter/ScatterEstimation.h +++ b/src/include/stir/scatter/ScatterEstimation.h @@ -100,7 +100,13 @@ class ScatterEstimation: public ParsingObject const bool remove_interleaving = true); static void - downsample_scatter_estimate(ProjData& scaled_scatter_proj_data, + pull_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const bool remove_interleaving = true); + + static void + push_scatter_estimate(ProjData& scaled_scatter_proj_data, const ProjData& emission_proj_data, const ProjData& scatter_proj_data, const bool remove_interleaving = true); diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index cac4d5e5ae..490237c523 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -150,7 +150,7 @@ upsample_scatter_estimate(ProjData& scaled_scatter_proj_data, void ScatterEstimation:: -downsample_scatter_estimate(ProjData& scaled_scatter_proj_data, +pull_scatter_estimate(ProjData& scaled_scatter_proj_data, const ProjData& emission_proj_data, const ProjData& scatter_proj_data, const bool remove_interleaving) @@ -165,7 +165,31 @@ downsample_scatter_estimate(ProjData& scaled_scatter_proj_data, interpolated_direct_scatter_proj_data_info_sptr); // interpolate projdata - interpolate_projdata_test(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); + interpolate_projdata_pull(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); + + // Perform Inverse Single Slice Rebinning + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + +} + +void +ScatterEstimation:: +push_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const bool remove_interleaving) +{ + + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + + // interpolate projdata + interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); // Perform Inverse Single Slice Rebinning inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); From b7c5179c7af8f74b9cab409198eabea6f6832ea7 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 5 Jun 2019 16:12:46 +0100 Subject: [PATCH 053/274] nearly there --- src/buildblock/interpolate_projdata.cxx | 36 +++++++++++-------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 4d3bd355c4..4871e57166 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -470,14 +470,16 @@ interpolate_projdata_pull(ProjData& proj_data_out, } Succeeded -interpolate_projdata_push(ProjData& proj_data_out, - const ProjData& proj_data_in, +interpolate_projdata_push(ProjData& proj_data_in, + const ProjData& proj_data_out, const bool remove_interleaving, const bool use_view_offset) { - + SegmentBySinogram sino_3D_out = proj_data_in.get_empty_segment_by_sinogram(0) ; PushTransposeLinearInterpolator proj_data_interpolator; + proj_data_interpolator.set_output(sino_3D_out); + if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); @@ -551,11 +553,11 @@ interpolate_projdata_push(ProjData& proj_data_out, shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); + make_non_interleaved_proj_data_info(proj_data_out_info); const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); + proj_data_out.get_segment_by_sinogram(0)); // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); Array<3,float> extended = @@ -571,15 +573,15 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - std::cerr << "MAX UP "<< extended.find_max() << '\n'; - std::cerr << "MIN UP "<< extended.find_min() << '\n'; - proj_data_interpolator.set_output(extended); - //proj_data_interpolator.set_input(proj_data_in.get_empty_segment_by_sinogram(0)); + sample_function_on_regular_grid_push(extended, proj_data_interpolator, offset, step); + proj_data_in.set_segment(sino_3D_out); + std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; + std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } else { Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) @@ -591,21 +593,15 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - std::cerr << "MAX UP "<< extended.find_max() << '\n'; - std::cerr << "MIN UP "<< extended.find_min() << '\n'; - proj_data_interpolator.set_output(extended); + sample_function_on_regular_grid_push(extended, proj_data_interpolator, offset, step); + proj_data_in.set_segment(sino_3D_out); + std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; + std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } // now do interpolation - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sample_function_on_regular_grid_push(sino_3D_out, proj_data_interpolator, offset, step); - - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - return Succeeded::yes; } END_NAMESPACE_STIR From 969280f09188afeca754bb2801a542e8d367feeb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 5 Jun 2019 17:49:53 +0100 Subject: [PATCH 054/274] input output correct order --- src/buildblock/interpolate_projdata.cxx | 52 +++++++++++++------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 4871e57166..de67529f89 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -469,16 +469,21 @@ interpolate_projdata_pull(ProjData& proj_data_out, return Succeeded::yes; } + + + Succeeded -interpolate_projdata_push(ProjData& proj_data_in, - const ProjData& proj_data_out, +interpolate_projdata_push(ProjData& proj_data_out, + const ProjData& proj_data_in, const bool remove_interleaving, const bool use_view_offset) { - SegmentBySinogram sino_3D_out = proj_data_in.get_empty_segment_by_sinogram(0) ; - PushTransposeLinearInterpolator proj_data_interpolator; - proj_data_interpolator.set_output(sino_3D_out); + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + PushTransposeLinearInterpolator proj_data_interpolator; + proj_data_interpolator.set_output(sino_3D_out); + if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); @@ -513,17 +518,17 @@ interpolate_projdata_push(ProjData& proj_data_in, const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); // offset in 'in' index units offset[1] = - (proj_data_in_info.get_m(Bin(0,0,0,0)) - - proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; + (proj_data_out_info.get_m(Bin(0,0,0,0)) - + proj_data_in_info.get_m(Bin(0,0,0,0))) / out_sampling_m; step[1]= - out_sampling_m/in_sampling_m; + in_sampling_m/out_sampling_m; - const float in_sampling_phi = - (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / + const float out_sampling_phi = + (proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0))) / (remove_interleaving ? 2 : 1); - const float out_sampling_phi = - proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); + const float in_sampling_phi = + proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0)); const float out_view_offset = use_view_offset @@ -534,17 +539,17 @@ interpolate_projdata_push(ProjData& proj_data_in, ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() : 0.F; offset[2] = - (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; + (proj_data_out_info.get_phi(Bin(0,0,0,0)) + out_view_offset - proj_data_in_info.get_phi(Bin(0,0,0,0)) - in_view_offset) / out_sampling_phi; step[2] = - out_sampling_phi/in_sampling_phi; + in_sampling_phi/out_sampling_phi; const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); offset[3] = - (proj_data_out_info.get_s(Bin(0,0,0,0)) - - proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; + (proj_data_in_info.get_s(Bin(0,0,0,0)) - + proj_data_out_info.get_s(Bin(0,0,0,0))) / out_sampling_s; step[3]= - out_sampling_s/in_sampling_s; + in_sampling_s/out_sampling_s; // initialise interpolator if (remove_interleaving) @@ -553,11 +558,11 @@ interpolate_projdata_push(ProjData& proj_data_in, shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_out_info); + make_non_interleaved_proj_data_info(proj_data_in_info); const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_out.get_segment_by_sinogram(0)); + proj_data_in.get_segment_by_sinogram(0)); // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); Array<3,float> extended = @@ -574,14 +579,14 @@ interpolate_projdata_push(ProjData& proj_data_in, } } sample_function_on_regular_grid_push(extended, proj_data_interpolator, offset, step); - proj_data_in.set_segment(sino_3D_out); + proj_data_out.set_segment(sino_3D_out); std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } else { Array<3,float> extended = - extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); + extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) @@ -594,14 +599,11 @@ interpolate_projdata_push(ProjData& proj_data_in, } } sample_function_on_regular_grid_push(extended, proj_data_interpolator, offset, step); - proj_data_in.set_segment(sino_3D_out); + proj_data_out.set_segment(sino_3D_out); std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } - // now do interpolation - - } END_NAMESPACE_STIR From b77d1275fbf84c70481e28c0b1bcea9c6aae236a Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 5 Jun 2019 17:59:33 +0100 Subject: [PATCH 055/274] push sampling correct notation --- .../stir/numerics/sampling_functions.inl | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index e8f5781599..b6f86fc5ba 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -101,38 +101,38 @@ void sample_function_on_regular_grid_pull(Array<3,elemT>& out, template -void sample_function_on_regular_grid_push(Array<3,elemT>& out, +void sample_function_on_regular_grid_push(Array<3,elemT>& in, FunctionType func, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step) { - BasicCoordinate<3,int> min_out, max_out; - IndexRange<3> out_range = out.get_index_range(); - if (!out_range.get_regular_range(min_out,max_out)) + BasicCoordinate<3,int> min_in, max_in; + IndexRange<3> in_range = in.get_index_range(); + if (!in_range.get_regular_range(min_in,max_in)) warning("Output must be regular range!"); - BasicCoordinate<3, int> index_out; + BasicCoordinate<3, int> index_in; BasicCoordinate<3, positionT> relative_positions; - index_out[1]=min_out[1]; - relative_positions[1]= index_out[1] * step[1] - offset[1] ; + index_in[1]=min_in[1]; + relative_positions[1]= index_in[1] * step[1] - offset[1] ; const BasicCoordinate<3, positionT> max_relative_positions= - (BasicCoordinate<3,positionT>(max_out)+static_cast(.001)) * step + offset; + (BasicCoordinate<3,positionT>(max_in)+static_cast(.001)) * step + offset; for (; - index_out[1]<=max_out[1] && relative_positions[1]<=max_relative_positions[1]; - ++index_out[1], relative_positions[1]+= step[1]) + index_in[1]<=max_in[1] && relative_positions[1]<=max_relative_positions[1]; + ++index_in[1], relative_positions[1]+= step[1]) { - index_out[2]=min_out[2]; - relative_positions[2]= index_out[2] * step[2] + offset[2] ; + index_in[2]=min_in[2]; + relative_positions[2]= index_in[2] * step[2] + offset[2] ; for (; - index_out[2]<=max_out[2] && relative_positions[2]<=max_relative_positions[2]; - ++index_out[2], relative_positions[2]+= step[2]) + index_in[2]<=max_in[2] && relative_positions[2]<=max_relative_positions[2]; + ++index_in[2], relative_positions[2]+= step[2]) { - index_out[3]=min_out[3]; - relative_positions[3]= index_out[3] * step[3] + offset[3] ; + index_in[3]=min_in[3]; + relative_positions[3]= index_in[3] * step[3] + offset[3] ; for (; - index_out[3]<=max_out[3] && relative_positions[3]<=max_relative_positions[3]; - ++index_out[3], relative_positions[3]+= step[3]) - func.add_to(relative_positions, out[index_out]); + index_in[3]<=max_in[3] && relative_positions[3]<=max_relative_positions[3]; + ++index_in[3], relative_positions[3]+= step[3]) + func.add_to(relative_positions, in[index_in]); } } } From 43e9e3d57f93f6c5df697f7b6de28df235b809d4 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 6 Jun 2019 15:04:21 +0100 Subject: [PATCH 056/274] solved scale issue --- src/buildblock/interpolate_projdata.cxx | 44 +++++++++---------- .../stir/numerics/sampling_functions.h | 8 ++-- .../stir/numerics/sampling_functions.inl | 18 +++++--- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index de67529f89..96a403ca5d 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -338,7 +338,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, { - PullLinearInterpolator proj_data_interpolator; + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); @@ -364,6 +364,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, + BasicCoordinate<3, double> offset, step ; // find relation between out_index and in_index such that they correspond to the same physical position @@ -405,6 +406,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, step[3]= out_sampling_s/in_sampling_s; + std::cerr << "PULL - OFFSET"<< offset[1] << "," << offset[2] << "," << offset[3] << '\n'; + std::cerr << "PULL - STEP"<< step[1] << "," << step[2] << "," << step[3] << '\n'; // initialise interpolator if (remove_interleaving) @@ -432,10 +435,11 @@ interpolate_projdata_pull(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - std::cerr << "MAX UP "<< extended.find_max() << '\n'; - std::cerr << "MIN UP "<< extended.find_min() << '\n'; - proj_data_interpolator.set_input(extended); - //proj_data_interpolator.set_input(proj_data_in.get_empty_segment_by_sinogram(0)); + + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); + proj_data_out.set_segment(sino_3D_out); + std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; + std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } else { @@ -452,20 +456,12 @@ interpolate_projdata_pull(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - std::cerr << "MAX UP "<< extended.find_max() << '\n'; - std::cerr << "MIN UP "<< extended.find_min() << '\n'; - proj_data_interpolator.set_input(extended); + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); + proj_data_out.set_segment(sino_3D_out); + std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; + std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } - // now do interpolation - - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sample_function_on_regular_grid_pull(sino_3D_out, proj_data_interpolator, offset, step); - - proj_data_out.set_segment(sino_3D_out); - - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; return Succeeded::yes; } @@ -481,9 +477,6 @@ interpolate_projdata_push(ProjData& proj_data_out, SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - PushTransposeLinearInterpolator proj_data_interpolator; - proj_data_interpolator.set_output(sino_3D_out); - if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); @@ -509,7 +502,6 @@ interpolate_projdata_push(ProjData& proj_data_out, - BasicCoordinate<3, double> offset, step ; // find relation between out_index and in_index such that they correspond to the same physical position @@ -543,14 +535,17 @@ interpolate_projdata_push(ProjData& proj_data_out, step[2] = in_sampling_phi/out_sampling_phi; - const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); offset[3] = (proj_data_in_info.get_s(Bin(0,0,0,0)) - proj_data_out_info.get_s(Bin(0,0,0,0))) / out_sampling_s; step[3]= in_sampling_s/out_sampling_s; + std::cerr << "PUSH - OFFSET"<< offset[1] << "," << offset[2] << "," << offset[3] << '\n'; + std::cerr << "PUSH - STEP"<< step[1] << "," << step[2] << "," << step[3] << '\n'; + // initialise interpolator if (remove_interleaving) @@ -578,7 +573,7 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - sample_function_on_regular_grid_push(extended, proj_data_interpolator, offset, step); + sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; @@ -598,12 +593,13 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - sample_function_on_regular_grid_push(extended, proj_data_interpolator, offset, step); + sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } + return Succeeded::yes; } END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index 63514fd721..e23e54831f 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -57,17 +57,17 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step); -template +template inline void sample_function_on_regular_grid_pull(Array<3,elemT>& out, - FunctionType func, + const Array<3,elemT>& in, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step); -template +template inline void sample_function_on_regular_grid_push(Array<3,elemT>& out, - FunctionType func, + const Array<3,elemT>& in, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step); diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index b6f86fc5ba..aee2db4de3 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -23,6 +23,7 @@ This file is part of STIR. \brief implementation of stir::sample_function_on_regular_grid */ +#include "stir_experimental/numerics/more_interpolators.h" START_NAMESPACE_STIR template @@ -62,9 +63,9 @@ void sample_function_on_regular_grid(Array<3,elemT>& out, } } -template +template void sample_function_on_regular_grid_pull(Array<3,elemT>& out, - FunctionType func, + const Array<3,elemT>& in, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step) { @@ -94,15 +95,16 @@ void sample_function_on_regular_grid_pull(Array<3,elemT>& out, for (; index_out[3]<=max_out[3] && relative_positions[3]<=max_relative_positions[3]; ++index_out[3], relative_positions[3]+= step[3]) - out[index_out] = func(relative_positions) ; + out[index_out] = pull_linear_interpolate(in, + relative_positions); } } } -template -void sample_function_on_regular_grid_push(Array<3,elemT>& in, - FunctionType func, +template +void sample_function_on_regular_grid_push(Array<3,elemT>& out, + const Array<3,elemT>& in, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step) { @@ -132,7 +134,9 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& in, for (; index_in[3]<=max_in[3] && relative_positions[3]<=max_relative_positions[3]; ++index_in[3], relative_positions[3]+= step[3]) - func.add_to(relative_positions, in[index_in]); + push_transpose_linear_interpolate(out, + relative_positions, + in[index_in]); } } } From 3a5815125fd4e81f30d4397c543601b86303594a Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 6 Jun 2019 16:12:58 +0100 Subject: [PATCH 057/274] scaling solved --- src/buildblock/interpolate_projdata.cxx | 16 ++++++---------- src/include/stir/numerics/sampling_functions.inl | 3 ++- .../numerics/more_interpolators.inl | 3 ++- .../upsample_and_fit_scatter_estimate.cxx | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 96a403ca5d..763cb20df3 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -438,8 +438,6 @@ interpolate_projdata_pull(ProjData& proj_data_out, sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); - std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; - std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; } else { @@ -458,8 +456,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, } sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); - std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; - std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; + } return Succeeded::yes; @@ -543,8 +540,8 @@ interpolate_projdata_push(ProjData& proj_data_out, step[3]= in_sampling_s/out_sampling_s; - std::cerr << "PUSH - OFFSET"<< offset[1] << "," << offset[2] << "," << offset[3] << '\n'; - std::cerr << "PUSH - STEP"<< step[1] << "," << step[2] << "," << step[3] << '\n'; + std::cerr << "PUSH - OFFSET:"<< offset[1] << "," << offset[2] << "," << offset[3] << '\n'; + std::cerr << "PUSH - STEP:"<< step[1] << "," << step[2] << "," << step[3] << '\n'; // initialise interpolator if (remove_interleaving) @@ -575,8 +572,8 @@ interpolate_projdata_push(ProjData& proj_data_out, } sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); - std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; - std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; + + } else { @@ -595,8 +592,7 @@ interpolate_projdata_push(ProjData& proj_data_out, } sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); - std::cerr << "MAX UP "<< sino_3D_out.find_max() << '\n'; - std::cerr << "MIN UP "<< sino_3D_out.find_min() << '\n'; + } return Succeeded::yes; diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index aee2db4de3..9bb751e862 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -116,7 +116,7 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, BasicCoordinate<3, int> index_in; BasicCoordinate<3, positionT> relative_positions; index_in[1]=min_in[1]; - relative_positions[1]= index_in[1] * step[1] - offset[1] ; + relative_positions[1]= index_in[1] *step[1] - offset[1] ; const BasicCoordinate<3, positionT> max_relative_positions= (BasicCoordinate<3,positionT>(max_in)+static_cast(.001)) * step + offset; for (; @@ -139,6 +139,7 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, in[index_in]); } } + out*=(step[1]*step[2]*step[3]); //very important } diff --git a/src/include/stir_experimental/numerics/more_interpolators.inl b/src/include/stir_experimental/numerics/more_interpolators.inl index 83d568c5ce..ec029229f3 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.inl +++ b/src/include/stir_experimental/numerics/more_interpolators.inl @@ -119,7 +119,7 @@ template void push_transpose_linear_interpolate(Array<3, elemT>& out, const BasicCoordinate<3, positionT>& point_in_output_coords, - valueT value) + valueT value) { if (value==0) return; @@ -129,6 +129,7 @@ push_transpose_linear_interpolate(Array<3, elemT>& out, round(std::floor(point_in_output_coords[2])), round(std::floor(point_in_output_coords[3]))); + // TODO handle boundary conditions if (left_neighbour[1] < out.get_max_index() && left_neighbour[1] > out.get_min_index() && diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 490237c523..e094ee0073 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -190,7 +190,7 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, // interpolate projdata interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); - + std::cerr << "PUSH.." << '\n'; // Perform Inverse Single Slice Rebinning inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); From 7f796867e4db7e7a955dbb905263fa450ccebdeb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 7 Jun 2019 16:52:51 +0100 Subject: [PATCH 058/274] before changing transpose --- src/buildblock/interpolate_projdata.cxx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 763cb20df3..22d4ecef23 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -438,6 +438,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; } else { @@ -456,6 +458,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, } sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; } @@ -508,7 +512,7 @@ interpolate_projdata_push(ProjData& proj_data_out, // offset in 'in' index units offset[1] = (proj_data_out_info.get_m(Bin(0,0,0,0)) - - proj_data_in_info.get_m(Bin(0,0,0,0))) / out_sampling_m; + proj_data_in_info.get_m(Bin(0,0,0,0))) / out_sampling_m; //divide by sampling: conversion from mm to voxel units step[1]= in_sampling_m/out_sampling_m; @@ -572,7 +576,8 @@ interpolate_projdata_push(ProjData& proj_data_out, } sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); - + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; } else @@ -592,6 +597,8 @@ interpolate_projdata_push(ProjData& proj_data_out, } sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; } From ff0a1bb5f5ee1ab02a1c0be4ae94f451fecd5bb6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 24 Jun 2019 10:58:51 +0100 Subject: [PATCH 059/274] push like pull --- src/buildblock/extend_projdata.cxx | 126 ++++++++++++++++++++++++ src/buildblock/interpolate_projdata.cxx | 94 ++++++++++++++++++ src/include/stir/extend_projdata.h | 8 ++ 3 files changed, 228 insertions(+) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index ccbbdcbeee..1e9bd738a5 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -123,6 +123,90 @@ namespace detail } // loop over views return input_extended_view; } + + inline static + Array<2,float> + compress_sinogram_in_views(const Array<2,float>& sino_positive_segment, + const Array<2,float>& sino_negative_segment, + const ProjDataInfo& proj_data_info, + const float min_view_extension, const float max_view_extension) + { + //* Check if projdata are from 0 to pi-phi + bool min_is_extended=false; + bool max_is_extended=false; + BasicCoordinate<2,int> min_in, max_in; + if (!sino_positive_segment.get_regular_range(min_in, max_in)) + { + warning("input segment 0 should have a regular range"); + } + + const int org_min_view_num=min_in[1]; + const int org_max_view_num=max_in[1]; + + const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); + const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); + + const float sampling_phi = + proj_data_info.get_phi(Bin(0,1,0,0)) - min_phi; + const int num_views_for_180 = round(_PI/sampling_phi); + + if (fabs(min_phi)< .01) + { + min_in[1]-=min_view_extension; + min_is_extended=true; + } + if (fabs(max_phi-(_PI-sampling_phi))<.01) + { + max_in[1]+=max_view_extension; + max_is_extended=true; + } + + + IndexRange<2> extended_range(min_in, max_in); + Array<2,float> input_extended_view(extended_range); + + if (!min_is_extended) + warning("Minimum view of the original projdata is not 0"); + if (!max_is_extended) + warning("Maximum view of the original projdata is not 180-sampling_phi"); + + for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) + { + bool use_extension=false; + int symmetric_view_num=0; + if (view_numorg_max_view_num && max_is_extended==true) + { + use_extension=true; + symmetric_view_num = view_num - num_views_for_180; + } + + if (!use_extension) + input_extended_view[view_num]= + sino_positive_segment[view_num]; + else + { + const int symmetric_min = std::max(min_in[2], -max_in[2]); + const int symmetric_max = std::min(-min_in[2], max_in[2]); + for (int tang_num=symmetric_min; tang_num<=symmetric_max; ++tang_num) + input_extended_view[view_num][tang_num]= + sino_negative_segment[symmetric_view_num][-tang_num]; + // now do extrapolation where we don't have data + for (int tang_num=min_in[2]; tang_num @@ -167,4 +251,46 @@ extend_sinogram_in_views(const Sinogram& sino, min_view_extension, max_view_extension); } +Array<3,float> +compress_segment_in_views(const SegmentBySinogram& sino, + const float min_view_extension, const float max_view_extension) +{ + if (sino.get_segment_num()!=0) + error("extend_segment with single segment works only for segment 0"); + + BasicCoordinate<3,int> min, max; + + min[1]=sino.get_min_axial_pos_num(); + max[1]=sino.get_max_axial_pos_num(); + min[2]=sino.get_min_view_num(); + max[2]=sino.get_max_view_num(); + min[3]=sino.get_min_tangential_pos_num(); + max[3]=sino.get_max_tangential_pos_num(); + const IndexRange<3> out_range(min,max); + Array<3,float> out(out_range); + for (int ax_pos_num=min[1]; ax_pos_num <=max[1] ; ++ax_pos_num) + { + out[ax_pos_num] = + detail:: + extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], + *(sino.get_proj_data_info_ptr()), + min_view_extension, max_view_extension); + } + return out; +} + +Array<2,float> +compress_sinogram_in_views(const Sinogram& sino, + const float min_view_extension, const float max_view_extension) +{ + if (sino.get_segment_num()!=0) + error("extend_segment with single segment works only for segment 0"); + + return + detail:: + compress_sinogram_in_views(sino, sino, + *(sino.get_proj_data_info_ptr()), + min_view_extension, max_view_extension); +} + END_NAMESPACE_STIR diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 22d4ecef23..73770388a1 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -72,6 +72,21 @@ namespace detail_interpolate_projdata return new_proj_data_info_sptr; } + static shared_ptr + make_compressed_proj_data_info(const ProjDataInfo& proj_data_info) + { + + // TODO: arc-correct? + if (dynamic_cast(&proj_data_info) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + shared_ptr new_proj_data_info_sptr( + proj_data_info.clone()); + new_proj_data_info_sptr-> + set_num_views(proj_data_info.get_num_views()/2); + return new_proj_data_info_sptr; + } + static void make_non_interleaved_sinogram(Sinogram& out_sinogram, const Sinogram& in_sinogram) @@ -134,6 +149,54 @@ namespace detail_interpolate_projdata } #endif + static void + make_compressed_sinogram(Sinogram& out_sinogram, + const Sinogram& in_sinogram) + { + if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + assert(out_sinogram.get_min_view_num() == 0); + assert(in_sinogram.get_min_view_num() == 0); + assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()/2); + assert(in_sinogram.get_segment_num() == 0); + assert(out_sinogram.get_segment_num() == 0); + + const int in_num_views = in_sinogram.get_num_views(); + + for (int view_num = out_sinogram.get_min_view_num(); + view_num <= out_sinogram.get_max_view_num(); + ++view_num) + { + // TODO don't put in outer tangential poss for now to avoid boundary stuff + for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; + tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; + ++tangential_pos_num) + { + if ((view_num+tangential_pos_num)%2 == 0) + { + const int in_view_num = + view_num%2==0 ? view_num/2 : (view_num+1)/2; + out_sinogram[view_num][tangential_pos_num] = + in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; + } + else + { + const int next_in_view = view_num/2+1; + const int other_in_view = (view_num+1)/2; + + out_sinogram[view_num][tangential_pos_num] = + (in_sinogram[view_num/2][tangential_pos_num] + + in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] + )/4; + } + } + } + } + + static void make_non_interleaved_segment(SegmentBySinogram& out_segment, const SegmentBySinogram& in_segment) @@ -152,6 +215,24 @@ namespace detail_interpolate_projdata } } + static void + make_compressed_segment(SegmentBySinogram& out_segment, + const SegmentBySinogram& in_segment) + { + if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + for (int axial_pos_num = out_segment.get_min_axial_pos_num(); + axial_pos_num <= out_segment.get_max_axial_pos_num(); + ++axial_pos_num) + { + Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); + make_compressed_sinogram(out_sinogram, + in_segment.get_sinogram(axial_pos_num)); + out_segment.set_sinogram(out_sinogram); + } + } + static SegmentBySinogram make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, const SegmentBySinogram& in_segment) @@ -165,6 +246,18 @@ namespace detail_interpolate_projdata return out_segment; } + static SegmentBySinogram + make_compressed_segment(const ProjDataInfo& compressed_proj_data_info, + const SegmentBySinogram& in_segment) + { + + SegmentBySinogram out_segment = + compressed_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); + + make_compressed_segment(out_segment, in_segment); + + return out_segment; + } } // end namespace detail_interpolate_projdata @@ -605,4 +698,5 @@ interpolate_projdata_push(ProjData& proj_data_out, return Succeeded::yes; } + END_NAMESPACE_STIR diff --git a/src/include/stir/extend_projdata.h b/src/include/stir/extend_projdata.h index bc5fd1b7fd..662c72e45e 100644 --- a/src/include/stir/extend_projdata.h +++ b/src/include/stir/extend_projdata.h @@ -43,6 +43,14 @@ extend_segment_in_views(const SegmentBySinogram& sino, Array<2,float> extend_sinogram_in_views(const Sinogram& sino, const int min_view_extension, const int max_view_extension); + +Array<3,float> +compress_segment_in_views(const SegmentBySinogram& sino, + const float min_view_compression, const float max_view_compression); +Array<2,float> +compress_sinogram_in_views(const Sinogram& sino, + const float min_view_compression, const float max_view_compression); + //@} END_NAMESPACE_STIR From bad44088d816118cd11d504c078c999cda3ae485 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 24 Jun 2019 11:06:37 +0100 Subject: [PATCH 060/274] read segm_in --- src/buildblock/interpolate_projdata.cxx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 73770388a1..626141cf69 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -667,7 +667,11 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); + for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) + { + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); + } proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; @@ -688,7 +692,12 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - sample_function_on_regular_grid_push(sino_3D_out,extended, offset, step); + + for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) + { + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); + } proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; From b47868beeaa48d86a1a0305ac57f32961516a44f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 24 Jun 2019 12:23:44 +0100 Subject: [PATCH 061/274] make transpose --- src/buildblock/interpolate_projdata.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 626141cf69..e7a5eb8c09 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -73,7 +73,7 @@ namespace detail_interpolate_projdata } static shared_ptr - make_compressed_proj_data_info(const ProjDataInfo& proj_data_info) + transpose_make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) { // TODO: arc-correct? @@ -150,7 +150,7 @@ namespace detail_interpolate_projdata #endif static void - make_compressed_sinogram(Sinogram& out_sinogram, + transpose_make_non_interleaved_sinogram(Sinogram& out_sinogram, const Sinogram& in_sinogram) { if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) @@ -216,7 +216,7 @@ namespace detail_interpolate_projdata } static void - make_compressed_segment(SegmentBySinogram& out_segment, + transpose_make_non_interleaved_segment(SegmentBySinogram& out_segment, const SegmentBySinogram& in_segment) { if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) @@ -227,7 +227,7 @@ namespace detail_interpolate_projdata ++axial_pos_num) { Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); - make_compressed_sinogram(out_sinogram, + transpose_make_non_interleaved_sinogram(out_sinogram, in_segment.get_sinogram(axial_pos_num)); out_segment.set_sinogram(out_sinogram); } @@ -247,14 +247,14 @@ namespace detail_interpolate_projdata } static SegmentBySinogram - make_compressed_segment(const ProjDataInfo& compressed_proj_data_info, + transpose_make_non_interleaved_segment(const ProjDataInfo& compressed_proj_data_info, const SegmentBySinogram& in_segment) { SegmentBySinogram out_segment = compressed_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); - make_compressed_segment(out_segment, in_segment); + transpose_make_non_interleaved_segment(out_segment, in_segment); return out_segment; } From f7f24d9cdec06728d7a12e2916b95fa4062bf0a8 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 24 Jun 2019 12:26:09 +0100 Subject: [PATCH 062/274] transpose interleaving --- src/buildblock/extend_projdata.cxx | 10 +++++----- src/include/stir/extend_projdata.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 1e9bd738a5..fc137d018f 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -126,7 +126,7 @@ namespace detail inline static Array<2,float> - compress_sinogram_in_views(const Array<2,float>& sino_positive_segment, + transpose_extend_sinogram_in_views(const Array<2,float>& sino_positive_segment, const Array<2,float>& sino_negative_segment, const ProjDataInfo& proj_data_info, const float min_view_extension, const float max_view_extension) @@ -252,7 +252,7 @@ extend_sinogram_in_views(const Sinogram& sino, } Array<3,float> -compress_segment_in_views(const SegmentBySinogram& sino, +transpose_extend_segment_in_views(const SegmentBySinogram& sino, const float min_view_extension, const float max_view_extension) { if (sino.get_segment_num()!=0) @@ -272,7 +272,7 @@ compress_segment_in_views(const SegmentBySinogram& sino, { out[ax_pos_num] = detail:: - extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], + transpose_extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], *(sino.get_proj_data_info_ptr()), min_view_extension, max_view_extension); } @@ -280,7 +280,7 @@ compress_segment_in_views(const SegmentBySinogram& sino, } Array<2,float> -compress_sinogram_in_views(const Sinogram& sino, +transpose_extend_sinogram_in_views(const Sinogram& sino, const float min_view_extension, const float max_view_extension) { if (sino.get_segment_num()!=0) @@ -288,7 +288,7 @@ compress_sinogram_in_views(const Sinogram& sino, return detail:: - compress_sinogram_in_views(sino, sino, + transpose_extend_sinogram_in_views(sino, sino, *(sino.get_proj_data_info_ptr()), min_view_extension, max_view_extension); } diff --git a/src/include/stir/extend_projdata.h b/src/include/stir/extend_projdata.h index 662c72e45e..e252424c7f 100644 --- a/src/include/stir/extend_projdata.h +++ b/src/include/stir/extend_projdata.h @@ -45,10 +45,10 @@ extend_sinogram_in_views(const Sinogram& sino, const int min_view_extension, const int max_view_extension); Array<3,float> -compress_segment_in_views(const SegmentBySinogram& sino, +transpose_extend_segment_in_views(const SegmentBySinogram& sino, const float min_view_compression, const float max_view_compression); Array<2,float> -compress_sinogram_in_views(const Sinogram& sino, +transpose_extend_sinogram_in_views(const Sinogram& sino, const float min_view_compression, const float max_view_compression); //@} From 52cc03e32c2a660cd1433eb9bc91d2e754c9824f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 26 Jun 2019 20:27:44 +0100 Subject: [PATCH 063/274] correct until pull transpose --- src/buildblock/extend_projdata.cxx | 72 ++++--- src/buildblock/interpolate_projdata.cxx | 89 ++++++-- src/include/stir/extend_projdata.h | 1 + .../upsample_and_fit_scatter_estimate.cxx | 2 + ...mple_and_fit_scatter_estimate.cxx.autosave | 202 ++++++++++++++++++ src/test/CMakeLists.txt | 1 + src/test/test_upsample.cxx | 126 +++++++++++ 7 files changed, 446 insertions(+), 47 deletions(-) create mode 100644 src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave create mode 100644 src/test/test_upsample.cxx diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index fc137d018f..ff16012ff3 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -41,6 +41,7 @@ namespace detail to find data in the negative segment if necessary. However, it needs testing if it would work for non-direct sinograms. */ + inline static Array<2,float> extend_sinogram_in_views(const Array<2,float>& sino_positive_segment, @@ -121,21 +122,23 @@ namespace detail input_extended_view[view_num][symmetric_max]; } } // loop over views + return input_extended_view; } + + inline static Array<2,float> - transpose_extend_sinogram_in_views(const Array<2,float>& sino_positive_segment, - const Array<2,float>& sino_negative_segment, + transpose_extend_sinogram_in_views(const Array<2,float>& sino_segment, const ProjDataInfo& proj_data_info, - const float min_view_extension, const float max_view_extension) + const float min_view_compression, const float max_view_compression) { //* Check if projdata are from 0 to pi-phi - bool min_is_extended=false; - bool max_is_extended=false; + bool min_is_compressed=false; + bool max_is_compressed=false; BasicCoordinate<2,int> min_in, max_in; - if (!sino_positive_segment.get_regular_range(min_in, max_in)) + if (!sino_segment.get_regular_range(min_in, max_in)) { warning("input segment 0 should have a regular range"); } @@ -152,59 +155,58 @@ namespace detail if (fabs(min_phi)< .01) { - min_in[1]-=min_view_extension; - min_is_extended=true; + min_in[1]-=min_view_compression; + min_is_compressed=true; } if (fabs(max_phi-(_PI-sampling_phi))<.01) { - max_in[1]+=max_view_extension; - max_is_extended=true; + max_in[1]+=max_view_compression; + max_is_compressed=true; } - IndexRange<2> extended_range(min_in, max_in); - Array<2,float> input_extended_view(extended_range); + IndexRange<2> compressed_range(min_in, max_in); + Array<2,float> input_compressed_view(compressed_range); - if (!min_is_extended) + if (!min_is_compressed) warning("Minimum view of the original projdata is not 0"); - if (!max_is_extended) + if (!max_is_compressed) warning("Maximum view of the original projdata is not 180-sampling_phi"); for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) { - bool use_extension=false; + bool use_compression=false; int symmetric_view_num=0; - if (view_numorg_max_view_num && max_is_extended==true) + else if (view_num>org_max_view_num && max_is_compressed==true) { - use_extension=true; + use_compression=true; symmetric_view_num = view_num - num_views_for_180; } - if (!use_extension) - input_extended_view[view_num]= - sino_positive_segment[view_num]; + if (!use_compression) + input_compressed_view[view_num]= + sino_segment[view_num]; else { const int symmetric_min = std::max(min_in[2], -max_in[2]); const int symmetric_max = std::min(-min_in[2], max_in[2]); for (int tang_num=symmetric_min; tang_num<=symmetric_max; ++tang_num) - input_extended_view[view_num][tang_num]= - sino_negative_segment[symmetric_view_num][-tang_num]; + input_compressed_view[view_num][tang_num]+=sino_segment[symmetric_view_num][-tang_num]; // now do extrapolation where we don't have data for (int tang_num=min_in[2]; tang_num& sino, Array<3,float> transpose_extend_segment_in_views(const SegmentBySinogram& sino, - const float min_view_extension, const float max_view_extension) + const float min_view_compression, const float max_view_compression) { if (sino.get_segment_num()!=0) error("extend_segment with single segment works only for segment 0"); @@ -272,25 +274,25 @@ transpose_extend_segment_in_views(const SegmentBySinogram& sino, { out[ax_pos_num] = detail:: - transpose_extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], + transpose_extend_sinogram_in_views(sino[ax_pos_num], *(sino.get_proj_data_info_ptr()), - min_view_extension, max_view_extension); + min_view_compression, max_view_compression); } return out; } Array<2,float> transpose_extend_sinogram_in_views(const Sinogram& sino, - const float min_view_extension, const float max_view_extension) + const float min_view_compression, const float max_view_compression) { if (sino.get_segment_num()!=0) error("extend_segment with single segment works only for segment 0"); return detail:: - transpose_extend_sinogram_in_views(sino, sino, + transpose_extend_sinogram_in_views(sino, *(sino.get_proj_data_info_ptr()), - min_view_extension, max_view_extension); + min_view_compression, max_view_compression); } END_NAMESPACE_STIR diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index e7a5eb8c09..e483607320 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -72,6 +72,20 @@ namespace detail_interpolate_projdata return new_proj_data_info_sptr; } + static shared_ptr + make_extended_proj_data_info(const ProjDataInfo& proj_data_info) + { + + if (dynamic_cast(&proj_data_info) == NULL) + error("make_extended_proj_data is only appropriate for non-arccorrected data"); + + shared_ptr new_proj_data_info_sptr( + proj_data_info.clone()); + new_proj_data_info_sptr-> + set_num_views(proj_data_info.get_num_views()*2); + return new_proj_data_info_sptr; + } + static shared_ptr transpose_make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) { @@ -215,6 +229,9 @@ namespace detail_interpolate_projdata } } + + + static void transpose_make_non_interleaved_segment(SegmentBySinogram& out_segment, const SegmentBySinogram& in_segment) @@ -549,6 +566,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } + + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) @@ -645,13 +664,13 @@ interpolate_projdata_push(ProjData& proj_data_out, { - + //we need to create an 'extended output' shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); + make_non_interleaved_proj_data_info(proj_data_out_info); const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); + proj_data_out.get_segment_by_sinogram(0)); // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); Array<3,float> extended = @@ -665,12 +684,15 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y].grow(old_min-1, old_max+1); extended[z][y][old_min-1] = extended[z][y][old_min]; extended[z][y][old_max+1] = extended[z][y][old_max]; + } } for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) { SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); - sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); + //now we need to do first the transpose of extended -> size non_interleaved_proj_data + // then we do the transpose of remove interleaving -> size projdata_out } proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) @@ -679,9 +701,13 @@ interpolate_projdata_push(ProjData& proj_data_out, } else { - Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); + + int z_dim = extended[0][0].size_all(); + int y_dim = extended[0].size_all()/z_dim; + int x_dim = extended.size_all()/(z_dim*y_dim); + std::cout<<"ext:" << x_dim << "x" << y_dim << "x" << z_dim << '\n'; + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) { @@ -693,15 +719,54 @@ interpolate_projdata_push(ProjData& proj_data_out, } } + z_dim = extended[0][0].size_all(); + y_dim = extended[0].size_all()/z_dim; + x_dim = extended.size_all()/(z_dim*y_dim); + std::cout<<"ext2222:" << x_dim << "x" << y_dim << "x" << z_dim << '\n'; + for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) { SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); - sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); - } - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; + //here the output of the push is 'extended' + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); + //create extended projdata info + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); + // std::cout<< "views" << extended_proj_data_info_sptr->get_num_views() << '\n'; + + //create SegmentBySinogram with extended + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); + + std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + + + // set the number of views correctly + extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); + + // i'm passing extended_segment_sino that is equivalent to the array 'extended' and i need to compress it + Array<3,float> out = extend_segment_in_views(extended_segment_sino,-4, -4); // here we do the tranpose : extended -> sino_out + + for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + { + for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) + { + const int old_min = out[z][y].get_min_index(); + const int old_max = out[z][y].get_max_index(); + out[z][y].grow(old_min+1, old_max-1); + out[z][y][old_min-1] = out[z][y][old_min]; + out[z][y][old_max+1] = out[z][y][old_max]; + } + } + + std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + return Succeeded::no; + + } } return Succeeded::yes; diff --git a/src/include/stir/extend_projdata.h b/src/include/stir/extend_projdata.h index e252424c7f..55f722ed2d 100644 --- a/src/include/stir/extend_projdata.h +++ b/src/include/stir/extend_projdata.h @@ -51,6 +51,7 @@ Array<2,float> transpose_extend_sinogram_in_views(const Sinogram& sino, const float min_view_compression, const float max_view_compression); + //@} END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index e094ee0073..29e59c4151 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -188,6 +188,8 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), interpolated_direct_scatter_proj_data_info_sptr); + + std::cout << "ALEX:"<< interpolated_direct_scatter.get_num_segments() << "x"<< interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_views()<< "x" << interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; // interpolate projdata interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); std::cerr << "PUSH.." << '\n'; diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave new file mode 100644 index 0000000000..8fbed19b06 --- /dev/null +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave @@ -0,0 +1,202 @@ +/* + Copyright (C) 2005 - 2011-12-31, Hammersmith Imanet Ltd + Copyright (C) 2014, University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +/*! +\file +\ingroup scatter +\brief implementation of stir::ScatterEstimationByBin::upsample_and_fit_scatter_estimate + +\author Charalampos Tsoumpas +\author Kris Thielemans +*/ + +#include "stir/ProjDataInfo.h" +#include "stir/ExamInfo.h" +#include "stir/ProjDataInMemory.h" +#include "stir/inverse_SSRB.h" +#include "stir/scale_sinograms.h" +#include "stir/scatter/ScatterEstimation.h" +#include "stir/recon_buildblock/BinNormalisation.h" +#include "stir/interpolate_projdata.h" +#include "stir/utilities.h" +#include "stir/IndexRange2D.h" +#include "stir/stream.h" +#include "stir/Succeeded.h" +#include "stir/thresholding.h" +#include "stir/is_null_ptr.h" +#include "stir/ArrayFilter1DUsingConvolution.h" +#include +#include +#include +/***********************************************************/ + +START_NAMESPACE_STIR + +void +ScatterEstimation:: +upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + BinNormalisation& scatter_normalisation, + const ProjData& weights_proj_data, + const float min_scale_factor, + const float max_scale_factor, + const unsigned half_filter_width, + BSpline::BSplineType spline_type, + const bool remove_interleaving) +{ + + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + + interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); + + + const TimeFrameDefinitions& time_frame_defs = emission_proj_data.get_exam_info_sptr()->time_frame_definitions; + + if (min_scale_factor != 1 || max_scale_factor != 1 || !scatter_normalisation.is_trivial()) + { + ProjDataInMemory interpolated_scatter(emission_proj_data.get_exam_info_sptr(), + emission_proj_data.get_proj_data_info_ptr()->create_shared_clone()); + inverse_SSRB(interpolated_scatter, interpolated_direct_scatter); + + scatter_normalisation.set_up(emission_proj_data.get_proj_data_info_ptr()->create_shared_clone()); + scatter_normalisation.undo(interpolated_scatter, + time_frame_defs.get_start_time(), time_frame_defs.get_end_time()); + Array<2,float> scale_factors; + + info("upsample_and_fit_scatter_estimate: Finding scale factors by sinogram"); + scale_factors = get_scale_factors_per_sinogram( + emission_proj_data, + interpolated_scatter, + weights_proj_data); + + std::cout << scale_factors; + threshold_lower(scale_factors.begin_all(), + scale_factors.end_all(), + min_scale_factor); + threshold_upper(scale_factors.begin_all(), + scale_factors.end_all(), + max_scale_factor); + info("upsample_and_fit_scatter_estimate: After thresholding:"); + std::cout << scale_factors; + VectorWithOffset kernel(-static_cast(half_filter_width),half_filter_width); + kernel.fill(1.F/(2*half_filter_width+1)); + ArrayFilter1DUsingConvolution lowpass_filter(kernel, BoundaryConditions::constant); + std::for_each(scale_factors.begin(), + scale_factors.end(), + lowpass_filter); + info("upsample_and_fit_scatter_estimate: After filtering:"); + std::cout << scale_factors; + info("upsample_and_fit_scatter_estimate: applying scale factors"); + if (scale_sinograms(scaled_scatter_proj_data, + interpolated_scatter, + scale_factors) != Succeeded::yes) + { + error("upsample_and_fit_scatter_estimate: writing of scaled sinograms failed"); + } + } + else // min/max_scale_factor equal to 1 + { + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + } +} + + +void +ScatterEstimation:: +upsample_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const bool remove_interleaving) +{ + stir::BSpline::BSplineType spline_type = stir::BSpline::linear; + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + + // interpolate projdata + interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); + + // Perform Inverse Single Slice Rebinning + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + +} + + + +void +ScatterEstimation:: +pull_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const bool remove_interleaving) +{ + + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + + // interpolate projdata + interpolate_projdata_pull(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); + + // Perform Inverse Single Slice Rebinning + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + +} + +void +ScatterEstimation:: +push_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const bool remove_interleaving) +{ + + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + + + //std::cout << "ALEX:"<< interpolated_direct_scatter.get_num_segments() << "x"<< interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_views()<< "x" << interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + // interpolate projdata + interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); + std::cerr << "PUSH.." << '\n'; + // Perform Inverse Single Slice Rebinning + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + +} + + +END_NAMESPACE_STIR diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index c82da59f14..b33b4f4b99 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -42,6 +42,7 @@ Set(${dir_INVOLVED_TEST_EXE_SOURCES} # the next 2 are interactive, so we don't add a test for it, but only compile them test_display test_interpolate + test_upsample ) set(buildblock_simple_tests diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx new file mode 100644 index 0000000000..cc4297d4c3 --- /dev/null +++ b/src/test/test_upsample.cxx @@ -0,0 +1,126 @@ +// +// +/*! + + \file + \ingroup test + + \author Ludovica Brusaferri + +*/ +/* + Copyright (C) 2015, University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ + +#include "stir/ProjDataInMemory.h" +#include "stir/ExamInfo.h" +#include "stir/ProjDataInfo.h" +#include "stir/Sinogram.h" +#include "stir/Viewgram.h" +#include "stir/Succeeded.h" +#include "stir/RunTests.h" +#include "stir/Scanner.h" +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/scatter/SingleScatterSimulation.h" +#include "stir/scatter/ScatterEstimation.h" + + +START_NAMESPACE_STIR + + +class UpsampleDownsampleTests: public RunTests +{ +public: + void run_tests(); +}; + +void +UpsampleDownsampleTests:: +run_tests() +{ + std::cout << "-------- Testing Upsampling and Downsampling --------\n"; + + //creating scanner shared pointer + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + + //creating proj data info + shared_ptr proj_data_info_sptr + (ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/1, 1,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ true) + ); + + //creating low resolution proj data info + shared_ptr LR_proj_data_info_sptr + (ProjDataInfo::ProjDataInfoCTI(scanner_sptr, + /*span*/1, 1,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ true) + ); + shared_ptr exam_info_sptr(new ExamInfo); + + + // construct projdata with filling to 0 + ProjDataInMemory proj_data(exam_info_sptr, proj_data_info_sptr); + { + Sinogram sinogram = proj_data.get_sinogram(0,0); + check_if_equal(sinogram.find_min(), + 0.F, + "test constructor and get_sinogram"); + } + + //std::cout << "TEST: 3D out size:"<< proj_data.get_num_segments() << "x"<< proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + + proj_data.fill(1); + + // construct projdata with filling to 5 + ProjDataInMemory proj_data_LR(exam_info_sptr, LR_proj_data_info_sptr); + { + Sinogram sinogram_LR = proj_data_LR.get_sinogram(0,0); + check_if_equal(sinogram_LR.find_min(), + 0.F, + "test constructor and get_sinogram"); + } + proj_data_LR.fill(1); + + //std::cout << "TEST: 3D LR size:"<< proj_data_LR.get_num_segments() << "x"<< proj_data_LR.get_segment_by_sinogram(0).get_num_views()<< "x" << proj_data_LR.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + + + ProjDataInMemory scaled_proj_data = proj_data; + scaled_proj_data.fill(1); + + //std::cout << "TEST: 3D scaled size:"<< scaled_proj_data.get_num_segments() << "x"<< scaled_proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + + std::cout << "-------- Testing Pull --------\n"; + ScatterEstimation::pull_scatter_estimate(scaled_proj_data,proj_data,proj_data_LR,false); + std::cout << "-------- Testing Push --------\n"; + + ProjDataInMemory scaled_proj_data_LR = proj_data_LR; + scaled_proj_data_LR.fill(1); + ScatterEstimation::push_scatter_estimate(scaled_proj_data_LR,proj_data_LR,scaled_proj_data,false); + + //std::cout << "TEST: 3D downsampled size:"<< scaled_proj_data_LR.get_num_segments() << "x"<< scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + +} + +END_NAMESPACE_STIR + + +USING_NAMESPACE_STIR + +int main() +{ + UpsampleDownsampleTests tests; + tests.run_tests(); + return tests.main_return_value(); +} From d894538444d55a7495955075ca8e4e35dd567c0e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 11:07:50 +0100 Subject: [PATCH 064/274] transpose --- src/buildblock/interpolate_projdata.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index e483607320..005cffeac9 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -744,7 +744,7 @@ interpolate_projdata_push(ProjData& proj_data_out, extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // i'm passing extended_segment_sino that is equivalent to the array 'extended' and i need to compress it - Array<3,float> out = extend_segment_in_views(extended_segment_sino,-4, -4); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,-4, -4); // here we do the tranpose : extended -> sino_out for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { From 9a2d5955aae89db9bf4c11cf5a723fea787745b4 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 11:10:31 +0100 Subject: [PATCH 065/274] test --- src/buildblock/interpolate_projdata.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 005cffeac9..9a750ca495 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -707,7 +707,7 @@ interpolate_projdata_push(ProjData& proj_data_out, int y_dim = extended[0].size_all()/z_dim; int x_dim = extended.size_all()/(z_dim*y_dim); std::cout<<"ext:" << x_dim << "x" << y_dim << "x" << z_dim << '\n'; - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + /* for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) { @@ -717,7 +717,7 @@ interpolate_projdata_push(ProjData& proj_data_out, extended[z][y][old_min-1] = extended[z][y][old_min]; extended[z][y][old_max+1] = extended[z][y][old_max]; } - } + }*/ z_dim = extended[0][0].size_all(); y_dim = extended[0].size_all()/z_dim; @@ -746,7 +746,7 @@ interpolate_projdata_push(ProjData& proj_data_out, // i'm passing extended_segment_sino that is equivalent to the array 'extended' and i need to compress it Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,-4, -4); // here we do the tranpose : extended -> sino_out - for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + /*for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) { @@ -756,7 +756,7 @@ interpolate_projdata_push(ProjData& proj_data_out, out[z][y][old_min-1] = out[z][y][old_min]; out[z][y][old_max+1] = out[z][y][old_max]; } - } + }*/ std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; From 4b5724f5bbf0cec36c08154aa47a616ee5ed4cb3 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 13:14:30 +0100 Subject: [PATCH 066/274] ok --- src/buildblock/extend_projdata.cxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index ff16012ff3..f87fcf2f13 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -70,12 +70,12 @@ namespace detail if (fabs(min_phi)< .01) { - min_in[1]-=min_view_extension; + min_in[1]-=min_view_extension; //here the new min is lower than the original min_is_extended=true; } if (fabs(max_phi-(_PI-sampling_phi))<.01) { - max_in[1]+=max_view_extension; + max_in[1]+=max_view_extension; //here the new max is bigger than the original max_is_extended=true; } @@ -92,13 +92,15 @@ namespace detail { bool use_extension=false; int symmetric_view_num=0; - if (view_numorg_max_view_num && max_is_extended==true) + else if (view_num>org_max_view_num && max_is_extended==true) //if view number is bigger than the old maximum (right hand side?) it's been extended { + std::cout << "view_num>org_max_view_num " << '\n'; use_extension=true; symmetric_view_num = view_num - num_views_for_180; } From b708abbb2e869a1e7f61d5a70ad12b38dd8dfceb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 13:33:25 +0100 Subject: [PATCH 067/274] +4 --- src/buildblock/extend_projdata.cxx | 4 ++-- src/buildblock/interpolate_projdata.cxx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index f87fcf2f13..4fc2f81795 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -157,12 +157,12 @@ namespace detail if (fabs(min_phi)< .01) { - min_in[1]-=min_view_compression; + min_in[1]+=min_view_compression; //increase the min min_is_compressed=true; } if (fabs(max_phi-(_PI-sampling_phi))<.01) { - max_in[1]+=max_view_compression; + max_in[1]-=max_view_compression; //reduce the max max_is_compressed=true; } diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 9a750ca495..365a52ebd5 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -744,7 +744,7 @@ interpolate_projdata_push(ProjData& proj_data_out, extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // i'm passing extended_segment_sino that is equivalent to the array 'extended' and i need to compress it - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,-4, -4); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,4, 4); // here we do the tranpose : extended -> sino_out /*for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { From 2e865173acbd7c3595567e80b092104f248f0af9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 13:44:58 +0100 Subject: [PATCH 068/274] before change --- src/buildblock/extend_projdata.cxx | 6 +++++- src/buildblock/interpolate_projdata.cxx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 4fc2f81795..a456b7778d 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -148,6 +148,8 @@ namespace detail const int org_min_view_num=min_in[1]; const int org_max_view_num=max_in[1]; + IndexRange<2> original_range(min_in, max_in); + std::cerr << "MIN and MAX:"<< min_in[1] <<","<< max_in[1] << '\n'; const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); @@ -160,14 +162,16 @@ namespace detail min_in[1]+=min_view_compression; //increase the min min_is_compressed=true; } - if (fabs(max_phi-(_PI-sampling_phi))<.01) + if (fabs(max_phi)>.01) { max_in[1]-=max_view_compression; //reduce the max max_is_compressed=true; } + std::cerr << "MIN2 and MAX2:"<< min_in[1] <<","<< max_in[1] << '\n'; IndexRange<2> compressed_range(min_in, max_in); + Array<2,float> input_compressed_view(compressed_range); if (!min_is_compressed) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 365a52ebd5..b70d133c30 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -744,7 +744,7 @@ interpolate_projdata_push(ProjData& proj_data_out, extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // i'm passing extended_segment_sino that is equivalent to the array 'extended' and i need to compress it - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,4, 4); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2, 2); // here we do the tranpose : extended -> sino_out /*for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { From ce9c957358b7c047c9e21786ad9fd372673d20c7 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 14:25:31 +0100 Subject: [PATCH 069/274] lower but sym --- src/buildblock/extend_projdata.cxx | 65 ++++++++++++------------- src/buildblock/interpolate_projdata.cxx | 2 +- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index a456b7778d..4818ac08a5 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -94,13 +94,13 @@ namespace detail int symmetric_view_num=0; if (view_numorg_max_view_num && max_is_extended==true) //if view number is bigger than the old maximum (right hand side?) it's been extended { - std::cout << "view_num>org_max_view_num " << '\n'; + // std::cout << "view_num>org_max_view_num " << '\n'; use_extension=true; symmetric_view_num = view_num - num_views_for_180; } @@ -137,8 +137,8 @@ namespace detail const float min_view_compression, const float max_view_compression) { //* Check if projdata are from 0 to pi-phi - bool min_is_compressed=false; - bool max_is_compressed=false; + bool min_is_extended=false; + bool max_is_extended=false; BasicCoordinate<2,int> min_in, max_in; if (!sino_segment.get_regular_range(min_in, max_in)) { @@ -148,8 +148,6 @@ namespace detail const int org_min_view_num=min_in[1]; const int org_max_view_num=max_in[1]; - IndexRange<2> original_range(min_in, max_in); - std::cerr << "MIN and MAX:"<< min_in[1] <<","<< max_in[1] << '\n'; const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); @@ -159,64 +157,65 @@ namespace detail if (fabs(min_phi)< .01) { - min_in[1]+=min_view_compression; //increase the min - min_is_compressed=true; + min_in[1]+=min_view_compression; //here the new min is bigger than the original + min_is_extended=true; } - if (fabs(max_phi)>.01) + //if (fabs(max_phi-(_PI-sampling_phi))<.01) { - max_in[1]-=max_view_compression; //reduce the max - max_is_compressed=true; + max_in[1]-=max_view_compression; //here the new max is smaller than the original + max_is_extended=true; } - std::cerr << "MIN2 and MAX2:"<< min_in[1] <<","<< max_in[1] << '\n'; IndexRange<2> compressed_range(min_in, max_in); - Array<2,float> input_compressed_view(compressed_range); - if (!min_is_compressed) - warning("Minimum view of the original projdata is not 0"); - if (!max_is_compressed) - warning("Maximum view of the original projdata is not 180-sampling_phi"); + // if (!min_is_extended) + // warning("Minimum view of the original projdata is not 0"); + // if (!max_is_extended) + // warning("Maximum view of the original projdata is not 180-sampling_phi"); for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) { - bool use_compression=false; - int symmetric_view_num=0; - if (view_numorg_max_view_num && max_is_compressed==true) + else if (view_num>org_max_view_num && max_is_extended==true) //if view number is bigger than the old maximum (right hand side?) it's been extended { - use_compression=true; + std::cout << "view_num>org_max_view_num " << '\n'; + use_extension=true; symmetric_view_num = view_num - num_views_for_180; - } + }*/ - if (!use_compression) - input_compressed_view[view_num]= - sino_segment[view_num]; - else + // if (!use_extension) + // input_extended_view[view_num]= + // sino_positive_segment[view_num]; + //else { const int symmetric_min = std::max(min_in[2], -max_in[2]); const int symmetric_max = std::min(-min_in[2], max_in[2]); for (int tang_num=symmetric_min; tang_num<=symmetric_max; ++tang_num) - input_compressed_view[view_num][tang_num]+=sino_segment[symmetric_view_num][-tang_num]; + input_compressed_view[view_num][tang_num]= + sino_segment[symmetric_view_num][-tang_num]; // now do extrapolation where we don't have data for (int tang_num=min_in[2]; tang_num extend_segment_in_views(const SegmentBySinogram& sino, const int min_view_extension, const int max_view_extension) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index b70d133c30..9b211875c3 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -744,7 +744,7 @@ interpolate_projdata_push(ProjData& proj_data_out, extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // i'm passing extended_segment_sino that is equivalent to the array 'extended' and i need to compress it - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2, 2); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out /*for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { From af2232885104321db6a4276664f54165261d7a93 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 17:44:52 +0100 Subject: [PATCH 070/274] ok --- src/buildblock/extend_projdata.cxx | 58 ++----------------------- src/buildblock/interpolate_projdata.cxx | 52 ++++++++-------------- 2 files changed, 20 insertions(+), 90 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 4818ac08a5..f0595b8091 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -148,68 +148,16 @@ namespace detail const int org_min_view_num=min_in[1]; const int org_max_view_num=max_in[1]; - const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); - const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); - - const float sampling_phi = - proj_data_info.get_phi(Bin(0,1,0,0)) - min_phi; - const int num_views_for_180 = round(_PI/sampling_phi); - - if (fabs(min_phi)< .01) - { - min_in[1]+=min_view_compression; //here the new min is bigger than the original - min_is_extended=true; - } - //if (fabs(max_phi-(_PI-sampling_phi))<.01) - { - max_in[1]-=max_view_compression; //here the new max is smaller than the original - max_is_extended=true; - } - + min_in[1]+=min_view_compression; //here the new min is bigger than the original + max_in[1]-=max_view_compression; //here the new max is smaller than the original IndexRange<2> compressed_range(min_in, max_in); Array<2,float> input_compressed_view(compressed_range); - // if (!min_is_extended) - // warning("Minimum view of the original projdata is not 0"); - // if (!max_is_extended) - // warning("Maximum view of the original projdata is not 180-sampling_phi"); - for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) { - bool use_extension=false; - int symmetric_view_num=view_num; - /*if (view_numorg_max_view_num && max_is_extended==true) //if view number is bigger than the old maximum (right hand side?) it's been extended - { - std::cout << "view_num>org_max_view_num " << '\n'; - use_extension=true; - symmetric_view_num = view_num - num_views_for_180; - }*/ + input_compressed_view[view_num]=sino_segment[view_num]; //here we cut everything bigger than max_in and smaller than min_in - // if (!use_extension) - // input_extended_view[view_num]= - // sino_positive_segment[view_num]; - //else - { - const int symmetric_min = std::max(min_in[2], -max_in[2]); - const int symmetric_max = std::min(-min_in[2], max_in[2]); - for (int tang_num=symmetric_min; tang_num<=symmetric_max; ++tang_num) - input_compressed_view[view_num][tang_num]= - sino_segment[symmetric_view_num][-tang_num]; - // now do extrapolation where we don't have data - for (int tang_num=min_in[2]; tang_num sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - //here the output of the push is 'extended' - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); - //create extended projdata info - shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); - // std::cout<< "views" << extended_proj_data_info_sptr->get_num_views() << '\n'; - - //create SegmentBySinogram with extended - SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); - std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views - - // set the number of views correctly - extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); - - // i'm passing extended_segment_sino that is equivalent to the array 'extended' and i need to compress it Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - /*for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) { const int old_min = out[z][y].get_min_index(); const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); - out[z][y][old_min-1] = out[z][y][old_min]; - out[z][y][old_max+1] = out[z][y][old_max]; + out[z][y].grow(old_min+1, old_max-1); //resize } - }*/ - - std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + } - SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) return Succeeded::no; } From df90ec3cbbaaf69f508bbd345480c36fb12175ed Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 19:05:30 +0100 Subject: [PATCH 071/274] checked offset --- src/buildblock/interpolate_projdata.cxx | 4 ++-- src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index df94cc8985..6b1bee1fde 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -643,7 +643,7 @@ interpolate_projdata_push(ProjData& proj_data_out, : 0.F; offset[2] = (proj_data_out_info.get_phi(Bin(0,0,0,0)) + out_view_offset - proj_data_in_info.get_phi(Bin(0,0,0,0)) - in_view_offset) / out_sampling_phi; - offset[2]+=-0.5; + step[2] = in_sampling_phi/out_sampling_phi; @@ -724,7 +724,7 @@ interpolate_projdata_push(ProjData& proj_data_out, sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - + // extended[0]=extended[1]; SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 29e59c4151..8fbed19b06 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -189,7 +189,7 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, interpolated_direct_scatter_proj_data_info_sptr); - std::cout << "ALEX:"<< interpolated_direct_scatter.get_num_segments() << "x"<< interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_views()<< "x" << interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + //std::cout << "ALEX:"<< interpolated_direct_scatter.get_num_segments() << "x"<< interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_views()<< "x" << interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; // interpolate projdata interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); std::cerr << "PUSH.." << '\n'; From d39f5b8386df7bb1293fb80e02c05e62a470e797 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 19:20:47 +0100 Subject: [PATCH 072/274] ok --- src/buildblock/extend_projdata.cxx | 2 ++ src/buildblock/interpolate_projdata.cxx | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index f0595b8091..ed6af0f901 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -157,6 +157,7 @@ namespace detail for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) { input_compressed_view[view_num]=sino_segment[view_num]; //here we cut everything bigger than max_in and smaller than min_in + input_compressed_view[min_in[1]]=input_compressed_view[min_in[1]+1]; } // loop over views @@ -188,6 +189,7 @@ extend_segment_in_views(const SegmentBySinogram& sino, extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], *(sino.get_proj_data_info_ptr()), min_view_extension, max_view_extension); + out[min[1]]=out[min[1]+1]; } return out; } diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 6b1bee1fde..895c6ec983 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -726,6 +726,8 @@ interpolate_projdata_push(ProjData& proj_data_out, // extended[0]=extended[1]; SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + + std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views @@ -741,6 +743,7 @@ interpolate_projdata_push(ProjData& proj_data_out, } } + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; From aab2bbdfa054476e68121c244a8adb99b9cdddfc Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 20:11:03 +0100 Subject: [PATCH 073/274] ok before interleaving --- src/buildblock/extend_projdata.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index ed6af0f901..0275174161 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -189,7 +189,7 @@ extend_segment_in_views(const SegmentBySinogram& sino, extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], *(sino.get_proj_data_info_ptr()), min_view_extension, max_view_extension); - out[min[1]]=out[min[1]+1]; + //out[min[1]]=out[min[1]+1]; } return out; } From 6715ad37da6130ea5f3c348a3719ff83d1b955f6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 20:27:40 +0100 Subject: [PATCH 074/274] comments --- src/buildblock/interpolate_projdata.cxx | 117 ++++++++++++++---------- 1 file changed, 71 insertions(+), 46 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 895c6ec983..989a57243a 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -660,6 +660,7 @@ interpolate_projdata_push(ProjData& proj_data_out, if (remove_interleaving) { + //=============== if remove interleaving ================== //we need to create an 'extended output' shared_ptr non_interleaved_proj_data_info_sptr = @@ -678,24 +679,50 @@ interpolate_projdata_push(ProjData& proj_data_out, { const int old_min = extended[z][y].get_min_index(); const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); + extended[z][y].grow(old_min-1, old_max+1); //increase tangential positions extended[z][y][old_min-1] = extended[z][y][old_min]; extended[z][y][old_max+1] = extended[z][y][old_max]; } } - for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) - { - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); - //now we need to do first the transpose of extended -> size non_interleaved_proj_data - // then we do the transpose of remove interleaving -> size projdata_out - } - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - } + + std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; + + for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) + { + // ========================= PUSH ============================// + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + + // ========================= TRANSPOSE: EXTENDED ============================// + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + + for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + { + for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) + { + const int old_min = out[z][y].get_min_index(); + const int old_max = out[z][y].get_max_index(); + out[z][y].grow(old_min+1, old_max-1); //reduce tangential positions + } + } + + // ========================= CREATE OUTPUT SEGMENTBYSINO ============================// + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + // ========================= SET OUTPUT ============================// + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + return Succeeded::no; + + } + //=============== end if remove interleaving ================== else { Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); @@ -710,7 +737,7 @@ interpolate_projdata_push(ProjData& proj_data_out, { const int old_min = extended[z][y].get_min_index(); const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); + extended[z][y].grow(old_min-1, old_max+1); //increase tangential positions extended[z][y][old_min-1] = extended[z][y][old_min]; extended[z][y][old_max+1] = extended[z][y][old_max]; } @@ -718,41 +745,39 @@ interpolate_projdata_push(ProjData& proj_data_out, std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; - for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) - { - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - - // extended[0]=extended[1]; - SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - - - std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views - - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - - for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) - { - for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) - { - const int old_min = out[z][y].get_min_index(); - const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); //resize - } - } - - - SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) - return Succeeded::no; + for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) + { + // ========================= PUSH ============================// + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + + // ========================= TRANSPOSE: EXTENDED ============================// + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + + for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + { + for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) + { + const int old_min = out[z][y].get_min_index(); + const int old_max = out[z][y].get_max_index(); + out[z][y].grow(old_min+1, old_max-1); //reduce tangential positions + } + } + + // ========================= CREATE OUTPUT SEGMENTBYSINO ============================// + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + // ========================= SET OUTPUT ============================// + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + return Succeeded::no; } - } return Succeeded::yes; } From f3835103fa8e6a74adace01492bbebc10ee6b6eb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 20:42:23 +0100 Subject: [PATCH 075/274] Revert "ok before interleaving" This reverts commit aab2bbdfa054476e68121c244a8adb99b9cdddfc. --- src/buildblock/extend_projdata.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 0275174161..ed6af0f901 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -189,7 +189,7 @@ extend_segment_in_views(const SegmentBySinogram& sino, extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], *(sino.get_proj_data_info_ptr()), min_view_extension, max_view_extension); - //out[min[1]]=out[min[1]+1]; + out[min[1]]=out[min[1]+1]; } return out; } From f316acc581a88552bbb84a35997ef539dd06f0b7 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 20:48:22 +0100 Subject: [PATCH 076/274] test --- src/buildblock/interpolate_projdata.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 989a57243a..2d790d3108 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -778,7 +778,8 @@ interpolate_projdata_push(ProjData& proj_data_out, return Succeeded::no; } - +//'' + } return Succeeded::yes; } From 71729a8c9d7faebb185a1959b241bf5c7acc8b06 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 20:53:41 +0100 Subject: [PATCH 077/274] commented ok --- src/buildblock/interpolate_projdata.cxx | 101 ++++++++++++------------ 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 2d790d3108..af8129dad1 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -577,8 +577,6 @@ interpolate_projdata_pull(ProjData& proj_data_out, } - - Succeeded interpolate_projdata_push(ProjData& proj_data_out, const ProjData& proj_data_in, @@ -660,7 +658,6 @@ interpolate_projdata_push(ProjData& proj_data_out, if (remove_interleaving) { - //=============== if remove interleaving ================== //we need to create an 'extended output' shared_ptr non_interleaved_proj_data_info_sptr = @@ -679,23 +676,33 @@ interpolate_projdata_push(ProjData& proj_data_out, { const int old_min = extended[z][y].get_min_index(); const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); //increase tangential positions + extended[z][y].grow(old_min-1, old_max+1); extended[z][y][old_min-1] = extended[z][y][old_min]; extended[z][y][old_max+1] = extended[z][y][old_max]; } } + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } - std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; - + //std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) { - // ========================= PUSH ============================// SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + // =================== PUSH ===================== sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - // ========================= TRANSPOSE: EXTENDED ============================// + // =================== TRANSPOSE EXTENDED ===================== shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; @@ -708,21 +715,20 @@ interpolate_projdata_push(ProjData& proj_data_out, { const int old_min = out[z][y].get_min_index(); const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); //reduce tangential positions + out[z][y].grow(old_min+1, old_max-1); //resize } } - // ========================= CREATE OUTPUT SEGMENTBYSINO ============================// + // =================== CREATE OUTPUT ===================== SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - // ========================= SET OUTPUT ============================// proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) return Succeeded::no; - } - //=============== end if remove interleaving ================== + } + } else { Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); @@ -737,51 +743,48 @@ interpolate_projdata_push(ProjData& proj_data_out, { const int old_min = extended[z][y].get_min_index(); const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); //increase tangential positions + extended[z][y].grow(old_min-1, old_max+1); extended[z][y][old_min-1] = extended[z][y][old_min]; extended[z][y][old_max+1] = extended[z][y][old_max]; } } - std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; - - for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) - { - // ========================= PUSH ============================// - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - - // ========================= TRANSPOSE: EXTENDED ============================// - shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - - for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) - { - for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) - { - const int old_min = out[z][y].get_min_index(); - const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); //reduce tangential positions - } - } - - // ========================= CREATE OUTPUT SEGMENTBYSINO ============================// - SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - // ========================= SET OUTPUT ============================// - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) - return Succeeded::no; + std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; + for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) + { + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + // =================== PUSH ===================== + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + + // =================== TRANSPOSE EXTENDED ===================== + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + + for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + { + for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) + { + const int old_min = out[z][y].get_min_index(); + const int old_max = out[z][y].get_max_index(); + out[z][y].grow(old_min+1, old_max-1); //resize + } + } + + // =================== CREATE OUTPUT ===================== + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + return Succeeded::no; } -//'' } + return Succeeded::yes; } - END_NAMESPACE_STIR From 361fd1c3f97d11460a947cab2dddd2e539705aa9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 21:14:35 +0100 Subject: [PATCH 078/274] clean --- src/buildblock/interpolate_projdata.cxx | 65 ++++++++++--------------- 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index af8129dad1..657bbb1f65 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -668,8 +668,8 @@ interpolate_projdata_push(ProjData& proj_data_out, proj_data_out.get_segment_by_sinogram(0)); // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - Array<3,float> extended = - extend_segment_in_views(non_interleaved_segment, 2, 2); + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) @@ -683,32 +683,20 @@ interpolate_projdata_push(ProjData& proj_data_out, } } - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - //std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; - for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) - { - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); - // =================== PUSH ===================== + // for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) + // { + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); + // =================== PUSH ================================== sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED ===================== shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - + std::cout<<"OUT - AFTER COMPRESSION:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) @@ -719,24 +707,24 @@ interpolate_projdata_push(ProjData& proj_data_out, } } - // =================== CREATE OUTPUT ===================== + // =================== TRANSPOSE REMOVE INTERLEAVING ======= + + + // =================== CREATE OUTPUT ======================= SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) return Succeeded::no; - } + // } } else { + // ================== this is without remove interleaving ====== Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); - - int z_dim = extended[0][0].size_all(); - int y_dim = extended[0].size_all()/z_dim; - int x_dim = extended.size_all()/(z_dim*y_dim); - std::cout<<"ext:" << x_dim << "x" << y_dim << "x" << z_dim << '\n'; + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) @@ -749,20 +737,21 @@ interpolate_projdata_push(ProjData& proj_data_out, } } - std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; - for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) - { - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(segm_num); + //for(int segm_num = proj_data_in.get_min_segment_num(); segm_num < proj_data_in.get_max_segment_num(); ++segm_num) + //{ + + //std::cout<<"segm num :" << proj_data_in.get_max_segment_num() << '\n'; + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); // =================== PUSH ===================== sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED ===================== shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"ext before compress:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - + std::cout<<"OUT - AFTER COMPRESSION:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) @@ -775,14 +764,14 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== CREATE OUTPUT ===================== SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"compressed output:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"correct output:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) return Succeeded::no; } - } + //} return Succeeded::yes; } From 089a7f5f04b766b58cc7380d10fd2b61c8df7f4d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 21:16:59 +0100 Subject: [PATCH 079/274] okokok --- src/buildblock/interpolate_projdata.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 657bbb1f65..bc10bd9308 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -696,7 +696,7 @@ interpolate_projdata_push(ProjData& proj_data_out, std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - AFTER COMPRESSION:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) @@ -706,7 +706,7 @@ interpolate_projdata_push(ProjData& proj_data_out, out[z][y].grow(old_min+1, old_max-1); //resize } } - + std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================== TRANSPOSE REMOVE INTERLEAVING ======= @@ -751,7 +751,7 @@ interpolate_projdata_push(ProjData& proj_data_out, std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - AFTER COMPRESSION:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) @@ -761,7 +761,7 @@ interpolate_projdata_push(ProjData& proj_data_out, out[z][y].grow(old_min+1, old_max-1); //resize } } - + std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================== CREATE OUTPUT ===================== SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; From e0019458aeea78c2b56104bd126371293d97bc6d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 23:41:10 +0100 Subject: [PATCH 080/274] okokok --- .../interpolate_projdata.cxx.autosave | 779 ++++++++++++++++++ 1 file changed, 779 insertions(+) create mode 100644 src/buildblock/interpolate_projdata.cxx.autosave diff --git a/src/buildblock/interpolate_projdata.cxx.autosave b/src/buildblock/interpolate_projdata.cxx.autosave new file mode 100644 index 0000000000..055117c0b8 --- /dev/null +++ b/src/buildblock/interpolate_projdata.cxx.autosave @@ -0,0 +1,779 @@ +// +// +/* + Copyright (C) 2005 - 2009-10-27, Hammersmith Imanet Ltd + Copyright (C) 2011-07-01 - 2011, Kris Thielemans + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +/*! + \file + \ingroup projdata + \brief Perform B-Splines Interpolation of sinograms + + \author Charalampos Tsoumpas + \author Kris Thielemans + +*/ +#include "stir/ProjData.h" +//#include "stir/display.h" +#include "stir/ProjDataInfo.h" +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/IndexRange.h" +#include "stir/BasicCoordinate.h" +#include "stir/Sinogram.h" +#include "stir/SegmentBySinogram.h" +#include "stir/Succeeded.h" +#include "stir/numerics/BSplines.h" +#include "stir/numerics/BSplinesRegularGrid.h" +#include "stir/interpolate_projdata.h" +#include "stir/extend_projdata.h" +#include "stir/numerics/sampling_functions.h" +#include "stir_experimental/motion/Transform3DObjectImageProcessor.h" +#include "stir_experimental/motion/transform_3d_object.h" +#include "stir_experimental/numerics/more_interpolators.h" +#include + +START_NAMESPACE_STIR + +namespace detail_interpolate_projdata +{ + /* Collection of functions to remove interleaving in non-arccorrected data. + + It does this by doubling the number of views, and filling in the new + tangential positions by averaging the 4 neighbouring bins. + + WARNING: most of STIR will get confused by the resulting sinograms, + so only use them here for the interpolate_projdata implementation. + */ + + static shared_ptr + make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) + { + + if (dynamic_cast(&proj_data_info) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + shared_ptr new_proj_data_info_sptr( + proj_data_info.clone()); + new_proj_data_info_sptr-> + set_num_views(proj_data_info.get_num_views()*2); + return new_proj_data_info_sptr; + } + + static shared_ptr + make_extended_proj_data_info(const ProjDataInfo& proj_data_info) + { + + if (dynamic_cast(&proj_data_info) == NULL) + error("make_extended_proj_data is only appropriate for non-arccorrected data"); + + shared_ptr new_proj_data_info_sptr( + proj_data_info.clone()); + new_proj_data_info_sptr-> + set_num_views(proj_data_info.get_num_views()*2); + return new_proj_data_info_sptr; + } + + static shared_ptr + transpose_make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) + { + + // TODO: arc-correct? + if (dynamic_cast(&proj_data_info) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + shared_ptr new_proj_data_info_sptr( + proj_data_info.clone()); + new_proj_data_info_sptr-> + set_num_views(proj_data_info.get_num_views()/2); + return new_proj_data_info_sptr; + } + + static void + make_non_interleaved_sinogram(Sinogram& out_sinogram, + const Sinogram& in_sinogram) + { + if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + assert(out_sinogram.get_min_view_num() == 0); + assert(in_sinogram.get_min_view_num() == 0); + assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()*2); + assert(in_sinogram.get_segment_num() == 0); + assert(out_sinogram.get_segment_num() == 0); + + const int in_num_views = in_sinogram.get_num_views(); + + for (int view_num = out_sinogram.get_min_view_num(); + view_num <= out_sinogram.get_max_view_num(); + ++view_num) + { + // TODO don't put in outer tangential poss for now to avoid boundary stuff + for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; + tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; + ++tangential_pos_num) + { + if ((view_num+tangential_pos_num)%2 == 0) + { + const int in_view_num = + view_num%2==0 ? view_num/2 : (view_num+1)/2; + out_sinogram[view_num][tangential_pos_num] = + in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; + } + else + { + const int next_in_view = view_num/2+1; + const int other_in_view = (view_num+1)/2; + + out_sinogram[view_num][tangential_pos_num] = + (in_sinogram[view_num/2][tangential_pos_num] + + in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] + )/4; + } + } + } + } + +#if 0 + // not needed for now + static Sinogram + make_non_interleaved_sinogram(const ProjDataInfo& non_interleaved_proj_data_info, + const Sinogram& in_sinogram) + { + Sinogram out_sinogram = + non_interleaved_proj_data_info.get_empty_sinogram(in_sinogram.get_axial_pos_num(), + in_sinogram.get_segment_num()); + + make_non_interleaved_sinogram(out_sinogram, in_sinogram); + return out_sinogram; + } +#endif + + static void + transpose_make_non_interleaved_sinogram(Sinogram& out_sinogram, + const Sinogram& in_sinogram) + { + if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + assert(out_sinogram.get_min_view_num() == 0); + assert(in_sinogram.get_min_view_num() == 0); + assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()/2); + assert(in_sinogram.get_segment_num() == 0); + assert(out_sinogram.get_segment_num() == 0); + + const int in_num_views = in_sinogram.get_num_views(); + + for (int view_num = out_sinogram.get_min_view_num(); + view_num <= out_sinogram.get_max_view_num(); + ++view_num) + { + // TODO don't put in outer tangential poss for now to avoid boundary stuff + for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; + tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; + ++tangential_pos_num) + { + if ((view_num+tangential_pos_num)%2 == 0) + { + const int in_view_num = + view_num%2==0 ? view_num/2 : (view_num+1)/2; + out_sinogram[view_num][tangential_pos_num] = + in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; + } + else + { + const int next_in_view = view_num/2+1; + const int other_in_view = (view_num+1)/2; + + out_sinogram[view_num][tangential_pos_num] = + (in_sinogram[view_num/2][tangential_pos_num] + + in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] + )/4; + } + } + } + } + + + static void + make_non_interleaved_segment(SegmentBySinogram& out_segment, + const SegmentBySinogram& in_segment) + { + if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + for (int axial_pos_num = out_segment.get_min_axial_pos_num(); + axial_pos_num <= out_segment.get_max_axial_pos_num(); + ++axial_pos_num) + { + Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); + make_non_interleaved_sinogram(out_sinogram, + in_segment.get_sinogram(axial_pos_num)); + out_segment.set_sinogram(out_sinogram); + } + } + + + + + static void + transpose_make_non_interleaved_segment(SegmentBySinogram& out_segment, + const SegmentBySinogram& in_segment) + { + if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) + error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + + for (int axial_pos_num = out_segment.get_min_axial_pos_num(); + axial_pos_num <= out_segment.get_max_axial_pos_num(); + ++axial_pos_num) + { + Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); + transpose_make_non_interleaved_sinogram(out_sinogram, + in_segment.get_sinogram(axial_pos_num)); + out_segment.set_sinogram(out_sinogram); + } + } + + static SegmentBySinogram + make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, + const SegmentBySinogram& in_segment) + { + + SegmentBySinogram out_segment = + non_interleaved_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); + + make_non_interleaved_segment(out_segment, in_segment); + + return out_segment; + } + + static SegmentBySinogram + transpose_make_non_interleaved_segment(const ProjDataInfo& compressed_proj_data_info, + const SegmentBySinogram& in_segment) + { + + SegmentBySinogram out_segment = + compressed_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); + + transpose_make_non_interleaved_segment(out_segment, in_segment); + + return out_segment; + } +} // end namespace detail_interpolate_projdata + + +using namespace detail_interpolate_projdata; + +Succeeded +interpolate_projdata(ProjData& proj_data_out, + const ProjData& proj_data_in, const BSpline::BSplineType these_types, + const bool remove_interleaving, + const bool use_view_offset) +{ + + BasicCoordinate<3, BSpline::BSplineType> these_types_3; + + these_types_3[1]=these_types_3[2]=these_types_3[3]=these_types; + + interpolate_projdata(proj_data_out,proj_data_in,these_types_3, remove_interleaving, use_view_offset); + + + return Succeeded::yes; +} + +Succeeded +interpolate_projdata(ProjData& proj_data_out, + const ProjData& proj_data_in, + const BasicCoordinate<3, BSpline::BSplineType> & these_types, + const bool remove_interleaving, + const bool use_view_offset) +{ + + + + if (use_view_offset) + warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); + + const ProjDataInfo & proj_data_in_info = + *proj_data_in.get_proj_data_info_ptr(); + const ProjDataInfo & proj_data_out_info = + *proj_data_out.get_proj_data_info_ptr(); + + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) + { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } + // check for the same ring radius + // This is strictly speaking only necessary for non-arccorrected data, but + // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) + { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } + + + + BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); + + BasicCoordinate<3, double> offset, step ; + + // find relation between out_index and in_index such that they correspond to the same physical position + // out_index * m_zoom + m_offset = in_index + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + // offset in 'in' index units + offset[1] = + (proj_data_in_info.get_m(Bin(0,0,0,0)) - + proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; + step[1]= + out_sampling_m/in_sampling_m; + + const float in_sampling_phi = + (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / + (remove_interleaving ? 2 : 1); + + const float out_sampling_phi = + proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); + + const float out_view_offset = + use_view_offset + ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + const float in_view_offset = + use_view_offset + ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + offset[2] = + (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; + step[2] = + out_sampling_phi/in_sampling_phi; + + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + offset[3] = + (proj_data_out_info.get_s(Bin(0,0,0,0)) - + proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; + step[3]= + out_sampling_s/in_sampling_s; + + // initialise interpolator + if (remove_interleaving) + + { + + + shared_ptr non_interleaved_proj_data_info_sptr = + make_non_interleaved_proj_data_info(proj_data_in_info); + + const SegmentBySinogram non_interleaved_segment = + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_in.get_segment_by_sinogram(0)); + // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + + Array<3,float> extended = + extend_segment_in_views(non_interleaved_segment, 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; + proj_data_interpolator.set_coef(extended); + } + else + { + Array<3,float> extended = + extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + std::cerr << "MAX UP "<< extended.find_max() << '\n'; + std::cerr << "MIN UP "<< extended.find_min() << '\n'; + proj_data_interpolator.set_coef(extended); + } + + // now do interpolation + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); + + proj_data_out.set_segment(sino_3D_out); + + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; + return Succeeded::yes; +} + + + + +Succeeded +interpolate_projdata_pull(ProjData& proj_data_out, + const ProjData& proj_data_in, + const bool remove_interleaving, + const bool use_view_offset) +{ + + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + if (use_view_offset) + warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); + + const ProjDataInfo & proj_data_in_info = + *proj_data_in.get_proj_data_info_ptr(); + const ProjDataInfo & proj_data_out_info = + *proj_data_out.get_proj_data_info_ptr(); + + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) + { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } + // check for the same ring radius + // This is strictly speaking only necessary for non-arccorrected data, but + // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) + { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } + + + + + + BasicCoordinate<3, double> offset, step ; + + // find relation between out_index and in_index such that they correspond to the same physical position + // out_index * m_zoom + m_offset = in_index + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + // offset in 'in' index units + offset[1] = + (proj_data_in_info.get_m(Bin(0,0,0,0)) - + proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; + step[1]= + out_sampling_m/in_sampling_m; + + const float in_sampling_phi = + (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / + (remove_interleaving ? 2 : 1); + + const float out_sampling_phi = + proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); + + const float out_view_offset = + use_view_offset + ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + const float in_view_offset = + use_view_offset + ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + offset[2] = + (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; + step[2] = + out_sampling_phi/in_sampling_phi; + + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + offset[3] = + (proj_data_out_info.get_s(Bin(0,0,0,0)) - + proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; + step[3]= + out_sampling_s/in_sampling_s; + + // initialise interpolator + if (remove_interleaving) + + { + + + shared_ptr non_interleaved_proj_data_info_sptr = + make_non_interleaved_proj_data_info(proj_data_in_info); + + const SegmentBySinogram non_interleaved_segment = + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_in.get_segment_by_sinogram(0)); + // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + + Array<3,float> extended = + extend_segment_in_views(non_interleaved_segment, 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); + proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; + } + else + { + Array<3,float> extended = + extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + + + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); + proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + return Succeeded::no; + + } + + return Succeeded::yes; +} + + +Succeeded +interpolate_projdata_push(ProjData& proj_data_out, + const ProjData& proj_data_in, + const bool remove_interleaving, + const bool use_view_offset) +{ + + + SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + + if (use_view_offset) + warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); + + const ProjDataInfo & proj_data_in_info = + *proj_data_in.get_proj_data_info_ptr(); + const ProjDataInfo & proj_data_out_info = + *proj_data_out.get_proj_data_info_ptr(); + + if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) + { + error("interpolate_projdata needs both projection data to be of the same type\n" + "(e.g. both arc-corrected or both not arc-corrected)"); + } + // check for the same ring radius + // This is strictly speaking only necessary for non-arccorrected data, but + // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - + proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) + { + error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); + } + + + + BasicCoordinate<3, double> offset, step ; + + // find relation between out_index and in_index such that they correspond to the same physical position + // out_index * m_zoom + m_offset = in_index + const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); + const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); + // offset in 'in' index units + offset[1] = + (proj_data_out_info.get_m(Bin(0,0,0,0)) - + proj_data_in_info.get_m(Bin(0,0,0,0))) / out_sampling_m; //divide by sampling: conversion from mm to voxel units + step[1]= + in_sampling_m/out_sampling_m; + + const float out_sampling_phi = + (proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0))) / + (remove_interleaving ? 2 : 1); + + const float in_sampling_phi = + proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0)); + + const float out_view_offset = + use_view_offset + ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + const float in_view_offset = + use_view_offset + ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() + : 0.F; + offset[2] = + (proj_data_out_info.get_phi(Bin(0,0,0,0)) + out_view_offset - proj_data_in_info.get_phi(Bin(0,0,0,0)) - in_view_offset) / out_sampling_phi; + + step[2] = + in_sampling_phi/out_sampling_phi; + + const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); + const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); + offset[3] = + (proj_data_in_info.get_s(Bin(0,0,0,0)) - + proj_data_out_info.get_s(Bin(0,0,0,0))) / out_sampling_s; + step[3]= + in_sampling_s/out_sampling_s; + + + // initialise interpolator + if (remove_interleaving) + + { + + //we need to create an 'extended output' + shared_ptr non_interleaved_proj_data_info_sptr = + make_non_interleaved_proj_data_info(proj_data_out_info); + + const SegmentBySinogram non_interleaved_segment = + make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_out.get_segment_by_sinogram(0)); + // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + + } + } + + //std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; + // for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) + // { + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); + // =================== PUSH ================================== + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + + // =================== TRANSPOSE EXTENDED ===================== + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + { + for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) + { + const int old_min = out[z][y].get_min_index(); + const int old_max = out[z][y].get_max_index(); + out[z][y].grow(old_min+1, old_max-1); //resize + } + } + std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + // =================== TRANSPOSE REMOVE INTERLEAVING ======= + + + // =================== CREATE OUTPUT ======================= + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + return Succeeded::no; + + // } + } + else + { + // ================== this is without remove interleaving ====== + Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + { + for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) + { + const int old_min = extended[z][y].get_min_index(); + const int old_max = extended[z][y].get_max_index(); + extended[z][y].grow(old_min-1, old_max+1); + extended[z][y][old_min-1] = extended[z][y][old_min]; + extended[z][y][old_max+1] = extended[z][y][old_max]; + } + } + + //for(int segm_num = proj_data_in.get_min_segment_num(); segm_num < proj_data_in.get_max_segment_num(); ++segm_num) + //{ + + //std::cout<<"segm num :" << proj_data_in.get_max_segment_num() << '\n'; + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); + // =================== PUSH ===================== + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + + // =================== TRANSPOSE EXTENDED ===================== + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) + { + for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) + { + const int old_min = out[z][y].get_min_index(); + const int old_max = out[z][y].get_max_index(); + out[z][y].grow(old_min+1, old_max-1); //resize + } + } + std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + // =================== CREATE OUTPUT ===================== + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + return Succeeded::no; + + } + //} + + return Succeeded::yes; +} + +END_NAMESPACE_STIR From b4c5e138a106c5cc3f18304ebf523e515617236f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 27 Jun 2019 23:46:35 +0100 Subject: [PATCH 081/274] before removing int --- src/buildblock/interpolate_projdata.cxx | 6 +- .../interpolate_projdata.cxx.autosave | 779 ------------------ 2 files changed, 3 insertions(+), 782 deletions(-) delete mode 100644 src/buildblock/interpolate_projdata.cxx.autosave diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index bc10bd9308..0e27ff3e11 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -669,7 +669,6 @@ interpolate_projdata_push(ProjData& proj_data_out, // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) @@ -683,6 +682,7 @@ interpolate_projdata_push(ProjData& proj_data_out, } } + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; //std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; // for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) // { @@ -724,7 +724,6 @@ interpolate_projdata_push(ProjData& proj_data_out, { // ================== this is without remove interleaving ====== Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) @@ -737,6 +736,7 @@ interpolate_projdata_push(ProjData& proj_data_out, } } + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; //for(int segm_num = proj_data_in.get_min_segment_num(); segm_num < proj_data_in.get_max_segment_num(); ++segm_num) //{ @@ -751,7 +751,7 @@ interpolate_projdata_push(ProjData& proj_data_out, std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) diff --git a/src/buildblock/interpolate_projdata.cxx.autosave b/src/buildblock/interpolate_projdata.cxx.autosave deleted file mode 100644 index 055117c0b8..0000000000 --- a/src/buildblock/interpolate_projdata.cxx.autosave +++ /dev/null @@ -1,779 +0,0 @@ -// -// -/* - Copyright (C) 2005 - 2009-10-27, Hammersmith Imanet Ltd - Copyright (C) 2011-07-01 - 2011, Kris Thielemans - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ -/*! - \file - \ingroup projdata - \brief Perform B-Splines Interpolation of sinograms - - \author Charalampos Tsoumpas - \author Kris Thielemans - -*/ -#include "stir/ProjData.h" -//#include "stir/display.h" -#include "stir/ProjDataInfo.h" -#include "stir/ProjDataInfoCylindricalNoArcCorr.h" -#include "stir/IndexRange.h" -#include "stir/BasicCoordinate.h" -#include "stir/Sinogram.h" -#include "stir/SegmentBySinogram.h" -#include "stir/Succeeded.h" -#include "stir/numerics/BSplines.h" -#include "stir/numerics/BSplinesRegularGrid.h" -#include "stir/interpolate_projdata.h" -#include "stir/extend_projdata.h" -#include "stir/numerics/sampling_functions.h" -#include "stir_experimental/motion/Transform3DObjectImageProcessor.h" -#include "stir_experimental/motion/transform_3d_object.h" -#include "stir_experimental/numerics/more_interpolators.h" -#include - -START_NAMESPACE_STIR - -namespace detail_interpolate_projdata -{ - /* Collection of functions to remove interleaving in non-arccorrected data. - - It does this by doubling the number of views, and filling in the new - tangential positions by averaging the 4 neighbouring bins. - - WARNING: most of STIR will get confused by the resulting sinograms, - so only use them here for the interpolate_projdata implementation. - */ - - static shared_ptr - make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) - { - - if (dynamic_cast(&proj_data_info) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - shared_ptr new_proj_data_info_sptr( - proj_data_info.clone()); - new_proj_data_info_sptr-> - set_num_views(proj_data_info.get_num_views()*2); - return new_proj_data_info_sptr; - } - - static shared_ptr - make_extended_proj_data_info(const ProjDataInfo& proj_data_info) - { - - if (dynamic_cast(&proj_data_info) == NULL) - error("make_extended_proj_data is only appropriate for non-arccorrected data"); - - shared_ptr new_proj_data_info_sptr( - proj_data_info.clone()); - new_proj_data_info_sptr-> - set_num_views(proj_data_info.get_num_views()*2); - return new_proj_data_info_sptr; - } - - static shared_ptr - transpose_make_non_interleaved_proj_data_info(const ProjDataInfo& proj_data_info) - { - - // TODO: arc-correct? - if (dynamic_cast(&proj_data_info) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - shared_ptr new_proj_data_info_sptr( - proj_data_info.clone()); - new_proj_data_info_sptr-> - set_num_views(proj_data_info.get_num_views()/2); - return new_proj_data_info_sptr; - } - - static void - make_non_interleaved_sinogram(Sinogram& out_sinogram, - const Sinogram& in_sinogram) - { - if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - assert(out_sinogram.get_min_view_num() == 0); - assert(in_sinogram.get_min_view_num() == 0); - assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()*2); - assert(in_sinogram.get_segment_num() == 0); - assert(out_sinogram.get_segment_num() == 0); - - const int in_num_views = in_sinogram.get_num_views(); - - for (int view_num = out_sinogram.get_min_view_num(); - view_num <= out_sinogram.get_max_view_num(); - ++view_num) - { - // TODO don't put in outer tangential poss for now to avoid boundary stuff - for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; - tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; - ++tangential_pos_num) - { - if ((view_num+tangential_pos_num)%2 == 0) - { - const int in_view_num = - view_num%2==0 ? view_num/2 : (view_num+1)/2; - out_sinogram[view_num][tangential_pos_num] = - in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; - } - else - { - const int next_in_view = view_num/2+1; - const int other_in_view = (view_num+1)/2; - - out_sinogram[view_num][tangential_pos_num] = - (in_sinogram[view_num/2][tangential_pos_num] + - in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] - )/4; - } - } - } - } - -#if 0 - // not needed for now - static Sinogram - make_non_interleaved_sinogram(const ProjDataInfo& non_interleaved_proj_data_info, - const Sinogram& in_sinogram) - { - Sinogram out_sinogram = - non_interleaved_proj_data_info.get_empty_sinogram(in_sinogram.get_axial_pos_num(), - in_sinogram.get_segment_num()); - - make_non_interleaved_sinogram(out_sinogram, in_sinogram); - return out_sinogram; - } -#endif - - static void - transpose_make_non_interleaved_sinogram(Sinogram& out_sinogram, - const Sinogram& in_sinogram) - { - if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - assert(out_sinogram.get_min_view_num() == 0); - assert(in_sinogram.get_min_view_num() == 0); - assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()/2); - assert(in_sinogram.get_segment_num() == 0); - assert(out_sinogram.get_segment_num() == 0); - - const int in_num_views = in_sinogram.get_num_views(); - - for (int view_num = out_sinogram.get_min_view_num(); - view_num <= out_sinogram.get_max_view_num(); - ++view_num) - { - // TODO don't put in outer tangential poss for now to avoid boundary stuff - for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; - tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; - ++tangential_pos_num) - { - if ((view_num+tangential_pos_num)%2 == 0) - { - const int in_view_num = - view_num%2==0 ? view_num/2 : (view_num+1)/2; - out_sinogram[view_num][tangential_pos_num] = - in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; - } - else - { - const int next_in_view = view_num/2+1; - const int other_in_view = (view_num+1)/2; - - out_sinogram[view_num][tangential_pos_num] = - (in_sinogram[view_num/2][tangential_pos_num] + - in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] - )/4; - } - } - } - } - - - static void - make_non_interleaved_segment(SegmentBySinogram& out_segment, - const SegmentBySinogram& in_segment) - { - if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - for (int axial_pos_num = out_segment.get_min_axial_pos_num(); - axial_pos_num <= out_segment.get_max_axial_pos_num(); - ++axial_pos_num) - { - Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); - make_non_interleaved_sinogram(out_sinogram, - in_segment.get_sinogram(axial_pos_num)); - out_segment.set_sinogram(out_sinogram); - } - } - - - - - static void - transpose_make_non_interleaved_segment(SegmentBySinogram& out_segment, - const SegmentBySinogram& in_segment) - { - if (dynamic_cast(in_segment.get_proj_data_info_ptr()) == NULL) - error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); - - for (int axial_pos_num = out_segment.get_min_axial_pos_num(); - axial_pos_num <= out_segment.get_max_axial_pos_num(); - ++axial_pos_num) - { - Sinogram out_sinogram = out_segment.get_sinogram(axial_pos_num); - transpose_make_non_interleaved_sinogram(out_sinogram, - in_segment.get_sinogram(axial_pos_num)); - out_segment.set_sinogram(out_sinogram); - } - } - - static SegmentBySinogram - make_non_interleaved_segment(const ProjDataInfo& non_interleaved_proj_data_info, - const SegmentBySinogram& in_segment) - { - - SegmentBySinogram out_segment = - non_interleaved_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); - - make_non_interleaved_segment(out_segment, in_segment); - - return out_segment; - } - - static SegmentBySinogram - transpose_make_non_interleaved_segment(const ProjDataInfo& compressed_proj_data_info, - const SegmentBySinogram& in_segment) - { - - SegmentBySinogram out_segment = - compressed_proj_data_info.get_empty_segment_by_sinogram(in_segment.get_segment_num()); - - transpose_make_non_interleaved_segment(out_segment, in_segment); - - return out_segment; - } -} // end namespace detail_interpolate_projdata - - -using namespace detail_interpolate_projdata; - -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, const BSpline::BSplineType these_types, - const bool remove_interleaving, - const bool use_view_offset) -{ - - BasicCoordinate<3, BSpline::BSplineType> these_types_3; - - these_types_3[1]=these_types_3[2]=these_types_3[3]=these_types; - - interpolate_projdata(proj_data_out,proj_data_in,these_types_3, remove_interleaving, use_view_offset); - - - return Succeeded::yes; -} - -Succeeded -interpolate_projdata(ProjData& proj_data_out, - const ProjData& proj_data_in, - const BasicCoordinate<3, BSpline::BSplineType> & these_types, - const bool remove_interleaving, - const bool use_view_offset) -{ - - - - if (use_view_offset) - warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); - - const ProjDataInfo & proj_data_in_info = - *proj_data_in.get_proj_data_info_ptr(); - const ProjDataInfo & proj_data_out_info = - *proj_data_out.get_proj_data_info_ptr(); - - if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) - { - error("interpolate_projdata needs both projection data to be of the same type\n" - "(e.g. both arc-corrected or both not arc-corrected)"); - } - // check for the same ring radius - // This is strictly speaking only necessary for non-arccorrected data, but - // we leave it in for all cases. - if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - - proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) - { - error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); - } - - - - BSpline::BSplinesRegularGrid<3, float, float> proj_data_interpolator(these_types); - - BasicCoordinate<3, double> offset, step ; - - // find relation between out_index and in_index such that they correspond to the same physical position - // out_index * m_zoom + m_offset = in_index - const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); - const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); - // offset in 'in' index units - offset[1] = - (proj_data_in_info.get_m(Bin(0,0,0,0)) - - proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; - step[1]= - out_sampling_m/in_sampling_m; - - const float in_sampling_phi = - (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / - (remove_interleaving ? 2 : 1); - - const float out_sampling_phi = - proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); - - const float out_view_offset = - use_view_offset - ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - const float in_view_offset = - use_view_offset - ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - offset[2] = - (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; - step[2] = - out_sampling_phi/in_sampling_phi; - - const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); - const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); - offset[3] = - (proj_data_out_info.get_s(Bin(0,0,0,0)) - - proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; - step[3]= - out_sampling_s/in_sampling_s; - - // initialise interpolator - if (remove_interleaving) - - { - - - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); - - const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); - // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - - Array<3,float> extended = - extend_segment_in_views(non_interleaved_segment, 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - std::cerr << "MAX UP "<< extended.find_max() << '\n'; - std::cerr << "MIN UP "<< extended.find_min() << '\n'; - proj_data_interpolator.set_coef(extended); - } - else - { - Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - std::cerr << "MAX UP "<< extended.find_max() << '\n'; - std::cerr << "MIN UP "<< extended.find_min() << '\n'; - proj_data_interpolator.set_coef(extended); - } - - // now do interpolation - - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - sample_function_on_regular_grid(sino_3D_out, proj_data_interpolator, offset, step); - - proj_data_out.set_segment(sino_3D_out); - - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - return Succeeded::yes; -} - - - - -Succeeded -interpolate_projdata_pull(ProjData& proj_data_out, - const ProjData& proj_data_in, - const bool remove_interleaving, - const bool use_view_offset) -{ - - - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - if (use_view_offset) - warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); - - const ProjDataInfo & proj_data_in_info = - *proj_data_in.get_proj_data_info_ptr(); - const ProjDataInfo & proj_data_out_info = - *proj_data_out.get_proj_data_info_ptr(); - - if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) - { - error("interpolate_projdata needs both projection data to be of the same type\n" - "(e.g. both arc-corrected or both not arc-corrected)"); - } - // check for the same ring radius - // This is strictly speaking only necessary for non-arccorrected data, but - // we leave it in for all cases. - if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - - proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) - { - error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); - } - - - - - - BasicCoordinate<3, double> offset, step ; - - // find relation between out_index and in_index such that they correspond to the same physical position - // out_index * m_zoom + m_offset = in_index - const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); - const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); - // offset in 'in' index units - offset[1] = - (proj_data_in_info.get_m(Bin(0,0,0,0)) - - proj_data_out_info.get_m(Bin(0,0,0,0))) / in_sampling_m; - step[1]= - out_sampling_m/in_sampling_m; - - const float in_sampling_phi = - (proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0))) / - (remove_interleaving ? 2 : 1); - - const float out_sampling_phi = - proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0)); - - const float out_view_offset = - use_view_offset - ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - const float in_view_offset = - use_view_offset - ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - offset[2] = - (proj_data_in_info.get_phi(Bin(0,0,0,0)) + in_view_offset - proj_data_out_info.get_phi(Bin(0,0,0,0)) - out_view_offset) / in_sampling_phi; - step[2] = - out_sampling_phi/in_sampling_phi; - - const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); - const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); - offset[3] = - (proj_data_out_info.get_s(Bin(0,0,0,0)) - - proj_data_in_info.get_s(Bin(0,0,0,0))) / in_sampling_s; - step[3]= - out_sampling_s/in_sampling_s; - - // initialise interpolator - if (remove_interleaving) - - { - - - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); - - const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); - // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - - Array<3,float> extended = - extend_segment_in_views(non_interleaved_segment, 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - - sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - } - else - { - Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - - - sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) - return Succeeded::no; - - } - - return Succeeded::yes; -} - - -Succeeded -interpolate_projdata_push(ProjData& proj_data_out, - const ProjData& proj_data_in, - const bool remove_interleaving, - const bool use_view_offset) -{ - - - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; - - if (use_view_offset) - warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); - - const ProjDataInfo & proj_data_in_info = - *proj_data_in.get_proj_data_info_ptr(); - const ProjDataInfo & proj_data_out_info = - *proj_data_out.get_proj_data_info_ptr(); - - if (typeid(proj_data_in_info) != typeid(proj_data_out_info)) - { - error("interpolate_projdata needs both projection data to be of the same type\n" - "(e.g. both arc-corrected or both not arc-corrected)"); - } - // check for the same ring radius - // This is strictly speaking only necessary for non-arccorrected data, but - // we leave it in for all cases. - if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - - proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) - { - error("interpolate_projdata needs both projection to be of a scanner with the same ring radius"); - } - - - - BasicCoordinate<3, double> offset, step ; - - // find relation between out_index and in_index such that they correspond to the same physical position - // out_index * m_zoom + m_offset = in_index - const float in_sampling_m = proj_data_in_info.get_sampling_in_m(Bin(0,0,0,0)); - const float out_sampling_m = proj_data_out_info.get_sampling_in_m(Bin(0,0,0,0)); - // offset in 'in' index units - offset[1] = - (proj_data_out_info.get_m(Bin(0,0,0,0)) - - proj_data_in_info.get_m(Bin(0,0,0,0))) / out_sampling_m; //divide by sampling: conversion from mm to voxel units - step[1]= - in_sampling_m/out_sampling_m; - - const float out_sampling_phi = - (proj_data_out_info.get_phi(Bin(0,1,0,0)) - proj_data_out_info.get_phi(Bin(0,0,0,0))) / - (remove_interleaving ? 2 : 1); - - const float in_sampling_phi = - proj_data_in_info.get_phi(Bin(0,1,0,0)) - proj_data_in_info.get_phi(Bin(0,0,0,0)); - - const float out_view_offset = - use_view_offset - ? proj_data_out_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - const float in_view_offset = - use_view_offset - ? proj_data_in_info.get_scanner_ptr()->get_default_intrinsic_tilt() - : 0.F; - offset[2] = - (proj_data_out_info.get_phi(Bin(0,0,0,0)) + out_view_offset - proj_data_in_info.get_phi(Bin(0,0,0,0)) - in_view_offset) / out_sampling_phi; - - step[2] = - in_sampling_phi/out_sampling_phi; - - const float out_sampling_s = proj_data_out_info.get_sampling_in_s(Bin(0,0,0,0)); - const float in_sampling_s = proj_data_in_info.get_sampling_in_s(Bin(0,0,0,0)); - offset[3] = - (proj_data_in_info.get_s(Bin(0,0,0,0)) - - proj_data_out_info.get_s(Bin(0,0,0,0))) / out_sampling_s; - step[3]= - in_sampling_s/out_sampling_s; - - - // initialise interpolator - if (remove_interleaving) - - { - - //we need to create an 'extended output' - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_out_info); - - const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_out.get_segment_by_sinogram(0)); - // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - - Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - - } - } - - //std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; - // for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) - // { - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); - // =================== PUSH ================================== - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - - // =================== TRANSPOSE EXTENDED ===================== - shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) - { - for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) - { - const int old_min = out[z][y].get_min_index(); - const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); //resize - } - } - std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // =================== TRANSPOSE REMOVE INTERLEAVING ======= - - - // =================== CREATE OUTPUT ======================= - SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) - return Succeeded::no; - - // } - } - else - { - // ================== this is without remove interleaving ====== - Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } - - //for(int segm_num = proj_data_in.get_min_segment_num(); segm_num < proj_data_in.get_max_segment_num(); ++segm_num) - //{ - - //std::cout<<"segm num :" << proj_data_in.get_max_segment_num() << '\n'; - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); - // =================== PUSH ===================== - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - - // =================== TRANSPOSE EXTENDED ===================== - shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) - { - for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) - { - const int old_min = out[z][y].get_min_index(); - const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); //resize - } - } - std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // =================== CREATE OUTPUT ===================== - SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) - return Succeeded::no; - - } - //} - - return Succeeded::yes; -} - -END_NAMESPACE_STIR From 5b9ac6d8855b20cfa7fe38ecc578d6975e5daa10 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 00:01:29 +0100 Subject: [PATCH 082/274] almost done --- src/buildblock/extend_projdata.cxx | 2 +- src/buildblock/interpolate_projdata.cxx | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index ed6af0f901..0275174161 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -189,7 +189,7 @@ extend_segment_in_views(const SegmentBySinogram& sino, extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], *(sino.get_proj_data_info_ptr()), min_view_extension, max_view_extension); - out[min[1]]=out[min[1]+1]; + //out[min[1]]=out[min[1]+1]; } return out; } diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 0e27ff3e11..e3061f9831 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -708,14 +708,18 @@ interpolate_projdata_push(ProjData& proj_data_out, } std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================== TRANSPOSE REMOVE INTERLEAVING ======= - - - // =================== CREATE OUTPUT ======================= SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + + shared_ptr new_proj_data_info_sptr = proj_data_out_info.create_shared_clone(); + SegmentBySinogram transpose_interleaved_segment = + transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, + compressed_output); + transpose_interleaved_segment.fill(1); + // =================== CREATE OUTPUT ======================= + proj_data_out.set_segment(transpose_interleaved_segment); + if (proj_data_out.set_segment(transpose_interleaved_segment) == Succeeded::no) return Succeeded::no; // } From e2fe6fc3dc193f38fd21a58146a473f710245e91 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 00:05:56 +0100 Subject: [PATCH 083/274] ok --- src/buildblock/interpolate_projdata.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index e3061f9831..938099871d 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -716,7 +716,7 @@ interpolate_projdata_push(ProjData& proj_data_out, SegmentBySinogram transpose_interleaved_segment = transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, compressed_output); - transpose_interleaved_segment.fill(1); + //transpose_interleaved_segment.fill(1); // =================== CREATE OUTPUT ======================= proj_data_out.set_segment(transpose_interleaved_segment); if (proj_data_out.set_segment(transpose_interleaved_segment) == Succeeded::no) From 09bf5334d1c61f79c1a47191fc510f204a7b42e5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 09:20:03 +0100 Subject: [PATCH 084/274] comments --- src/buildblock/interpolate_projdata.cxx | 64 ++++++++----------- ...mple_and_fit_scatter_estimate.cxx.autosave | 2 - 2 files changed, 26 insertions(+), 40 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 938099871d..357c983ea8 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -600,9 +600,7 @@ interpolate_projdata_push(ProjData& proj_data_out, error("interpolate_projdata needs both projection data to be of the same type\n" "(e.g. both arc-corrected or both not arc-corrected)"); } - // check for the same ring radius - // This is strictly speaking only necessary for non-arccorrected data, but - // we leave it in for all cases. + if (fabs(proj_data_in_info.get_scanner_ptr()->get_inner_ring_radius() - proj_data_out_info.get_scanner_ptr()->get_inner_ring_radius()) > 1) { @@ -654,19 +652,14 @@ interpolate_projdata_push(ProjData& proj_data_out, in_sampling_s/out_sampling_s; - // initialise interpolator if (remove_interleaving) { - //we need to create an 'extended output' - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_out_info); - - const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_out.get_segment_by_sinogram(0)); - // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); + // =================== RESIZE 'EXTENDED' OUTPUT ========================= + shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_out_info); + const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, + proj_data_out.get_segment_by_sinogram(0)); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) @@ -683,20 +676,19 @@ interpolate_projdata_push(ProjData& proj_data_out, } std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - //std::cout<<"extended before push:" << extended.size_all()/(z_dim*y_dim) << "x" << extended[0].size_all()/z_dim << "x" << extended[0][0].size_all() << '\n'; - // for(int segm_num = proj_data_in.get_min_segment_num(); segm_num <= proj_data_in.get_max_segment_num(); ++segm_num) - // { - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); - // =================== PUSH ================================== + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments + // ===========================PUSH ================================== + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - // =================== TRANSPOSE EXTENDED ===================== + // =================== TRANSPOSE EXTENDED =========================== + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) @@ -707,28 +699,26 @@ interpolate_projdata_push(ProjData& proj_data_out, } } std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // =================== TRANSPOSE REMOVE INTERLEAVING ======= + // =================TRANSPOSE REMOVE INTERLEAVING ==================== + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; shared_ptr new_proj_data_info_sptr = proj_data_out_info.create_shared_clone(); - SegmentBySinogram transpose_interleaved_segment = - transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, - compressed_output); - //transpose_interleaved_segment.fill(1); - // =================== CREATE OUTPUT ======================= + SegmentBySinogram transpose_interleaved_segment = transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, compressed_output); + + // ======================== CREATE OUTPUT ============================= proj_data_out.set_segment(transpose_interleaved_segment); if (proj_data_out.set_segment(transpose_interleaved_segment) == Succeeded::no) return Succeeded::no; - - // } } else { - // ================== this is without remove interleaving ====== - Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) + // =================== RESIZE 'EXTENDED' OUTPUT ========================= + + Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); + for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) { for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) { @@ -741,15 +731,13 @@ interpolate_projdata_push(ProjData& proj_data_out, } std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - //for(int segm_num = proj_data_in.get_min_segment_num(); segm_num < proj_data_in.get_max_segment_num(); ++segm_num) - //{ - - //std::cout<<"segm num :" << proj_data_in.get_max_segment_num() << '\n'; SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); - // =================== PUSH ===================== + // ===========================PUSH ================================== + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - // =================== TRANSPOSE EXTENDED ===================== + // =================== TRANSPOSE EXTENDED =========================== + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; @@ -766,7 +754,8 @@ interpolate_projdata_push(ProjData& proj_data_out, } } std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // =================== CREATE OUTPUT ===================== + // ======================== CREATE OUTPUT ============================= + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; @@ -775,7 +764,6 @@ interpolate_projdata_push(ProjData& proj_data_out, return Succeeded::no; } - //} return Succeeded::yes; } diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave index 8fbed19b06..2e852302f1 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave @@ -189,8 +189,6 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, interpolated_direct_scatter_proj_data_info_sptr); - //std::cout << "ALEX:"<< interpolated_direct_scatter.get_num_segments() << "x"<< interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_views()<< "x" << interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; - // interpolate projdata interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); std::cerr << "PUSH.." << '\n'; // Perform Inverse Single Slice Rebinning From dbca79577a4e09e2069dabb9c5ceb12f6310f436 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 12:27:31 +0100 Subject: [PATCH 085/274] interleaving fails but dim ok --- src/buildblock/interpolate_projdata.cxx | 35 +-- .../upsample_and_fit_scatter_estimate.cxx | 2 - ...mple_and_fit_scatter_estimate.cxx.autosave | 200 ------------------ 3 files changed, 18 insertions(+), 219 deletions(-) delete mode 100644 src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 357c983ea8..4e738925b1 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -204,7 +204,7 @@ namespace detail_interpolate_projdata in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] - )/4; + )/4 + in_sinogram[view_num][tangential_pos_num]; //contribution to itself; } } } @@ -528,8 +528,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); - // display(non_interleaved_segment, non_interleaved_segment.find_max(),"non-inter"); - + std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; + std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) @@ -544,8 +544,10 @@ interpolate_projdata_pull(ProjData& proj_data_out, } } + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; } @@ -565,7 +567,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, } } - + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) @@ -683,12 +685,9 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== - shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views + SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended d Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) @@ -698,16 +697,19 @@ interpolate_projdata_push(ProjData& proj_data_out, out[z][y].grow(old_min+1, old_max-1); //resize } } - std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================TRANSPOSE REMOVE INTERLEAVING ==================== - SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + SegmentBySinogram compressed_output(out, non_interleaved_proj_data_info_sptr, 0); + std::cout<<"NON-INTERLEAVED:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; shared_ptr new_proj_data_info_sptr = proj_data_out_info.create_shared_clone(); SegmentBySinogram transpose_interleaved_segment = transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, compressed_output); + //std::cout<<"VIEWS - BEFORE:" << compressed_output.get_num_views() << '\n'; + //std::cout<<"VIEWS - AFTER:" << transpose_interleaved_segment.get_num_views() << '\n'; + std::cout<<"FINAL:" << transpose_interleaved_segment.get_num_views() << "x" << transpose_interleaved_segment.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; // ======================== CREATE OUTPUT ============================= proj_data_out.set_segment(transpose_interleaved_segment); if (proj_data_out.set_segment(transpose_interleaved_segment) == Succeeded::no) @@ -741,9 +743,8 @@ interpolate_projdata_push(ProjData& proj_data_out, shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - extended_proj_data_info_sptr->set_num_views(extended_segment_sino.get_num_views()); // set the number of views Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"OUT - COMPRESSED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) { for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) @@ -753,11 +754,11 @@ interpolate_projdata_push(ProjData& proj_data_out, out[z][y].grow(old_min+1, old_max-1); //resize } } - std::cout<<"OUT - RESIZED:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // ======================== CREATE OUTPUT ============================= SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"OUT - SINO:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 8fbed19b06..2e852302f1 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -189,8 +189,6 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, interpolated_direct_scatter_proj_data_info_sptr); - //std::cout << "ALEX:"<< interpolated_direct_scatter.get_num_segments() << "x"<< interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_views()<< "x" << interpolated_direct_scatter.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; - // interpolate projdata interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); std::cerr << "PUSH.." << '\n'; // Perform Inverse Single Slice Rebinning diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave deleted file mode 100644 index 2e852302f1..0000000000 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx.autosave +++ /dev/null @@ -1,200 +0,0 @@ -/* - Copyright (C) 2005 - 2011-12-31, Hammersmith Imanet Ltd - Copyright (C) 2014, University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ -/*! -\file -\ingroup scatter -\brief implementation of stir::ScatterEstimationByBin::upsample_and_fit_scatter_estimate - -\author Charalampos Tsoumpas -\author Kris Thielemans -*/ - -#include "stir/ProjDataInfo.h" -#include "stir/ExamInfo.h" -#include "stir/ProjDataInMemory.h" -#include "stir/inverse_SSRB.h" -#include "stir/scale_sinograms.h" -#include "stir/scatter/ScatterEstimation.h" -#include "stir/recon_buildblock/BinNormalisation.h" -#include "stir/interpolate_projdata.h" -#include "stir/utilities.h" -#include "stir/IndexRange2D.h" -#include "stir/stream.h" -#include "stir/Succeeded.h" -#include "stir/thresholding.h" -#include "stir/is_null_ptr.h" -#include "stir/ArrayFilter1DUsingConvolution.h" -#include -#include -#include -/***********************************************************/ - -START_NAMESPACE_STIR - -void -ScatterEstimation:: -upsample_and_fit_scatter_estimate(ProjData& scaled_scatter_proj_data, - const ProjData& emission_proj_data, - const ProjData& scatter_proj_data, - BinNormalisation& scatter_normalisation, - const ProjData& weights_proj_data, - const float min_scale_factor, - const float max_scale_factor, - const unsigned half_filter_width, - BSpline::BSplineType spline_type, - const bool remove_interleaving) -{ - - shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); - - - info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); - ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), - interpolated_direct_scatter_proj_data_info_sptr); - - interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); - - - const TimeFrameDefinitions& time_frame_defs = emission_proj_data.get_exam_info_sptr()->time_frame_definitions; - - if (min_scale_factor != 1 || max_scale_factor != 1 || !scatter_normalisation.is_trivial()) - { - ProjDataInMemory interpolated_scatter(emission_proj_data.get_exam_info_sptr(), - emission_proj_data.get_proj_data_info_ptr()->create_shared_clone()); - inverse_SSRB(interpolated_scatter, interpolated_direct_scatter); - - scatter_normalisation.set_up(emission_proj_data.get_proj_data_info_ptr()->create_shared_clone()); - scatter_normalisation.undo(interpolated_scatter, - time_frame_defs.get_start_time(), time_frame_defs.get_end_time()); - Array<2,float> scale_factors; - - info("upsample_and_fit_scatter_estimate: Finding scale factors by sinogram"); - scale_factors = get_scale_factors_per_sinogram( - emission_proj_data, - interpolated_scatter, - weights_proj_data); - - std::cout << scale_factors; - threshold_lower(scale_factors.begin_all(), - scale_factors.end_all(), - min_scale_factor); - threshold_upper(scale_factors.begin_all(), - scale_factors.end_all(), - max_scale_factor); - info("upsample_and_fit_scatter_estimate: After thresholding:"); - std::cout << scale_factors; - VectorWithOffset kernel(-static_cast(half_filter_width),half_filter_width); - kernel.fill(1.F/(2*half_filter_width+1)); - ArrayFilter1DUsingConvolution lowpass_filter(kernel, BoundaryConditions::constant); - std::for_each(scale_factors.begin(), - scale_factors.end(), - lowpass_filter); - info("upsample_and_fit_scatter_estimate: After filtering:"); - std::cout << scale_factors; - info("upsample_and_fit_scatter_estimate: applying scale factors"); - if (scale_sinograms(scaled_scatter_proj_data, - interpolated_scatter, - scale_factors) != Succeeded::yes) - { - error("upsample_and_fit_scatter_estimate: writing of scaled sinograms failed"); - } - } - else // min/max_scale_factor equal to 1 - { - inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); - } -} - - -void -ScatterEstimation:: -upsample_scatter_estimate(ProjData& scaled_scatter_proj_data, - const ProjData& emission_proj_data, - const ProjData& scatter_proj_data, - const bool remove_interleaving) -{ - stir::BSpline::BSplineType spline_type = stir::BSpline::linear; - shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); - - - info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); - ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), - interpolated_direct_scatter_proj_data_info_sptr); - - // interpolate projdata - interpolate_projdata(interpolated_direct_scatter, scatter_proj_data, spline_type, remove_interleaving); - - // Perform Inverse Single Slice Rebinning - inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); - -} - - - -void -ScatterEstimation:: -pull_scatter_estimate(ProjData& scaled_scatter_proj_data, - const ProjData& emission_proj_data, - const ProjData& scatter_proj_data, - const bool remove_interleaving) -{ - - shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); - - - info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); - ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), - interpolated_direct_scatter_proj_data_info_sptr); - - // interpolate projdata - interpolate_projdata_pull(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); - - // Perform Inverse Single Slice Rebinning - inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); - -} - -void -ScatterEstimation:: -push_scatter_estimate(ProjData& scaled_scatter_proj_data, - const ProjData& emission_proj_data, - const ProjData& scatter_proj_data, - const bool remove_interleaving) -{ - - shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); - - - info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); - ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), - interpolated_direct_scatter_proj_data_info_sptr); - - - interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); - std::cerr << "PUSH.." << '\n'; - // Perform Inverse Single Slice Rebinning - inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); - -} - - -END_NAMESPACE_STIR From 1a84a34680bcaab351550c04884f979173357a77 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 12:57:26 +0100 Subject: [PATCH 086/274] unit test ok --- src/buildblock/interpolate_projdata.cxx | 3 +- src/test/test_upsample.cxx | 75 +++++++++++-------------- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 4e738925b1..0ca2d51ba5 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -547,7 +547,6 @@ interpolate_projdata_pull(ProjData& proj_data_out, std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; } @@ -566,7 +565,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, extended[z][y][old_max+1] = extended[z][y][old_max]; } } - + std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index cc4297d4c3..47a9cdd12b 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -53,48 +53,38 @@ run_tests() { std::cout << "-------- Testing Upsampling and Downsampling --------\n"; - //creating scanner shared pointer - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); - - //creating proj data info - shared_ptr proj_data_info_sptr - (ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span*/1, 1,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ true) - ); - - //creating low resolution proj data info - shared_ptr LR_proj_data_info_sptr - (ProjDataInfo::ProjDataInfoCTI(scanner_sptr, - /*span*/1, 1,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ true) - ); - shared_ptr exam_info_sptr(new ExamInfo); - - - // construct projdata with filling to 0 - ProjDataInMemory proj_data(exam_info_sptr, proj_data_info_sptr); - { - Sinogram sinogram = proj_data.get_sinogram(0,0); - check_if_equal(sinogram.find_min(), - 0.F, - "test constructor and get_sinogram"); - } - - //std::cout << "TEST: 3D out size:"<< proj_data.get_num_segments() << "x"<< proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; - proj_data.fill(1); + shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + shared_ptr exam_info_sptr(new ExamInfo); + shared_ptr LR_exam_info_sptr(new ExamInfo); + + //creating proj data info + shared_ptr proj_data_info_sptr + (ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ false)); + + //creating low resolution proj data info + shared_ptr LR_proj_data_info_sptr + (ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ false)); - // construct projdata with filling to 5 - ProjDataInMemory proj_data_LR(exam_info_sptr, LR_proj_data_info_sptr); - { - Sinogram sinogram_LR = proj_data_LR.get_sinogram(0,0); - check_if_equal(sinogram_LR.find_min(), - 0.F, - "test constructor and get_sinogram"); - } - proj_data_LR.fill(1); - //std::cout << "TEST: 3D LR size:"<< proj_data_LR.get_num_segments() << "x"<< proj_data_LR.get_segment_by_sinogram(0).get_num_views()<< "x" << proj_data_LR.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + // construct projdata + ProjDataInMemory proj_data(exam_info_sptr, proj_data_info_sptr); + { + Sinogram sinogram = proj_data.get_sinogram(0,0); + check_if_equal(sinogram.find_min(),0.F,"test constructor and get_sinogram"); + } + // construct LR projdata + ProjDataInMemory LR_proj_data(LR_exam_info_sptr, LR_proj_data_info_sptr); + { + Sinogram LR_sinogram = LR_proj_data.get_sinogram(0,0); + check_if_equal(LR_sinogram.find_min(), 0.F, "test constructor and get_sinogram"); + } + + proj_data.fill(1); + LR_proj_data.fill(1); + std::cout << "TEST: 3D size:"<< proj_data.get_num_segments() << "x"<< proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; +std::cout << "TEST LR: 3D size:"<< LR_proj_data.get_num_segments() << "x"<< LR_proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << LR_proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; ProjDataInMemory scaled_proj_data = proj_data; scaled_proj_data.fill(1); @@ -102,12 +92,13 @@ run_tests() //std::cout << "TEST: 3D scaled size:"<< scaled_proj_data.get_num_segments() << "x"<< scaled_proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; std::cout << "-------- Testing Pull --------\n"; - ScatterEstimation::pull_scatter_estimate(scaled_proj_data,proj_data,proj_data_LR,false); + ScatterEstimation::pull_scatter_estimate(scaled_proj_data,proj_data,LR_proj_data,true); + std::cout << "-------- Testing Push --------\n"; - ProjDataInMemory scaled_proj_data_LR = proj_data_LR; - scaled_proj_data_LR.fill(1); - ScatterEstimation::push_scatter_estimate(scaled_proj_data_LR,proj_data_LR,scaled_proj_data,false); + ProjDataInMemory LR_scaled_proj_data = LR_proj_data; + LR_scaled_proj_data.fill(1); + ScatterEstimation::push_scatter_estimate(LR_scaled_proj_data,LR_proj_data,scaled_proj_data,true); //std::cout << "TEST: 3D downsampled size:"<< scaled_proj_data_LR.get_num_segments() << "x"<< scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; From aeac36b78c792573dec36b4010998dfcaa776b4e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 16:18:28 +0100 Subject: [PATCH 087/274] interleaving ok --- src/buildblock/interpolate_projdata.cxx | 45 ++++++++++++------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 0ca2d51ba5..568128a675 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -110,27 +110,29 @@ namespace detail_interpolate_projdata assert(out_sinogram.get_min_view_num() == 0); assert(in_sinogram.get_min_view_num() == 0); - assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()*2); + assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()*2); //check that the views are dowbled assert(in_sinogram.get_segment_num() == 0); assert(out_sinogram.get_segment_num() == 0); - const int in_num_views = in_sinogram.get_num_views(); + const int in_num_views = in_sinogram.get_num_views(); //number of views of the input sinogram - for (int view_num = out_sinogram.get_min_view_num(); + for (int view_num = out_sinogram.get_min_view_num(); //output sinogram should have the double number of views view_num <= out_sinogram.get_max_view_num(); ++view_num) { // TODO don't put in outer tangential poss for now to avoid boundary stuff - for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; + //std::cerr<< "CHECK" << 24%12 << '\n'; + for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; //skip boundaries tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; ++tangential_pos_num) { + // here we're filling a bigger grid. if ((view_num+tangential_pos_num)%2 == 0) { const int in_view_num = view_num%2==0 ? view_num/2 : (view_num+1)/2; out_sinogram[view_num][tangential_pos_num] = - in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; + in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; //filling with the input } else { @@ -176,36 +178,31 @@ namespace detail_interpolate_projdata assert(in_sinogram.get_segment_num() == 0); assert(out_sinogram.get_segment_num() == 0); + if (out_sinogram.get_num_views() != in_sinogram.get_num_views()/2) + error("views need to be reduced of a factor 2"); + const int in_num_views = in_sinogram.get_num_views(); + const int out_num_views = out_sinogram.get_num_views(); - for (int view_num = out_sinogram.get_min_view_num(); - view_num <= out_sinogram.get_max_view_num(); + for (int view_num = in_sinogram.get_min_view_num(); + view_num <= in_sinogram.get_max_view_num(); ++view_num) { // TODO don't put in outer tangential poss for now to avoid boundary stuff - for (int tangential_pos_num = out_sinogram.get_min_tangential_pos_num()+1; - tangential_pos_num <= out_sinogram.get_max_tangential_pos_num()-1; + for (int tangential_pos_num = in_sinogram.get_min_tangential_pos_num(); + tangential_pos_num <= in_sinogram.get_max_tangential_pos_num(); ++tangential_pos_num) { - if ((view_num+tangential_pos_num)%2 == 0) + // here i need to take the bigger grid an + if ((view_num+tangential_pos_num)%2 == 0) //if it's even { - const int in_view_num = + const int out_view_num = view_num%2==0 ? view_num/2 : (view_num+1)/2; - out_sinogram[view_num][tangential_pos_num] = - in_sinogram[in_view_num%in_num_views][(in_view_num>=in_num_views? -1: 1)*tangential_pos_num]; + out_sinogram[out_view_num%out_num_views][(out_view_num>=out_num_views? -1: 1)*tangential_pos_num] = + in_sinogram[view_num][tangential_pos_num]; } - else - { - const int next_in_view = view_num/2+1; - const int other_in_view = (view_num+1)/2; - out_sinogram[view_num][tangential_pos_num] = - (in_sinogram[view_num/2][tangential_pos_num] + - in_sinogram[next_in_view%in_num_views][(next_in_view>=in_num_views ? -1 : 1)*tangential_pos_num] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num-1)] + - in_sinogram[other_in_view%in_num_views][(other_in_view>=in_num_views ? -1 : 1)*(tangential_pos_num+1)] - )/4 + in_sinogram[view_num][tangential_pos_num]; //contribution to itself; - } + } } } From f55294d3a59056c3657b52d6715290318f32f4cf Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 16:35:53 +0100 Subject: [PATCH 088/274] boundary --- src/buildblock/interpolate_projdata.cxx | 2 ++ src/include/stir/numerics/sampling_functions.h | 3 +++ src/include/stir/numerics/sampling_functions.inl | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 568128a675..d90da7bd36 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -673,6 +673,8 @@ interpolate_projdata_push(ProjData& proj_data_out, } } + + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments // ===========================PUSH ================================== diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index e23e54831f..0f2eb155ed 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -70,6 +70,9 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, const Array<3,elemT>& in, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step); +template +inline +void set_pull_boundary_conditions(Array<3,elemT>& out); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 9bb751e862..15f6ecd80b 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -99,8 +99,14 @@ void sample_function_on_regular_grid_pull(Array<3,elemT>& out, relative_positions); } } + set_pull_boundary_conditions(out); } +template +void set_pull_boundary_conditions(Array<3,elemT>& out) +{ + std::cout<< "I'm here" << '\n'; +} template void sample_function_on_regular_grid_push(Array<3,elemT>& out, From 3eaec61499b3724d5bad7fa62c35b2350f01dfdd Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 28 Jun 2019 23:14:48 +0100 Subject: [PATCH 089/274] check views --- src/buildblock/extend_projdata.cxx | 2 +- .../stir/numerics/sampling_functions.h | 10 +++- .../stir/numerics/sampling_functions.inl | 59 ++++++++++++++++++- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 0275174161..c3e52e4ca5 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -157,7 +157,7 @@ namespace detail for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) { input_compressed_view[view_num]=sino_segment[view_num]; //here we cut everything bigger than max_in and smaller than min_in - input_compressed_view[min_in[1]]=input_compressed_view[min_in[1]+1]; + //input_compressed_view[min_in[1]]=input_compressed_view[min_in[1]+1]; } // loop over views diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index 0f2eb155ed..58c9b91eef 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -72,7 +72,15 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, const BasicCoordinate<3, positionT>& step); template inline -void set_pull_boundary_conditions(Array<3,elemT>& out); +void axial_position_boundary_conditions(Array<3,elemT>& out); + +template +inline +void views_position_boundary_conditions(Array<3,elemT>& out); + +template +inline +void tan_position_boundary_conditions(Array<3,elemT>& out); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 15f6ecd80b..3ddf071dd1 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -99,13 +99,63 @@ void sample_function_on_regular_grid_pull(Array<3,elemT>& out, relative_positions); } } - set_pull_boundary_conditions(out); + axial_position_boundary_conditions(out); } template -void set_pull_boundary_conditions(Array<3,elemT>& out) +void axial_position_boundary_conditions(Array<3,elemT>& array) { - std::cout<< "I'm here" << '\n'; + // boundary contitions for the axial position + + for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) + { + for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) + { + const int min = array.get_min_index(); + const int max = array.get_max_index(); + array[min][i][j]=array[min+1][i][j]; + array[max][i][j]=array[max-1][i][j]; + //std::cerr< +void views_boundary_conditions(Array<3,elemT>& array) +{ + // boundary contitions for the axial position + + for (int i=array.get_min_index(); i<= array.get_max_index(); ++i) + { + for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) + { + const int min = array[0].get_min_index(); + const int max = array[0].get_max_index(); + array[i][min][j]=array[i][min+1][j]; + //array[i][max][j]=array[i][max-1][j]; + //std::cerr< +void tan_position_boundary_conditions(Array<3,elemT>& array) +{ + // boundary contitions for the axial position + + for (int i=array.get_min_index(); i<= array.get_max_index(); ++i) + { + for (int j=array[0].get_min_index(); j<= array[0].get_max_index(); ++j) + { + const int min = array[0][0].get_min_index(); + const int max = array[0][0].get_max_index(); + array[i][j][min]=array[i][j][min+1]; + array[i][j][max]=array[i][j][max-1]; + //std::cerr< @@ -146,6 +196,9 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, } } out*=(step[1]*step[2]*step[3]); //very important + axial_position_boundary_conditions(out); + tan_position_boundary_conditions(out); + views_boundary_conditions(out); } From c7550f51e36a7abca41e519c9249b82bfdfd281e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sun, 30 Jun 2019 10:52:27 +0100 Subject: [PATCH 090/274] ok --- src/buildblock/interpolate_projdata.cxx | 3 +-- src/include/stir/numerics/sampling_functions.inl | 8 ++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index d90da7bd36..93756ee283 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -201,8 +201,6 @@ namespace detail_interpolate_projdata out_sinogram[out_view_num%out_num_views][(out_view_num>=out_num_views? -1: 1)*tangential_pos_num] = in_sinogram[view_num][tangential_pos_num]; } - - } } } @@ -565,6 +563,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); + //axial_position_boundary_conditions(sino_3D_out); proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 3ddf071dd1..b680e06297 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -99,7 +99,6 @@ void sample_function_on_regular_grid_pull(Array<3,elemT>& out, relative_positions); } } - axial_position_boundary_conditions(out); } template @@ -132,8 +131,8 @@ void views_boundary_conditions(Array<3,elemT>& array) { const int min = array[0].get_min_index(); const int max = array[0].get_max_index(); - array[i][min][j]=array[i][min+1][j]; - //array[i][max][j]=array[i][max-1][j]; + array[i][0][j]=100; + array[i][max][j]=array[i][max-1][j]; //std::cerr<& out, } } out*=(step[1]*step[2]*step[3]); //very important - axial_position_boundary_conditions(out); - tan_position_boundary_conditions(out); - views_boundary_conditions(out); } From 6657a2ff859faa3debf3206f9db05086019d8077 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sun, 30 Jun 2019 11:23:50 +0100 Subject: [PATCH 091/274] func --- src/buildblock/interpolate_projdata.cxx | 74 ++----------------- .../stir/numerics/sampling_functions.h | 19 ++++- .../stir/numerics/sampling_functions.inl | 70 ++++++++++-------- 3 files changed, 62 insertions(+), 101 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 93756ee283..29596e62c4 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -525,19 +525,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, proj_data_in.get_segment_by_sinogram(0)); std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; - Array<3,float> extended = - extend_segment_in_views(non_interleaved_segment, 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); + extend_tangential_position(extended); std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); @@ -549,21 +538,10 @@ interpolate_projdata_pull(ProjData& proj_data_out, { Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } + extend_tangential_position(extended); std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); - //axial_position_boundary_conditions(sino_3D_out); proj_data_out.set_segment(sino_3D_out); if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; @@ -659,19 +637,7 @@ interpolate_projdata_push(ProjData& proj_data_out, proj_data_out.get_segment_by_sinogram(0)); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - - } - } - + extend_tangential_position(extended); std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -685,15 +651,7 @@ interpolate_projdata_push(ProjData& proj_data_out, SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended d Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) - { - for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) - { - const int old_min = out[z][y].get_min_index(); - const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); //resize - } - } + transpose_extend_tangential_position(out); std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================TRANSPOSE REMOVE INTERLEAVING ==================== @@ -717,17 +675,7 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== RESIZE 'EXTENDED' OUTPUT ========================= Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); - for (int z=extended.get_min_index(); z<= extended.get_max_index(); ++z) - { - for (int y=extended[z].get_min_index(); y<= extended[z].get_max_index(); ++y) - { - const int old_min = extended[z][y].get_min_index(); - const int old_max = extended[z][y].get_max_index(); - extended[z][y].grow(old_min-1, old_max+1); - extended[z][y][old_min-1] = extended[z][y][old_min]; - extended[z][y][old_max+1] = extended[z][y][old_max]; - } - } + extend_tangential_position(extended); std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); @@ -742,15 +690,7 @@ interpolate_projdata_push(ProjData& proj_data_out, std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - for (int z=out.get_min_index(); z<= out.get_max_index(); ++z) - { - for (int y=out[z].get_min_index(); y<= out[z].get_max_index(); ++y) - { - const int old_min = out[z][y].get_min_index(); - const int old_max = out[z][y].get_max_index(); - out[z][y].grow(old_min+1, old_max-1); //resize - } - } + transpose_extend_tangential_position(out); std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // ======================== CREATE OUTPUT ============================= diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index 58c9b91eef..1430714f4f 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -70,17 +70,30 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, const Array<3,elemT>& in, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step); -template +/*template inline void axial_position_boundary_conditions(Array<3,elemT>& out); template inline -void views_position_boundary_conditions(Array<3,elemT>& out); +void views_position_boundary_conditions(Array<3,elemT>& out);*/ + +template +inline +void extend_tangential_position(Array<3,elemT>& out); + +template +inline +void transpose_extend_tangential_position(Array<3,elemT>& out); + + +template +inline +void extend_axial_position(Array<3,elemT>& out); template inline -void tan_position_boundary_conditions(Array<3,elemT>& out); +void transpose_extend_axial_position(Array<3,elemT>& out); END_NAMESPACE_STIR diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index b680e06297..2cbe2c61af 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -101,62 +101,70 @@ void sample_function_on_regular_grid_pull(Array<3,elemT>& out, } } + template -void axial_position_boundary_conditions(Array<3,elemT>& array) +void extend_tangential_position(Array<3,elemT>& array) { - // boundary contitions for the axial position - - for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) - { - for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) + for (int z=array.get_min_index(); z<= array.get_max_index(); ++z) + { + for (int y=array[z].get_min_index(); y<= array[z].get_max_index(); ++y) { - const int min = array.get_min_index(); - const int max = array.get_max_index(); - array[min][i][j]=array[min+1][i][j]; - array[max][i][j]=array[max-1][i][j]; - //std::cerr< -void views_boundary_conditions(Array<3,elemT>& array) +void transpose_extend_tangential_position(Array<3,elemT>& array) { - // boundary contitions for the axial position + for (int z=array.get_min_index(); z<= array.get_max_index(); ++z) + { + for (int y=array[z].get_min_index(); y<= array[z].get_max_index(); ++y) + { + const int old_min = array[z][y].get_min_index(); + const int old_max = array[z][y].get_max_index(); + array[z][y].grow(old_min+1, old_max-1); //resize + } + } +} + + - for (int i=array.get_min_index(); i<= array.get_max_index(); ++i) +template +void extend_axial_position(Array<3,elemT>& array) +{ + for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) { for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { - const int min = array[0].get_min_index(); - const int max = array[0].get_max_index(); - array[i][0][j]=100; - array[i][max][j]=array[i][max-1][j]; - //std::cerr< -void tan_position_boundary_conditions(Array<3,elemT>& array) +void transpose_extend_axial_position(Array<3,elemT>& array) { - // boundary contitions for the axial position - - for (int i=array.get_min_index(); i<= array.get_max_index(); ++i) + for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) { - for (int j=array[0].get_min_index(); j<= array[0].get_max_index(); ++j) + for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { - const int min = array[0][0].get_min_index(); - const int max = array[0][0].get_max_index(); - array[i][j][min]=array[i][j][min+1]; - array[i][j][max]=array[i][j][max-1]; - //std::cerr< void sample_function_on_regular_grid_push(Array<3,elemT>& out, const Array<3,elemT>& in, From 0791203805dbb31eeccbfe7707c8b88c3cfb5cc5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sun, 30 Jun 2019 21:53:54 +0100 Subject: [PATCH 092/274] axial --- src/buildblock/interpolate_projdata.cxx | 2 +- .../stir/numerics/sampling_functions.inl | 32 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 29596e62c4..aef4742e73 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -690,7 +690,7 @@ interpolate_projdata_push(ProjData& proj_data_out, std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - transpose_extend_tangential_position(out); + transpose_extend_tangential_position(out); std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // ======================== CREATE OUTPUT ============================= diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 2cbe2c61af..bde1bab29d 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -138,15 +138,18 @@ void transpose_extend_tangential_position(Array<3,elemT>& array) template void extend_axial_position(Array<3,elemT>& array) { - for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) + for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) { for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { const int old_min = array.get_min_index(); const int old_max = array.get_max_index(); - array.grow(old_min-1, old_max+1)[i][j]; - array[old_min-1][i] = array[old_min][i][j]; - array[old_max+1][j] = array[old_max][i][j]; + //std::cout << old_min <<"," << old_max <<'\n'; + + array[i][j].grow(old_min-1,old_max+1); + std::cout << array.get_min_index() <<"," << array.get_max_index() <<'\n'; + //array[old_min-1][i][j] = array[old_min][i][j]; + //array[old_max+1][j][j] = array[old_max][i][j]; } } } @@ -156,14 +159,19 @@ template void transpose_extend_axial_position(Array<3,elemT>& array) { for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) - { - for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) - { - const int old_min = array.get_min_index(); - const int old_max = array.get_max_index(); - array.grow(old_min+1, old_max-1)[i][j]; //resize - } - } + { + for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) + { + const int old_min = array.get_min_index(); + const int old_max = array.get_max_index(); + //std::cout << old_min <<"," << old_max <<'\n'; + + array[i][j].grow(old_min+1,old_max-1); + //std::cout << array.get_min_index() <<"," << array.get_max_index() <<'\n'; + //array[old_min-1][i][j] = array[old_min][i][j]; + //array[old_max+1][j][j] = array[old_max][i][j]; + } + } } template void sample_function_on_regular_grid_push(Array<3,elemT>& out, From 8f48df6bf8a548d17864869d4640b05cdd661fda Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sun, 30 Jun 2019 23:18:59 +0100 Subject: [PATCH 093/274] axial ok --- src/buildblock/interpolate_projdata.cxx | 9 +++- .../stir/numerics/sampling_functions.inl | 53 +++++++++---------- src/test/test_upsample.cxx | 15 +++++- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index aef4742e73..732a324b13 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -638,6 +638,8 @@ interpolate_projdata_push(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); extend_tangential_position(extended); + extend_axial_position(extended); + // std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -648,10 +650,11 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== + transpose_extend_axial_position(extended); + transpose_extend_tangential_position(extended); SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended d Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - transpose_extend_tangential_position(out); std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================TRANSPOSE REMOVE INTERLEAVING ==================== @@ -676,6 +679,7 @@ interpolate_projdata_push(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); extend_tangential_position(extended); + extend_axial_position(extended); std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); @@ -685,12 +689,13 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== + transpose_extend_axial_position(extended); + transpose_extend_tangential_position(extended); shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - transpose_extend_tangential_position(out); std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // ======================== CREATE OUTPUT ============================= diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index bde1bab29d..639774e2f7 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -138,40 +138,37 @@ void transpose_extend_tangential_position(Array<3,elemT>& array) template void extend_axial_position(Array<3,elemT>& array) { - for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) - { - for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) - { - const int old_min = array.get_min_index(); - const int old_max = array.get_max_index(); - //std::cout << old_min <<"," << old_max <<'\n'; - - array[i][j].grow(old_min-1,old_max+1); - std::cout << array.get_min_index() <<"," << array.get_max_index() <<'\n'; - //array[old_min-1][i][j] = array[old_min][i][j]; - //array[old_max+1][j][j] = array[old_max][i][j]; - } - } + + BasicCoordinate<3,int> min, max; + + min[1]=array.get_min_index()-1; + max[1]=array.get_max_index()+1; + min[2]=array[0].get_min_index();; + max[2]=array[0].get_max_index();; + min[3]=array[0][0].get_min_index(); + max[3]=array[0][0].get_max_index(); + + array.grow(IndexRange<3>(min, max)); + + } + + template void transpose_extend_axial_position(Array<3,elemT>& array) { - for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) - { - for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) - { - const int old_min = array.get_min_index(); - const int old_max = array.get_max_index(); - //std::cout << old_min <<"," << old_max <<'\n'; - - array[i][j].grow(old_min+1,old_max-1); - //std::cout << array.get_min_index() <<"," << array.get_max_index() <<'\n'; - //array[old_min-1][i][j] = array[old_min][i][j]; - //array[old_max+1][j][j] = array[old_max][i][j]; - } - } + BasicCoordinate<3,int> min, max; + + min[1]=array.get_min_index()+1; + max[1]=array.get_max_index()-1; + min[2]=array[0].get_min_index();; + max[2]=array[0].get_max_index();; + min[3]=array[0][0].get_min_index(); + max[3]=array[0][0].get_max_index(); + array.grow(IndexRange<3>(min, max)); + } template void sample_function_on_regular_grid_push(Array<3,elemT>& out, diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 47a9cdd12b..64def8aee7 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -89,7 +89,7 @@ std::cout << "TEST LR: 3D size:"<< LR_proj_data.get_num_segments() << "x"<< LR_ ProjDataInMemory scaled_proj_data = proj_data; scaled_proj_data.fill(1); - //std::cout << "TEST: 3D scaled size:"<< scaled_proj_data.get_num_segments() << "x"<< scaled_proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + //std::cout << "TEST: g scaled size:"<< scaled_proj_data.get_num_segments() << "x"<< scaled_proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; std::cout << "-------- Testing Pull --------\n"; ScatterEstimation::pull_scatter_estimate(scaled_proj_data,proj_data,LR_proj_data,true); @@ -100,6 +100,19 @@ std::cout << "TEST LR: 3D size:"<< LR_proj_data.get_num_segments() << "x"<< LR_ LR_scaled_proj_data.fill(1); ScatterEstimation::push_scatter_estimate(LR_scaled_proj_data,LR_proj_data,scaled_proj_data,true); + SegmentBySinogram array = LR_scaled_proj_data.get_segment_by_sinogram(0); + + BasicCoordinate<3,int> min, max; + + min[1]=array.get_min_index()-1; + max[1]=array.get_max_index()+1; + min[2]=array[0].get_min_index();; + max[2]=array[0].get_max_index();; + min[3]=array[0][0].get_max_index(); + max[3]=array[0][0].get_max_index(); + array.grow(IndexRange<3>(min, max)); + + std::cout << min[1] <<"," << max[1] <<'\n'; //std::cout << "TEST: 3D downsampled size:"<< scaled_proj_data_LR.get_num_segments() << "x"<< scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; } From 4e882ab4f5a0f37ca405de9246e022a9f9db4732 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sun, 30 Jun 2019 23:41:20 +0100 Subject: [PATCH 094/274] fine okk --- src/buildblock/interpolate_projdata.cxx | 10 ++++++---- src/include/stir/numerics/sampling_functions.inl | 11 +++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 732a324b13..de38053536 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -527,7 +527,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); extend_tangential_position(extended); - + extend_axial_position(extended); std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); proj_data_out.set_segment(sino_3D_out); @@ -539,6 +539,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); extend_tangential_position(extended); + extend_axial_position(extended); std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); @@ -636,9 +637,10 @@ interpolate_projdata_push(ProjData& proj_data_out, const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_out.get_segment_by_sinogram(0)); - Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); - extend_tangential_position(extended); - extend_axial_position(extended); + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //extend the views + extend_tangential_position(extended); //extend the tangential positions + extend_axial_position(extended); //extend the axial positions + // diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 639774e2f7..6f3a45aea7 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -150,6 +150,17 @@ void extend_axial_position(Array<3,elemT>& array) array.grow(IndexRange<3>(min, max)); + for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) + { + for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) + { + const int min = array.get_min_index(); + const int max = array.get_max_index(); + array[min][i][j]=array[min+1][i][j]; + array[max][i][j]=array[max-1][i][j]; + //std::cerr< Date: Mon, 1 Jul 2019 11:08:27 +0100 Subject: [PATCH 095/274] cleaned --- src/buildblock/interpolate_projdata.cxx | 143 +++++++++--------- .../stir/numerics/sampling_functions.inl | 1 - 2 files changed, 68 insertions(+), 76 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index de38053536..b3402a0295 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -511,39 +511,35 @@ interpolate_projdata_pull(ProjData& proj_data_out, step[3]= out_sampling_s/in_sampling_s; - // initialise interpolator if (remove_interleaving) { + shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_in_info); - - shared_ptr non_interleaved_proj_data_info_sptr = - make_non_interleaved_proj_data_info(proj_data_in_info); - - const SegmentBySinogram non_interleaved_segment = - make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_in.get_segment_by_sinogram(0)); + const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; - Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); - extend_tangential_position(extended); - extend_axial_position(extended); + + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //here we are doubling the number of views + extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) + extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); - proj_data_out.set_segment(sino_3D_out); + + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation + proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; } else { - Array<3,float> extended = - extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); - extend_tangential_position(extended); - extend_axial_position(extended); + Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views + extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) + extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); - proj_data_out.set_segment(sino_3D_out); + + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation + proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; @@ -631,82 +627,79 @@ interpolate_projdata_push(ProjData& proj_data_out, if (remove_interleaving) { - // =================== RESIZE 'EXTENDED' OUTPUT ========================= shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_out_info); - const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, - proj_data_out.get_segment_by_sinogram(0)); + const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_out.get_segment_by_sinogram(0)); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //extend the views extend_tangential_position(extended); //extend the tangential positions extend_axial_position(extended); //extend the axial positions - // + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments + // ===========================PUSH ================================== - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments - // ===========================PUSH ================================== + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + // =================== TRANSPOSE EXTENDED =========================== - // =================== TRANSPOSE EXTENDED =========================== + transpose_extend_axial_position(extended); //reduce axial positions + transpose_extend_tangential_position(extended); //reduce tangential positions + SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended d + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + // =================TRANSPOSE REMOVE INTERLEAVING ==================== - transpose_extend_axial_position(extended); - transpose_extend_tangential_position(extended); - SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended d - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // =================TRANSPOSE REMOVE INTERLEAVING ==================== + SegmentBySinogram compressed_output(out, non_interleaved_proj_data_info_sptr, 0); + std::cout<<"NON-INTERLEAVED:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - SegmentBySinogram compressed_output(out, non_interleaved_proj_data_info_sptr, 0); - std::cout<<"NON-INTERLEAVED:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + shared_ptr new_proj_data_info_sptr = proj_data_out_info.create_shared_clone(); + SegmentBySinogram transpose_interleaved_segment = transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, compressed_output); - shared_ptr new_proj_data_info_sptr = proj_data_out_info.create_shared_clone(); - SegmentBySinogram transpose_interleaved_segment = transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, compressed_output); + std::cout<<"FINAL:" << transpose_interleaved_segment.get_num_views() << "x" << transpose_interleaved_segment.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - //std::cout<<"VIEWS - BEFORE:" << compressed_output.get_num_views() << '\n'; - //std::cout<<"VIEWS - AFTER:" << transpose_interleaved_segment.get_num_views() << '\n'; - std::cout<<"FINAL:" << transpose_interleaved_segment.get_num_views() << "x" << transpose_interleaved_segment.get_num_tangential_poss() << '\n'; - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - // ======================== CREATE OUTPUT ============================= - proj_data_out.set_segment(transpose_interleaved_segment); - if (proj_data_out.set_segment(transpose_interleaved_segment) == Succeeded::no) - return Succeeded::no; + // ======================== CREATE OUTPUT ============================= + proj_data_out.set_segment(transpose_interleaved_segment); + if (proj_data_out.set_segment(transpose_interleaved_segment) == Succeeded::no) + return Succeeded::no; } else { // =================== RESIZE 'EXTENDED' OUTPUT ========================= - Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); - extend_tangential_position(extended); - extend_axial_position(extended); - - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); - // ===========================PUSH ================================== - - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - - // =================== TRANSPOSE EXTENDED =========================== - - transpose_extend_axial_position(extended); - transpose_extend_tangential_position(extended); - shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf - SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // ======================== CREATE OUTPUT ============================= - - SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) - return Succeeded::no; + Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); //extend the views + extend_tangential_position(extended); //extend the tangential positions + extend_axial_position(extended); //extend the axial positions + + std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); + + // ===========================PUSH ================================== + + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + + // =================== TRANSPOSE EXTENDED =========================== + + transpose_extend_axial_position(extended); + transpose_extend_tangential_position(extended); + shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf + SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended + std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + + // ======================== CREATE OUTPUT ============================= + + SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); + std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + return Succeeded::no; } diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 6f3a45aea7..700aa432fd 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -158,7 +158,6 @@ void extend_axial_position(Array<3,elemT>& array) const int max = array.get_max_index(); array[min][i][j]=array[min+1][i][j]; array[max][i][j]=array[max-1][i][j]; - //std::cerr< Date: Mon, 1 Jul 2019 11:50:34 +0100 Subject: [PATCH 096/274] ok --- .../stir/numerics/sampling_functions.inl | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 700aa432fd..5622adcfaa 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -102,6 +102,46 @@ void sample_function_on_regular_grid_pull(Array<3,elemT>& out, } +template +void sample_function_on_regular_grid_push(Array<3,elemT>& out, + const Array<3,elemT>& in, + const BasicCoordinate<3, positionT>& offset, + const BasicCoordinate<3, positionT>& step) +{ + BasicCoordinate<3,int> min_in, max_in; + IndexRange<3> in_range = in.get_index_range(); + if (!in_range.get_regular_range(min_in,max_in)) + warning("Output must be regular range!"); + + BasicCoordinate<3, int> index_in; + BasicCoordinate<3, positionT> relative_positions; + index_in[1]=min_in[1]; + relative_positions[1]= index_in[1] *step[1] - offset[1] ; + const BasicCoordinate<3, positionT> max_relative_positions= + (BasicCoordinate<3,positionT>(max_in)+static_cast(.001)) * step + offset; + for (; + index_in[1]<=max_in[1] && relative_positions[1]<=max_relative_positions[1]; + ++index_in[1], relative_positions[1]+= step[1]) + { + index_in[2]=min_in[2]; + relative_positions[2]= index_in[2] * step[2] + offset[2] ; + for (; + index_in[2]<=max_in[2] && relative_positions[2]<=max_relative_positions[2]; + ++index_in[2], relative_positions[2]+= step[2]) + { + index_in[3]=min_in[3]; + relative_positions[3]= index_in[3] * step[3] + offset[3] ; + for (; + index_in[3]<=max_in[3] && relative_positions[3]<=max_relative_positions[3]; + ++index_in[3], relative_positions[3]+= step[3]) + push_transpose_linear_interpolate(out, + relative_positions, + in[index_in]); + } + } + out*=(step[1]*step[2]*step[3]); //very important +} + template void extend_tangential_position(Array<3,elemT>& array) { @@ -178,47 +218,5 @@ void transpose_extend_axial_position(Array<3,elemT>& array) min[3]=array[0][0].get_min_index(); max[3]=array[0][0].get_max_index(); array.grow(IndexRange<3>(min, max)); - } -template -void sample_function_on_regular_grid_push(Array<3,elemT>& out, - const Array<3,elemT>& in, - const BasicCoordinate<3, positionT>& offset, - const BasicCoordinate<3, positionT>& step) -{ - BasicCoordinate<3,int> min_in, max_in; - IndexRange<3> in_range = in.get_index_range(); - if (!in_range.get_regular_range(min_in,max_in)) - warning("Output must be regular range!"); - - BasicCoordinate<3, int> index_in; - BasicCoordinate<3, positionT> relative_positions; - index_in[1]=min_in[1]; - relative_positions[1]= index_in[1] *step[1] - offset[1] ; - const BasicCoordinate<3, positionT> max_relative_positions= - (BasicCoordinate<3,positionT>(max_in)+static_cast(.001)) * step + offset; - for (; - index_in[1]<=max_in[1] && relative_positions[1]<=max_relative_positions[1]; - ++index_in[1], relative_positions[1]+= step[1]) - { - index_in[2]=min_in[2]; - relative_positions[2]= index_in[2] * step[2] + offset[2] ; - for (; - index_in[2]<=max_in[2] && relative_positions[2]<=max_relative_positions[2]; - ++index_in[2], relative_positions[2]+= step[2]) - { - index_in[3]=min_in[3]; - relative_positions[3]= index_in[3] * step[3] + offset[3] ; - for (; - index_in[3]<=max_in[3] && relative_positions[3]<=max_relative_positions[3]; - ++index_in[3], relative_positions[3]+= step[3]) - push_transpose_linear_interpolate(out, - relative_positions, - in[index_in]); - } - } - out*=(step[1]*step[2]*step[3]); //very important -} - - END_NAMESPACE_STIR From 010709dff67ca8c2ba319644f0d8411041dcfbcc Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 1 Jul 2019 11:59:46 +0100 Subject: [PATCH 097/274] clean 2 --- src/buildblock/interpolate_projdata.cxx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index b3402a0295..58fb6182a2 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -514,9 +514,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, if (remove_interleaving) { - shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_in_info); - - const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); + shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_in_info); //create non interleaved projdata info + const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); //create non interleaved segment std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; @@ -635,18 +634,17 @@ interpolate_projdata_push(ProjData& proj_data_out, extend_tangential_position(extended); //extend the tangential positions extend_axial_position(extended); //extend the axial positions - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments // ===========================PUSH ================================== + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); //reduce axial positions transpose_extend_tangential_position(extended); //reduce tangential positions - SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended d + SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; @@ -675,10 +673,10 @@ interpolate_projdata_push(ProjData& proj_data_out, extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); // ===========================PUSH ================================== + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== From 77b60759f41742c70dc9b4a37570580ca3b99516 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 2 Jul 2019 10:34:07 +0100 Subject: [PATCH 098/274] test interpolator --- src/buildblock/interpolate_projdata.cxx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 58fb6182a2..ed9b5b9a70 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -537,7 +537,9 @@ interpolate_projdata_pull(ProjData& proj_data_out, std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation + // sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0) ; + sample_function_on_regular_grid_pull(sino_3D_out,sino_3D_in, offset, step); //pull interpolation proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; @@ -677,8 +679,8 @@ interpolate_projdata_push(ProjData& proj_data_out, // ===========================PUSH ================================== SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); - sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - + //sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); @@ -695,8 +697,11 @@ interpolate_projdata_push(ProjData& proj_data_out, SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; - proj_data_out.set_segment(compressed_output); - if (proj_data_out.set_segment(compressed_output) == Succeeded::no) +// proj_data_out.set_segment(compressed_output); + // if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + + proj_data_out.set_segment(sino_3D_out); + if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; } From 15dacc24cda7bdc267dea60a2ef757558ece722c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 2 Jul 2019 12:14:16 +0100 Subject: [PATCH 099/274] test1 --- src/buildblock/interpolate_projdata.cxx | 31 ++++++++++--------- .../stir/numerics/sampling_functions.h | 4 +-- .../stir/numerics/sampling_functions.inl | 19 ++++++++---- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index ed9b5b9a70..cfe63bc6b3 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -520,7 +520,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //here we are doubling the number of views - extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) + extend_tangential_position(extended,2,2); // here we are adding one tangential position before and after max and min index (for the interpolation) extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -532,14 +532,15 @@ interpolate_projdata_pull(ProjData& proj_data_out, else { Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views - extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) + extend_tangential_position(extended,1,1); // here we are adding one tangential position before and after max and min index (for the interpolation) extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - // sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0) ; - sample_function_on_regular_grid_pull(sino_3D_out,sino_3D_in, offset, step); //pull interpolation + sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation + // SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0) ; + //sample_function_on_regular_grid_pull(sino_3D_out,sino_3D_in, offset, step); //pull interpolation + //sino_3D_out.fill(1); proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; @@ -633,7 +634,7 @@ interpolate_projdata_push(ProjData& proj_data_out, const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_out.get_segment_by_sinogram(0)); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //extend the views - extend_tangential_position(extended); //extend the tangential positions + extend_tangential_position(extended,2,2); //extend the tangential positions extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -645,7 +646,7 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); //reduce axial positions - transpose_extend_tangential_position(extended); //reduce tangential positions + transpose_extend_tangential_position(extended,2,2); //reduce tangential positions SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; @@ -671,7 +672,7 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== RESIZE 'EXTENDED' OUTPUT ========================= Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); //extend the views - extend_tangential_position(extended); //extend the tangential positions + extend_tangential_position(extended,1,1); //extend the tangential positions extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -679,12 +680,12 @@ interpolate_projdata_push(ProjData& proj_data_out, // ===========================PUSH ================================== SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); - //sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); //here the output of the push is 'extended' + sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' + //sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); - transpose_extend_tangential_position(extended); + transpose_extend_tangential_position(extended,1,1); shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; @@ -697,11 +698,11 @@ interpolate_projdata_push(ProjData& proj_data_out, SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; -// proj_data_out.set_segment(compressed_output); - // if (proj_data_out.set_segment(compressed_output) == Succeeded::no) + proj_data_out.set_segment(compressed_output); + if (proj_data_out.set_segment(compressed_output) == Succeeded::no) - proj_data_out.set_segment(sino_3D_out); - if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) + // proj_data_out.set_segment(sino_3D_out); + // if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; } diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index 1430714f4f..301b5a13a0 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -80,11 +80,11 @@ void views_position_boundary_conditions(Array<3,elemT>& out);*/ template inline -void extend_tangential_position(Array<3,elemT>& out); +void extend_tangential_position(Array<3,elemT>& out,int min_ext, int max_ext); template inline -void transpose_extend_tangential_position(Array<3,elemT>& out); +void transpose_extend_tangential_position(Array<3,elemT>& out, int min_red, int max_red); template diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 5622adcfaa..08e4eda641 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -143,7 +143,7 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, } template -void extend_tangential_position(Array<3,elemT>& array) +void extend_tangential_position(Array<3,elemT>& array, int min_ext, int max_ext) { for (int z=array.get_min_index(); z<= array.get_max_index(); ++z) { @@ -151,16 +151,23 @@ void extend_tangential_position(Array<3,elemT>& array) { const int old_min = array[z][y].get_min_index(); const int old_max = array[z][y].get_max_index(); - array[z][y].grow(old_min-1, old_max+1); - array[z][y][old_min-1] = array[z][y][old_min]; - array[z][y][old_max+1] = array[z][y][old_max]; + array[z][y].grow(old_min-min_ext, old_max+max_ext); + for (int i = 0; i -void transpose_extend_tangential_position(Array<3,elemT>& array) +void transpose_extend_tangential_position(Array<3,elemT>& array, int min_red, int max_red) { for (int z=array.get_min_index(); z<= array.get_max_index(); ++z) { @@ -168,7 +175,7 @@ void transpose_extend_tangential_position(Array<3,elemT>& array) { const int old_min = array[z][y].get_min_index(); const int old_max = array[z][y].get_max_index(); - array[z][y].grow(old_min+1, old_max-1); //resize + array[z][y].grow(old_min+min_red, old_max-max_red); //resize } } } From dcab6873b9119611727c120324d4c7382b91d916 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 2 Jul 2019 23:38:28 +0100 Subject: [PATCH 100/274] interleaving ok --- src/buildblock/interpolate_projdata.cxx | 68 ++++++++++++------- .../stir/numerics/sampling_functions.inl | 4 +- .../numerics/more_interpolators.inl | 12 ++-- src/test/test_upsample.cxx | 14 ---- 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index cfe63bc6b3..15616462b1 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -45,6 +45,8 @@ #include "stir_experimental/numerics/more_interpolators.h" #include +#include "stir/IO/write_data.h" + START_NAMESPACE_STIR namespace detail_interpolate_projdata @@ -172,6 +174,7 @@ namespace detail_interpolate_projdata if (dynamic_cast(in_sinogram.get_proj_data_info_ptr()) == NULL) error("make_non_interleaved_proj_data is only appropriate for non-arccorrected data"); + // Sinogram& out_sinogram2 = out_sinogram.get_empty_copy(); assert(out_sinogram.get_min_view_num() == 0); assert(in_sinogram.get_min_view_num() == 0); assert(out_sinogram.get_num_views() == in_sinogram.get_num_views()/2); @@ -184,13 +187,13 @@ namespace detail_interpolate_projdata const int in_num_views = in_sinogram.get_num_views(); const int out_num_views = out_sinogram.get_num_views(); - for (int view_num = in_sinogram.get_min_view_num(); - view_num <= in_sinogram.get_max_view_num(); + for (int view_num = in_sinogram.get_min_view_num()+1; + view_num <= in_sinogram.get_max_view_num()-1; ++view_num) { // TODO don't put in outer tangential poss for now to avoid boundary stuff - for (int tangential_pos_num = in_sinogram.get_min_tangential_pos_num(); - tangential_pos_num <= in_sinogram.get_max_tangential_pos_num(); + for (int tangential_pos_num = in_sinogram.get_min_tangential_pos_num()+1; + tangential_pos_num <= in_sinogram.get_max_tangential_pos_num()-1; ++tangential_pos_num) { // here i need to take the bigger grid an @@ -198,9 +201,14 @@ namespace detail_interpolate_projdata { const int out_view_num = view_num%2==0 ? view_num/2 : (view_num+1)/2; - out_sinogram[out_view_num%out_num_views][(out_view_num>=out_num_views? -1: 1)*tangential_pos_num] = - in_sinogram[view_num][tangential_pos_num]; - } + out_sinogram[out_view_num%out_num_views][tangential_pos_num] += + in_sinogram[view_num][tangential_pos_num]+(in_sinogram[view_num-1][tangential_pos_num] + + in_sinogram[view_num+1][tangential_pos_num] + + in_sinogram[view_num][(tangential_pos_num-1)] + + in_sinogram[view_num][(tangential_pos_num+1)] + )/4; + } + } } } @@ -511,6 +519,9 @@ interpolate_projdata_pull(ProjData& proj_data_out, step[3]= out_sampling_s/in_sampling_s; + int ext_views = 2; + int ext_tan_pos = 1; + if (remove_interleaving) { @@ -518,29 +529,35 @@ interpolate_projdata_pull(ProjData& proj_data_out, const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); //create non interleaved segment std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; + std::fstream s; + open_write_binary(s, "noninterleaved.data"); + write_data(s,non_interleaved_segment); + s.close(); - Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //here we are doubling the number of views - extend_tangential_position(extended,2,2); // here we are adding one tangential position before and after max and min index (for the interpolation) + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, ext_views, ext_views); //here we are doubling the number of views + extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); // here we are adding one tangential position before and after max and min index (for the interpolation) extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - + open_write_binary(s, "extended_before_interopolation.data"); + write_data(s,extended); + s.close(); sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation + open_write_binary(s, "output.data"); + write_data(s,sino_3D_out); + s.close(); proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; } else { - Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views - extend_tangential_position(extended,1,1); // here we are adding one tangential position before and after max and min index (for the interpolation) + Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), ext_views, ext_views); //here we are extending the number of views + extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); // here we are adding one tangential position before and after max and min index (for the interpolation) extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation - // SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0) ; - //sample_function_on_regular_grid_pull(sino_3D_out,sino_3D_in, offset, step); //pull interpolation - //sino_3D_out.fill(1); proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; @@ -625,6 +642,8 @@ interpolate_projdata_push(ProjData& proj_data_out, step[3]= in_sampling_s/out_sampling_s; + int ext_views = 2; + int ext_tan_pos = 1; if (remove_interleaving) @@ -632,9 +651,8 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== RESIZE 'EXTENDED' OUTPUT ========================= shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_out_info); const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_out.get_segment_by_sinogram(0)); - - Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //extend the views - extend_tangential_position(extended,2,2); //extend the tangential positions + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, ext_views, ext_views); //extend the views + extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); //extend the tangential positions extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -646,9 +664,9 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); //reduce axial positions - transpose_extend_tangential_position(extended,2,2); //reduce tangential positions + transpose_extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); //reduce tangential positions SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,ext_views,ext_views); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================TRANSPOSE REMOVE INTERLEAVING ==================== @@ -671,25 +689,25 @@ interpolate_projdata_push(ProjData& proj_data_out, { // =================== RESIZE 'EXTENDED' OUTPUT ========================= - Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); //extend the views - extend_tangential_position(extended,1,1); //extend the tangential positions + Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), ext_views,ext_views); //extend the views + extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); //extend the tangential positions extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; // ===========================PUSH ================================== - SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); + SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' //sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); - transpose_extend_tangential_position(extended,1,1); + transpose_extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,ext_views,ext_views); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 08e4eda641..c2f6f739ed 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -108,7 +108,9 @@ void sample_function_on_regular_grid_push(Array<3,elemT>& out, const BasicCoordinate<3, positionT>& offset, const BasicCoordinate<3, positionT>& step) { - BasicCoordinate<3,int> min_in, max_in; + +BasicCoordinate<3,int> min_in, max_in; + IndexRange<3> in_range = in.get_index_range(); if (!in_range.get_regular_range(min_in,max_in)) warning("Output must be regular range!"); diff --git a/src/include/stir_experimental/numerics/more_interpolators.inl b/src/include/stir_experimental/numerics/more_interpolators.inl index ec029229f3..d26d20f96d 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.inl +++ b/src/include/stir_experimental/numerics/more_interpolators.inl @@ -80,11 +80,11 @@ pull_linear_interpolate(const Array<3, elemT>& in, // TODO handle boundary conditions if (left_neighbour[1] < in.get_max_index() && - left_neighbour[1] > in.get_min_index() && + left_neighbour[1] >= in.get_min_index() && left_neighbour[2] < in[left_neighbour[1]].get_max_index() && - left_neighbour[2] > in[left_neighbour[1]].get_min_index() && + left_neighbour[2] >= in[left_neighbour[1]].get_min_index() && left_neighbour[3] < in[left_neighbour[1]][left_neighbour[2]].get_max_index() && - left_neighbour[3] > in[left_neighbour[1]][left_neighbour[2]].get_min_index()) + left_neighbour[3] >= in[left_neighbour[1]][left_neighbour[2]].get_min_index()) { const int x1=left_neighbour[3]; const int y1=left_neighbour[2]; @@ -132,11 +132,11 @@ push_transpose_linear_interpolate(Array<3, elemT>& out, // TODO handle boundary conditions if (left_neighbour[1] < out.get_max_index() && - left_neighbour[1] > out.get_min_index() && + left_neighbour[1] >= out.get_min_index() && left_neighbour[2] < out[left_neighbour[1]].get_max_index() && - left_neighbour[2] > out[left_neighbour[1]].get_min_index() && + left_neighbour[2] >= out[left_neighbour[1]].get_min_index() && left_neighbour[3] < out[left_neighbour[1]][left_neighbour[2]].get_max_index() && - left_neighbour[3] > out[left_neighbour[1]][left_neighbour[2]].get_min_index()) + left_neighbour[3] >= out[left_neighbour[1]][left_neighbour[2]].get_min_index()) { const int x1=left_neighbour[3]; const int y1=left_neighbour[2]; diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 64def8aee7..7ea89bf774 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -100,20 +100,6 @@ std::cout << "TEST LR: 3D size:"<< LR_proj_data.get_num_segments() << "x"<< LR_ LR_scaled_proj_data.fill(1); ScatterEstimation::push_scatter_estimate(LR_scaled_proj_data,LR_proj_data,scaled_proj_data,true); - SegmentBySinogram array = LR_scaled_proj_data.get_segment_by_sinogram(0); - - BasicCoordinate<3,int> min, max; - - min[1]=array.get_min_index()-1; - max[1]=array.get_max_index()+1; - min[2]=array[0].get_min_index();; - max[2]=array[0].get_max_index();; - min[3]=array[0][0].get_max_index(); - max[3]=array[0][0].get_max_index(); - array.grow(IndexRange<3>(min, max)); - - std::cout << min[1] <<"," << max[1] <<'\n'; - //std::cout << "TEST: 3D downsampled size:"<< scaled_proj_data_LR.get_num_segments() << "x"<< scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data_LR.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; } From 02af63e93fb9cb5bfc2d64ae04631e4b24ac0921 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 3 Jul 2019 00:31:45 +0100 Subject: [PATCH 101/274] errors ok --- src/include/stir/numerics/sampling_functions.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index c2f6f739ed..0b7909ebf4 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -141,7 +141,7 @@ BasicCoordinate<3,int> min_in, max_in; in[index_in]); } } - out*=(step[1]*step[2]*step[3]); //very important + //out*=(step[1]*step[2]*step[3]); //very important } template From 1db713590f60fcbb15ee90e31dee63bfa1f54926 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 3 Jul 2019 10:47:54 +0100 Subject: [PATCH 102/274] cleaned --- src/buildblock/interpolate_projdata.cxx | 29 ++++++++----------- .../stir/numerics/sampling_functions.h | 4 +-- .../stir/numerics/sampling_functions.inl | 21 +++++--------- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 15616462b1..ba3331b6a3 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -519,8 +519,6 @@ interpolate_projdata_pull(ProjData& proj_data_out, step[3]= out_sampling_s/in_sampling_s; - int ext_views = 2; - int ext_tan_pos = 1; if (remove_interleaving) @@ -534,8 +532,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, write_data(s,non_interleaved_segment); s.close(); - Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, ext_views, ext_views); //here we are doubling the number of views - extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); // here we are adding one tangential position before and after max and min index (for the interpolation) + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //here we are doubling the number of views + extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; open_write_binary(s, "extended_before_interopolation.data"); @@ -551,8 +549,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, } else { - Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), ext_views, ext_views); //here we are extending the number of views - extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); // here we are adding one tangential position before and after max and min index (for the interpolation) + Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views + extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -642,17 +640,14 @@ interpolate_projdata_push(ProjData& proj_data_out, step[3]= in_sampling_s/out_sampling_s; - int ext_views = 2; - int ext_tan_pos = 1; - if (remove_interleaving) { // =================== RESIZE 'EXTENDED' OUTPUT ========================= shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_out_info); const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_out.get_segment_by_sinogram(0)); - Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, ext_views, ext_views); //extend the views - extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); //extend the tangential positions + Array<3,float> extended = extend_segment_in_views(non_interleaved_segment,2,2); //extend the views + extend_tangential_position(extended); //extend the tangential positions extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -664,9 +659,9 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); //reduce axial positions - transpose_extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); //reduce tangential positions + transpose_extend_tangential_position(extended); //reduce tangential positions SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,ext_views,ext_views); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================TRANSPOSE REMOVE INTERLEAVING ==================== @@ -689,8 +684,8 @@ interpolate_projdata_push(ProjData& proj_data_out, { // =================== RESIZE 'EXTENDED' OUTPUT ========================= - Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), ext_views,ext_views); //extend the views - extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); //extend the tangential positions + Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); //extend the views + extend_tangential_position(extended); //extend the tangential positions extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -703,11 +698,11 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== transpose_extend_axial_position(extended); - transpose_extend_tangential_position(extended,ext_tan_pos,ext_tan_pos); + transpose_extend_tangential_position(extended); shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; - Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,ext_views,ext_views); // here we do the tranpose : extended -> sino_out + Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; diff --git a/src/include/stir/numerics/sampling_functions.h b/src/include/stir/numerics/sampling_functions.h index 301b5a13a0..1430714f4f 100644 --- a/src/include/stir/numerics/sampling_functions.h +++ b/src/include/stir/numerics/sampling_functions.h @@ -80,11 +80,11 @@ void views_position_boundary_conditions(Array<3,elemT>& out);*/ template inline -void extend_tangential_position(Array<3,elemT>& out,int min_ext, int max_ext); +void extend_tangential_position(Array<3,elemT>& out); template inline -void transpose_extend_tangential_position(Array<3,elemT>& out, int min_red, int max_red); +void transpose_extend_tangential_position(Array<3,elemT>& out); template diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 0b7909ebf4..9effabd4c3 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -145,7 +145,7 @@ BasicCoordinate<3,int> min_in, max_in; } template -void extend_tangential_position(Array<3,elemT>& array, int min_ext, int max_ext) +void extend_tangential_position(Array<3,elemT>& array) { for (int z=array.get_min_index(); z<= array.get_max_index(); ++z) { @@ -153,23 +153,18 @@ void extend_tangential_position(Array<3,elemT>& array, int min_ext, int max_ext) { const int old_min = array[z][y].get_min_index(); const int old_max = array[z][y].get_max_index(); - array[z][y].grow(old_min-min_ext, old_max+max_ext); - for (int i = 0; i -void transpose_extend_tangential_position(Array<3,elemT>& array, int min_red, int max_red) +void transpose_extend_tangential_position(Array<3,elemT>& array) { for (int z=array.get_min_index(); z<= array.get_max_index(); ++z) { @@ -177,7 +172,7 @@ void transpose_extend_tangential_position(Array<3,elemT>& array, int min_red, in { const int old_min = array[z][y].get_min_index(); const int old_max = array[z][y].get_max_index(); - array[z][y].grow(old_min+min_red, old_max-max_red); //resize + array[z][y].grow(old_min+1, old_max-1); //resize } } } From 0478af1c67aadae6507ddb725eaa36b2fa83d73c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 4 Jul 2019 11:26:06 +0100 Subject: [PATCH 103/274] works fine --- src/buildblock/extend_projdata.cxx | 2 +- src/buildblock/interpolate_projdata.cxx | 43 +- src/buildblock/zoom.cxx | 819 ++++++++++++------------ src/include/stir/ZoomOptions.h | 70 +- src/include/stir/zoom.h | 361 +++++------ 5 files changed, 649 insertions(+), 646 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index c3e52e4ca5..14f144eebb 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -157,10 +157,10 @@ namespace detail for (int view_num=min_in[1]; view_num<=max_in[1]; ++view_num) { input_compressed_view[view_num]=sino_segment[view_num]; //here we cut everything bigger than max_in and smaller than min_in - //input_compressed_view[min_in[1]]=input_compressed_view[min_in[1]+1]; } // loop over views + input_compressed_view[min_in[1]]+=sino_segment[max_in[1]+1];//boundary condition return input_compressed_view; } diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index ba3331b6a3..c42275544f 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -196,24 +196,47 @@ namespace detail_interpolate_projdata tangential_pos_num <= in_sinogram.get_max_tangential_pos_num()-1; ++tangential_pos_num) { + const int out_view_num = + view_num%2==0 ? view_num/2 : (view_num+1)/2; + int first_view=in_sinogram.get_min_view_num(); + int last_view=in_sinogram.get_max_view_num(); + // here i need to take the bigger grid an if ((view_num+tangential_pos_num)%2 == 0) //if it's even { - const int out_view_num = - view_num%2==0 ? view_num/2 : (view_num+1)/2; - out_sinogram[out_view_num%out_num_views][tangential_pos_num] += - in_sinogram[view_num][tangential_pos_num]+(in_sinogram[view_num-1][tangential_pos_num] + - in_sinogram[view_num+1][tangential_pos_num] + - in_sinogram[view_num][(tangential_pos_num-1)] + - in_sinogram[view_num][(tangential_pos_num+1)] - )/4; - } + + out_sinogram[out_view_num%out_num_views][tangential_pos_num] += in_sinogram[view_num][tangential_pos_num] + + (in_sinogram[view_num-1][tangential_pos_num] + + in_sinogram[view_num+1][tangential_pos_num] + + in_sinogram[view_num][(tangential_pos_num-1)] + + in_sinogram[view_num][(tangential_pos_num+1)])/4; + + //BOUNDARY CONDITIONS FOR MIN AND MAX TAN POS + out_sinogram[out_view_num%out_num_views][in_sinogram.get_min_tangential_pos_num()] = + (in_sinogram[view_num][(in_sinogram.get_min_tangential_pos_num()+1)])/4; + out_sinogram[out_view_num%out_num_views][in_sinogram.get_max_tangential_pos_num()] = + (in_sinogram[view_num][(in_sinogram.get_max_tangential_pos_num()-1)])/4; + } + + + //BOUNDARY FOR MIN AND MAX VIEWS + out_sinogram[first_view][tangential_pos_num] = in_sinogram[first_view][tangential_pos_num]+ + (in_sinogram[first_view+1][tangential_pos_num] + + in_sinogram[last_view][tangential_pos_num]+ + in_sinogram[first_view][(tangential_pos_num-1)] + + in_sinogram[first_view][(tangential_pos_num+1)])/4; + + //CORNERS + out_sinogram[first_view][in_sinogram.get_min_tangential_pos_num()] = + (in_sinogram[first_view][(in_sinogram.get_max_tangential_pos_num()-1)])/4; + out_sinogram[first_view][in_sinogram.get_max_tangential_pos_num()] = + (in_sinogram[first_view][(in_sinogram.get_min_tangential_pos_num()+1)])/4; + } } } - static void make_non_interleaved_segment(SegmentBySinogram& out_segment, const SegmentBySinogram& in_segment) diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 2736300fe1..497007dc68 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -1,56 +1,46 @@ -// -// /* - Copyright (C) 2000 PARAPET partners - Copyright (C) 2000- 2011, Hammersmith Imanet Ltd - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ + Copyright (C) 2000 PARAPET partners + Copyright (C) 2000- 2011, Hammersmith Imanet Ltd + Copyright (C) 2018-2019, University College London + This file is part of STIR. + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details + */ /*! - \file - \ingroup buildblock - - \brief Implementations of the stir::zoom functions - - \author Kris Thielemans - \author Claire Labbe - \author PARAPET project - - -*/ + \file + \ingroup buildblock + \brief Implementations of the stir::zoom functions + \author Kris Thielemans + \author Claire Labbe + \author PARAPET project + \author Ludovica Brusaferri + */ /* Modification history: - - First versions by CL and KT (sinogram version based on C code by Matthias Egger (using linear interpolation). - - CL introduced overlap interpolation. - - KT moved interpolation to separate function overlap_interpolate, removing bugs. - - KT introduced 3D zooming for images. - - KT converted to new design + - First versions by CL and KT (sinogram version based on C code by Matthias Egger (using linear interpolation). + - CL introduced overlap interpolation. + - KT moved interpolation to separate function overlap_interpolate, removing bugs. + - KT introduced 3D zooming for images. + - KT converted to new design */ - + #include "stir/interpolate.h" #include "stir/zoom.h" -#include "stir/PostFiltering.h" #include "stir/DataProcessor.h" #include "stir/DiscretisedDensity.h" -#include "stir/VoxelsOnCartesianGrid.h" -#include "stir/PixelsOnCartesianGrid.h" +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/PixelsOnCartesianGrid.h" #include "stir/Viewgram.h" #include "stir/RelatedViewgrams.h" #include "stir/ProjDataInfoCylindricalArcCorr.h" #include "stir/IndexRange3D.h" #include "stir/IndexRange2D.h" -#include "stir/SeparableGaussianImageFilter.h" -#include "stir/ZoomOptions.h" #include START_NAMESPACE_STIR @@ -60,185 +50,185 @@ START_NAMESPACE_STIR // also they need to be converted to the new design // as we don't need them at the moment, I can't be bothered... #if 0 -void zoom_segment (SegmentByView& segment, - const float zoom, const float azimuthal_angle_sampling, const float y_offset_in_mm, +void zoom_segment (SegmentByView& segment, + const float zoom, const float azimuthal_angle_sampling, const float y_offset_in_mm, const int new_size, const float azimuthal_angle_sampling) { - - // First check if there is anything to do at all, - // if not, return original segment. - - if (new_size == segment.get_num_bins() && - zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) + + // First check if there is anything to do at all, + // if not, return original segment. + + if (new_size == segment.get_num_bins() && + zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) return; - - // KT 17/01/2000 use local copy of scan_info instead of segment.scan_info - ScanInfo scan_info = segment.scan_info; - scan_info.set_num_bins(new_size); - scan_info.set_bin_size(segment.scan_info.get_bin_size() / zoom); - - const int minsize = -new_size/2; - const int maxsize = minsize+new_size-1; - - // TODO replace by get_empty_segment or so - SegmentByView + + // KT 17/01/2000 use local copy of scan_info instead of segment.scan_info + ScanInfo scan_info = segment.scan_info; + scan_info.set_num_bins(new_size); + scan_info.set_bin_size(segment.scan_info.get_bin_size() / zoom); + + const int minsize = -new_size/2; + const int maxsize = minsize+new_size-1; + + // TODO replace by get_empty_segment or so + SegmentByView out_segment(Tensor3D(segment.get_min_view(), segment.get_max_view(), - segment.get_min_axial_pos_num(), segment.get_max_axial_pos_num(), - minsize, maxsize), - scan_info, - segment.get_segment_num(), - segment.get_min_axial_pos_num_difference(), - segment.get_max_ring_difference()); - - for (int view = segment.get_min_view(); view <= segment.get_max_view(); view++) + segment.get_min_axial_pos_num(), segment.get_max_axial_pos_num(), + minsize, maxsize), + scan_info, + segment.get_segment_num(), + segment.get_min_axial_pos_num_difference(), + segment.get_max_ring_difference()); + + for (int view = segment.get_min_view(); view <= segment.get_max_view(); view++) { - Viewgram viewgram = segment.get_viewgram(view); - zoom_viewgram(viewgram, - zoom, x_offset_in_mm, y_offset_in_mm, - new_size, azimuthal_angle_sampling); - out_segment.set_viewgram(viewgram); + Viewgram viewgram = segment.get_viewgram(view); + zoom_viewgram(viewgram, + zoom, x_offset_in_mm, y_offset_in_mm, + new_size, azimuthal_angle_sampling); + out_segment.set_viewgram(viewgram); } - - segment = out_segment; + + segment = out_segment; } #endif void -zoom_viewgrams (RelatedViewgrams& in_viewgrams, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm, const float y_offset_in_mm) +zoom_viewgrams (RelatedViewgrams& in_viewgrams, + const float zoom, + const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm, const float y_offset_in_mm) { - if (min_tang_pos_num == in_viewgrams.get_min_tangential_pos_num() && - max_tang_pos_num == in_viewgrams.get_max_tangential_pos_num() && - zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) + if (min_tang_pos_num == in_viewgrams.get_min_tangential_pos_num() && + max_tang_pos_num == in_viewgrams.get_max_tangential_pos_num() && + zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) return; - ProjDataInfo * new_proj_data_info_ptr = + ProjDataInfo * new_proj_data_info_ptr = in_viewgrams.get_proj_data_info_ptr()->clone(); - ProjDataInfoCylindricalArcCorr* new_proj_data_info_arccorr_ptr = + ProjDataInfoCylindricalArcCorr* new_proj_data_info_arccorr_ptr = dynamic_cast(new_proj_data_info_ptr); - - if ( new_proj_data_info_arccorr_ptr==0) + + if ( new_proj_data_info_arccorr_ptr==0) error("zoom_viewgram does not support non-arccorrected data. Sorry\n"); - - new_proj_data_info_arccorr_ptr->set_min_tangential_pos_num(min_tang_pos_num); - new_proj_data_info_arccorr_ptr->set_max_tangential_pos_num(max_tang_pos_num); - - new_proj_data_info_arccorr_ptr-> + + new_proj_data_info_arccorr_ptr->set_min_tangential_pos_num(min_tang_pos_num); + new_proj_data_info_arccorr_ptr->set_max_tangential_pos_num(max_tang_pos_num); + + new_proj_data_info_arccorr_ptr-> set_tangential_sampling(new_proj_data_info_arccorr_ptr-> - get_tangential_sampling() / zoom); - - shared_ptr + get_tangential_sampling() / zoom); + + shared_ptr symmetries_sptr(in_viewgrams.get_symmetries_ptr()->clone()); - - RelatedViewgrams - out_viewgrams = + + RelatedViewgrams + out_viewgrams = new_proj_data_info_arccorr_ptr-> - get_empty_related_viewgrams(in_viewgrams.get_basic_view_segment_num(), - symmetries_sptr); - - { - RelatedViewgrams::iterator out_iter = out_viewgrams.begin(); - RelatedViewgrams::const_iterator in_iter = in_viewgrams.begin(); - for (; out_iter != out_viewgrams.end(); ++out_iter, ++in_iter) - zoom_viewgram(*out_iter, *in_iter, - x_offset_in_mm, y_offset_in_mm); - } - - in_viewgrams = out_viewgrams; + get_empty_related_viewgrams(in_viewgrams.get_basic_view_segment_num(), + symmetries_sptr); + + { + RelatedViewgrams::iterator out_iter = out_viewgrams.begin(); + RelatedViewgrams::const_iterator in_iter = in_viewgrams.begin(); + for (; out_iter != out_viewgrams.end(); ++out_iter, ++in_iter) + zoom_viewgram(*out_iter, *in_iter, + x_offset_in_mm, y_offset_in_mm); + } + + in_viewgrams = out_viewgrams; } void -zoom_viewgram (Viewgram& in_view, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm, const float y_offset_in_mm) -{ - if (min_tang_pos_num == in_view.get_min_tangential_pos_num() && - max_tang_pos_num == in_view.get_max_tangential_pos_num() && - zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) +zoom_viewgram (Viewgram& in_view, + const float zoom, + const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm, const float y_offset_in_mm) +{ + if (min_tang_pos_num == in_view.get_min_tangential_pos_num() && + max_tang_pos_num == in_view.get_max_tangential_pos_num() && + zoom == 1.0 && x_offset_in_mm == 0.0 && y_offset_in_mm == 0.0) return; - ProjDataInfo * new_proj_data_info_ptr = + ProjDataInfo * new_proj_data_info_ptr = in_view.get_proj_data_info_ptr()->clone(); - ProjDataInfoCylindricalArcCorr* new_proj_data_info_arccorr_ptr = + ProjDataInfoCylindricalArcCorr* new_proj_data_info_arccorr_ptr = dynamic_cast(new_proj_data_info_ptr); - - if ( new_proj_data_info_arccorr_ptr==0) + + if ( new_proj_data_info_arccorr_ptr==0) error("zoom_viewgram does not support non-arccorrected data. Sorry\n"); - - new_proj_data_info_arccorr_ptr->set_min_tangential_pos_num(min_tang_pos_num); - new_proj_data_info_arccorr_ptr->set_max_tangential_pos_num(max_tang_pos_num); - - new_proj_data_info_arccorr_ptr-> + + new_proj_data_info_arccorr_ptr->set_min_tangential_pos_num(min_tang_pos_num); + new_proj_data_info_arccorr_ptr->set_max_tangential_pos_num(max_tang_pos_num); + + new_proj_data_info_arccorr_ptr-> set_tangential_sampling(new_proj_data_info_arccorr_ptr-> - get_tangential_sampling() / zoom); - - Viewgram + get_tangential_sampling() / zoom); + + Viewgram out_view = new_proj_data_info_arccorr_ptr-> - get_empty_viewgram( - in_view.get_view_num(), - in_view.get_segment_num()); - - zoom_viewgram(out_view, in_view, - x_offset_in_mm, y_offset_in_mm); - - in_view = out_view; + get_empty_viewgram( + in_view.get_view_num(), + in_view.get_segment_num()); + + zoom_viewgram(out_view, in_view, + x_offset_in_mm, y_offset_in_mm); + + in_view = out_view; } void -zoom_viewgram (Viewgram& out_view, - const Viewgram& in_view, - const float x_offset_in_mm, const float y_offset_in_mm) -{ - // minimal checks on compatibility - assert(in_view.get_proj_data_info_ptr()->get_num_views() == - out_view.get_proj_data_info_ptr()->get_num_views()); - assert(in_view.get_view_num() == out_view.get_view_num()); - assert(in_view.get_proj_data_info_ptr()->get_num_segments() == - out_view.get_proj_data_info_ptr()->get_num_segments()); - assert(in_view.get_segment_num() == out_view.get_segment_num()); - assert(in_view.get_min_axial_pos_num() == out_view.get_min_axial_pos_num()); - assert(in_view.get_max_axial_pos_num() == out_view.get_max_axial_pos_num()); - - // get the pointers to the arc-corrected ProjDataInfo - const ProjDataInfoCylindricalArcCorr* in_proj_data_info_arccorr_ptr = +zoom_viewgram (Viewgram& out_view, + const Viewgram& in_view, + const float x_offset_in_mm, const float y_offset_in_mm) +{ + // minimal checks on compatibility + assert(in_view.get_proj_data_info_ptr()->get_num_views() == + out_view.get_proj_data_info_ptr()->get_num_views()); + assert(in_view.get_view_num() == out_view.get_view_num()); + assert(in_view.get_proj_data_info_ptr()->get_num_segments() == + out_view.get_proj_data_info_ptr()->get_num_segments()); + assert(in_view.get_segment_num() == out_view.get_segment_num()); + assert(in_view.get_min_axial_pos_num() == out_view.get_min_axial_pos_num()); + assert(in_view.get_max_axial_pos_num() == out_view.get_max_axial_pos_num()); + + // get the pointers to the arc-corrected ProjDataInfo + const ProjDataInfoCylindricalArcCorr* in_proj_data_info_arccorr_ptr = dynamic_cast(in_view.get_proj_data_info_ptr()); - const ProjDataInfoCylindricalArcCorr* out_proj_data_info_arccorr_ptr = + const ProjDataInfoCylindricalArcCorr* out_proj_data_info_arccorr_ptr = dynamic_cast(out_view.get_proj_data_info_ptr()); - - if (in_proj_data_info_arccorr_ptr==0 || - out_proj_data_info_arccorr_ptr==0) + + if (in_proj_data_info_arccorr_ptr==0 || + out_proj_data_info_arccorr_ptr==0) error("zoom_viewgram does not support non-arccorrected data. Sorry\n"); - - - const float in_bin_size = + + + const float in_bin_size = in_proj_data_info_arccorr_ptr->get_tangential_sampling(); - const float out_bin_size = + const float out_bin_size = out_proj_data_info_arccorr_ptr->get_tangential_sampling(); - - const float zoom = in_bin_size / out_bin_size; - - if (out_view.get_min_tangential_pos_num() == in_view.get_min_tangential_pos_num() && - out_view.get_max_tangential_pos_num() == in_view.get_max_tangential_pos_num() && - zoom == 1.0F && x_offset_in_mm == 0.0F && y_offset_in_mm == 0.0F) + + const float zoom = in_bin_size / out_bin_size; + + if (out_view.get_min_tangential_pos_num() == in_view.get_min_tangential_pos_num() && + out_view.get_max_tangential_pos_num() == in_view.get_max_tangential_pos_num() && + zoom == 1.0F && x_offset_in_mm == 0.0F && y_offset_in_mm == 0.0F) return; - const float phi = - in_proj_data_info_arccorr_ptr-> - get_phi(Bin(in_view.get_segment_num(), in_view.get_view_num(), 0,0)); - - // compute offset in tangential_sampling_in units - const float offset = + const float phi = + in_proj_data_info_arccorr_ptr-> + get_phi(Bin(in_view.get_segment_num(), in_view.get_view_num(), 0,0)); + + // compute offset in tangential_sampling_in units + const float offset = (x_offset_in_mm*cos(phi) +y_offset_in_mm*sin(phi))/ in_bin_size; - - for (int axial_pos_num= out_view.get_min_axial_pos_num(); axial_pos_num <= out_view.get_max_axial_pos_num(); ++axial_pos_num) + + for (int axial_pos_num= out_view.get_min_axial_pos_num(); axial_pos_num <= out_view.get_max_axial_pos_num(); ++axial_pos_num) { - overlap_interpolate(out_view[axial_pos_num], in_view[axial_pos_num], zoom, offset); - } + overlap_interpolate(out_view[axial_pos_num], in_view[axial_pos_num], zoom, offset); + } } @@ -247,323 +237,306 @@ zoom_viewgram (Viewgram& out_view, static VoxelsOnCartesianGrid construct_new_image_from_zoom_parameters(const VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes_arg) + const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, + const BasicCoordinate<3,int>& new_sizes_arg) { - CartesianCoordinate3D new_sizes = new_sizes_arg; - assert(new_sizes.x()>=0); - assert(new_sizes.y()>=0); - assert(new_sizes.z()>=0); - CartesianCoordinate3D + CartesianCoordinate3D new_sizes = new_sizes_arg; + assert(new_sizes.x()>=0); + assert(new_sizes.y()>=0); + assert(new_sizes.z()>=0); + CartesianCoordinate3D voxel_size = image.get_grid_spacing() / zooms; - - // first set origin to 0 - CartesianCoordinate3D + + // first set origin to 0 + CartesianCoordinate3D origin(0.F,0.F,0.F); - - VoxelsOnCartesianGrid - new_image(IndexRange3D(0, new_sizes.z()-1, - -new_sizes.y()/2, -new_sizes.y()/2+new_sizes.y()-1, - -new_sizes.x()/2, -new_sizes.x()/2+new_sizes.x()-1), - origin, - voxel_size); - - // find coordinates of middle of images - BasicCoordinate<3,int> min_indices, max_indices; - if (!image.get_regular_range(min_indices, max_indices)) + + VoxelsOnCartesianGrid + new_image(image.get_exam_info_sptr(), + IndexRange3D(0, new_sizes.z()-1, + -new_sizes.y()/2, -new_sizes.y()/2+new_sizes.y()-1, + -new_sizes.x()/2, -new_sizes.x()/2+new_sizes.x()-1), + origin, + voxel_size); + + // find coordinates of middle of images + BasicCoordinate<3,int> min_indices, max_indices; + if (!image.get_regular_range(min_indices, max_indices)) error("zoom_image: Non-regular range of coordinates in input image. That's strange."); - BasicCoordinate<3,int> new_min_indices, new_max_indices; - if (!new_image.get_regular_range(new_min_indices, new_max_indices)) + BasicCoordinate<3,int> new_min_indices, new_max_indices; + if (!new_image.get_regular_range(new_min_indices, new_max_indices)) error("zoom_image: Non-regular range of coordinates in output image. That's a bug."); - - const BasicCoordinate<3,float> middle = + + const BasicCoordinate<3,float> middle = (image.get_physical_coordinates_for_indices(min_indices) + image.get_physical_coordinates_for_indices(max_indices))/2; - const BasicCoordinate<3,float> new_middle = + const BasicCoordinate<3,float> new_middle = (new_image.get_physical_coordinates_for_indices(new_min_indices) + new_image.get_physical_coordinates_for_indices(new_max_indices))/2; - // now make sure that these are shifted as required - new_image.set_origin(offsets_in_mm + middle - new_middle); - // check - { - const BasicCoordinate<3,float> final_middle = - (new_image.get_physical_coordinates_for_indices(new_min_indices) + - new_image.get_physical_coordinates_for_indices(new_max_indices))/2; - if (norm(final_middle - middle - offsets_in_mm) > 1) - error("zoom_image bug in finding new origin"); - } - - return new_image; + // now make sure that these are shifted as required + new_image.set_origin(offsets_in_mm + middle - new_middle); + // check + { + const BasicCoordinate<3,float> final_middle = + (new_image.get_physical_coordinates_for_indices(new_min_indices) + + new_image.get_physical_coordinates_for_indices(new_max_indices))/2; + if (norm(final_middle - middle - offsets_in_mm) > 1) + error("zoom_image bug in finding new origin"); + } + + return new_image; } void zoom_image_in_place(VoxelsOnCartesianGrid &image, - const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size ) + const float zoom, + const float x_offset_in_mm, const float y_offset_in_mm, + const int new_size, + const ZoomOptions zoom_options) { - VoxelsOnCartesianGrid new_image = - zoom_image(image, zoom, x_offset_in_mm, y_offset_in_mm, new_size); - image = new_image; + VoxelsOnCartesianGrid new_image = + zoom_image(image, zoom, x_offset_in_mm, y_offset_in_mm, new_size, zoom_options); + image = new_image; } VoxelsOnCartesianGrid zoom_image(const VoxelsOnCartesianGrid &image, const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size ) + const float x_offset_in_mm, const float y_offset_in_mm, + const int new_size, + const ZoomOptions zoom_options) { - assert(new_size>=0); - if(zoom==1 && x_offset_in_mm==0 && y_offset_in_mm==0 && new_size== image.get_x_size()) + assert(new_size>=0); + if(zoom==1 && x_offset_in_mm==0 && y_offset_in_mm==0 && new_size== image.get_x_size()) return image; - - const CartesianCoordinate3D zooms(1,zoom,zoom); - const CartesianCoordinate3D offsets_in_mm(0.F, y_offset_in_mm, x_offset_in_mm); - const BasicCoordinate<3,int> new_sizes = + + const CartesianCoordinate3D zooms(1,zoom,zoom); + const CartesianCoordinate3D offsets_in_mm(0.F, y_offset_in_mm, x_offset_in_mm); + const BasicCoordinate<3,int> new_sizes = make_coordinate(image.get_length(), new_size, new_size); - - VoxelsOnCartesianGrid new_image = + + VoxelsOnCartesianGrid new_image = construct_new_image_from_zoom_parameters(image, - zooms, - offsets_in_mm, - new_sizes); - - PixelsOnCartesianGrid + zooms, + offsets_in_mm, + new_sizes); + + PixelsOnCartesianGrid new_image2D = new_image.get_plane(new_image.get_min_z()); - for (int plane = image.get_min_z(); plane <= image.get_max_z(); plane++) + for (int plane = image.get_min_z(); plane <= image.get_max_z(); plane++) { - zoom_image(new_image2D, image.get_plane(plane)); - new_image.set_plane(new_image2D, plane); + zoom_image(new_image2D, image.get_plane(plane), zoom_options); + new_image.set_plane(new_image2D, plane); } - assert(norm(new_image.get_voxel_size() - image.get_voxel_size()/zooms)<1); - - return new_image; + assert(norm(new_image.get_voxel_size() - image.get_voxel_size()/zooms)<1); + + return new_image; } void zoom_image_in_place(VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes) + const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, + const BasicCoordinate<3,int>& new_sizes, + const ZoomOptions zoom_options) { - const VoxelsOnCartesianGrid new_image = - zoom_image(image, zooms, offsets_in_mm, new_sizes); - image = new_image; + const VoxelsOnCartesianGrid new_image = + zoom_image(image, zooms, offsets_in_mm, new_sizes, zoom_options); + image = new_image; } VoxelsOnCartesianGrid zoom_image(const VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes) + const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, + const BasicCoordinate<3,int>& new_sizes, + const ZoomOptions zoom_options) { - - VoxelsOnCartesianGrid new_image = + + VoxelsOnCartesianGrid new_image = construct_new_image_from_zoom_parameters(image, - zooms, - offsets_in_mm, - new_sizes); - zoom_image(new_image, image); - return new_image; -} - - - -void -zoom_image_matlab(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const int &zoom_option) -{ - ZoomOptions::ZO zo = ZoomOptions::ZO(zoom_option); - zoom_image(image_out, image_in, postfilter_parameter_filename, zo); -} - -void -zoom_image_matlab(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const int &zoom_option) -{ - ZoomOptions::ZO zo = ZoomOptions::ZO(zoom_option); - zoom_image(image_out, image_in, zo); + zooms, + offsets_in_mm, + new_sizes); + zoom_image(new_image, image, zoom_options); + return new_image; } - void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO &zo) + const VoxelsOnCartesianGrid &image_in, + const ZoomOptions zoom_options) { - zoom_image(image_out, image_in, zo); - - //apply filter - PostFiltering > filter; - filter.parse(postfilter_parameter_filename.c_str()); - filter.process_data(image_out); - -} - - - -void -zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO &zo) -{ - - -/* + image_out.set_exam_info(image_in.get_exam_info()); + /* interpolation routine uses the following relation: - x_in_index = x_out_index/zoom + offset - + x_in_index = x_out_index/zoom + offset compare to 'physical' coordinates - x_phys = (x_index) * voxel_size.x + origin.x - + x_phys = (x_index) * voxel_size.x + origin.x + as x_in_phys == x_out_phys, we find - (x_in_index)* voxel_size_in.x + origin_in.x == - (x_out_index )* voxel_size_out.x + origin_out.x - <=> - x_in_index = (x_out_index * voxel_size_out.x - + origin_out.x - origin_in.x) - / voxel_size_in.x - + (x_in_index)* voxel_size_in.x + origin_in.x == + (x_out_index )* voxel_size_out.x + origin_out.x + <=> + x_in_index = (x_out_index * voxel_size_out.x + + origin_out.x - origin_in.x) + / voxel_size_in.x so, zoom= voxel_size_in.x/ voxel_size_out.x - offset = (origin_out.x - origin_in.x)/ voxel_size_in.x - - */ - // check relation between indices and physical coordinates - { - const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); - if (norm(image_in.get_physical_coordinates_for_indices(indices) - - (image_in.get_voxel_size() * BasicCoordinate<3,float>(indices) + image_in.get_origin()) - ) > 2.F) - error("zoom_image is confused about the relation between indices and physical coordinates"); - } - const float zoom_x = + offset = (origin_out.x - origin_in.x)/ voxel_size_in.x + */ + // check relation between indices and physical coordinates + { + const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); + if (norm(image_in.get_physical_coordinates_for_indices(indices) + - (image_in.get_voxel_size() * BasicCoordinate<3,float>(indices) + image_in.get_origin()) + ) > 2.F) + error("zoom_image is confused about the relation between indices and physical coordinates"); + } + const float zoom_x = image_in.get_voxel_size().x() / image_out.get_voxel_size().x(); - const float zoom_y = + const float zoom_y = image_in.get_voxel_size().y() / image_out.get_voxel_size().y(); - const float zoom_z = + const float zoom_z = image_in.get_voxel_size().z() / image_out.get_voxel_size().z(); - const float x_offset = + const float x_offset = (image_out.get_origin().x() - image_in.get_origin().x()) - / image_in.get_voxel_size().x(); - const float y_offset = + / image_in.get_voxel_size().x(); + const float y_offset = (image_out.get_origin().y() - image_in.get_origin().y()) / image_in.get_voxel_size().y(); - const float z_offset = + const float z_offset = (image_out.get_origin().z() - image_in.get_origin().z()) / image_in.get_voxel_size().z(); - - - if(zoom_x==1.0F && zoom_y==1.0F && zoom_z==1.0F && - x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && - image_in.get_index_range() == image_out.get_index_range() - ) + + + if(zoom_x==1.0F && zoom_y==1.0F && zoom_z==1.0F && + x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && + image_in.get_index_range() == image_out.get_index_range() + ) { - image_out = image_in; - return; + image_out = image_in; + return; } - - // TODO creating a lot of new images here... - Array<3,float> + + // TODO creating a lot of new images here... + Array<3,float> temp(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), - image_in.get_min_y(), image_in.get_max_y(), - image_out.get_min_x(), image_out.get_max_x())); - - for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) + image_in.get_min_y(), image_in.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); + + for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) for (int y=image_in.get_min_y(); y<=image_in.get_max_y(); y++) - overlap_interpolate(temp[z][y], image_in[z][y], zoom_x, x_offset); - - Array<3,float> temp2(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), - image_out.get_min_y(), image_out.get_max_y(), - image_out.get_min_x(), image_out.get_max_x())); - - for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) + overlap_interpolate(temp[z][y], image_in[z][y], zoom_x, x_offset); + + Array<3,float> temp2(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), + image_out.get_min_y(), image_out.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); + + for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) overlap_interpolate(temp2[z], temp[z], zoom_y, y_offset); - - temp.recycle(); - - overlap_interpolate(image_out, temp2, zoom_z, z_offset); - - - /* The code provides for three possible rescaling options: - * preserving the image values, - * preserving the image projectors, - * preserving the image sum - - DEFAULT: Preserve image sum*/ - - float scale_image = 1.F; - - switch (zo) - { - case ZoomOptions::preserve_values: - { - std::cerr << "Zoom - Rescaling Factor: preserve values\n"; - - scale_image = zoom_x*zoom_y*zoom_z; - break; - } - - case ZoomOptions::preserve_projections: - - { - std::cerr << "Zoom - Rescaling Factor: preserve projectors\n"; - - scale_image = zoom_y*zoom_z; - break; - } - - case ZoomOptions::preserve_sum: - { - std::cerr << "Zoom - Rescaling Factor: preserve sum\n"; - return; // no need to scale - } - + + temp.recycle(); + + overlap_interpolate(image_out, temp2, zoom_z, z_offset); + + float scale_image = 1.F; + + switch (zoom_options.get_scaling_option()) + { + case ZoomOptions::preserve_values: + { + scale_image = zoom_x*zoom_y*zoom_z; + break; + } + + case ZoomOptions::preserve_projections: + + { + scale_image = zoom_y*zoom_z; + break; + } + + case ZoomOptions::preserve_sum: + { + return; // no need to scale + } + } - - - image_out*= scale_image; - + + if (scale_image != 1.F) + image_out*= scale_image; + } - - void -zoom_image(PixelsOnCartesianGrid &image2D_out, - const PixelsOnCartesianGrid &image2D_in) +zoom_image(PixelsOnCartesianGrid &image2D_out, + const PixelsOnCartesianGrid &image2D_in, + const ZoomOptions zoom_options) { - /* - see above for how to find zoom and offsets - */ - - const float zoom_x = + image2D_out.set_exam_info(image2D_in.get_exam_info()); + /* + see above for how to find zoom and offsets + */ + + const float zoom_x = image2D_in.get_pixel_size().x() / image2D_out.get_pixel_size().x(); - const float zoom_y = + const float zoom_y = image2D_in.get_pixel_size().y() / image2D_out.get_pixel_size().y(); - const float x_offset = - ((image2D_out.get_origin().x() - image2D_in.get_origin().x()) + const float x_offset = + ((image2D_out.get_origin().x() - image2D_in.get_origin().x()) / image2D_in.get_pixel_size().x() - ); - const float y_offset = - ((image2D_out.get_origin().y() - image2D_in.get_origin().y()) + ); + const float y_offset = + ((image2D_out.get_origin().y() - image2D_in.get_origin().y()) / image2D_in.get_pixel_size().y() - ); - - if(zoom_x==1.0F && zoom_y==1.0F && - x_offset == 0.F && y_offset == 0.F && - image2D_in.get_index_range() == image2D_out.get_index_range() - ) - { - image2D_out = image2D_in; - return; - } - - Array<2,float> + ); + + if(zoom_x==1.0F && zoom_y==1.0F && + x_offset == 0.F && y_offset == 0.F && + image2D_in.get_index_range() == image2D_out.get_index_range() + ) + { + image2D_out = image2D_in; + return; + } + + Array<2,float> temp(IndexRange2D(image2D_in.get_min_y(), image2D_in.get_max_y(), - image2D_out.get_min_x(), image2D_out.get_max_x())); - - for (int y=image2D_in.get_min_y(); y<=image2D_in.get_max_y(); y++) + image2D_out.get_min_x(), image2D_out.get_max_x())); + + for (int y=image2D_in.get_min_y(); y<=image2D_in.get_max_y(); y++) overlap_interpolate(temp[y], image2D_in[y], zoom_x, x_offset); - - overlap_interpolate(image2D_out, temp, zoom_y, y_offset); + + overlap_interpolate(image2D_out, temp, zoom_y, y_offset); + + float scale_image = 1.F; + + switch (zoom_options.get_scaling_option()) + { + case ZoomOptions::preserve_values: + { + scale_image = zoom_x*zoom_y; + break; + } + + case ZoomOptions::preserve_projections: + + { + scale_image = zoom_y; + break; + } + + case ZoomOptions::preserve_sum: + { + return; // no need to scale + } + + } + + if (scale_image != 1.F) + image2D_out*= scale_image; + } END_NAMESPACE_STIR diff --git a/src/include/stir/ZoomOptions.h b/src/include/stir/ZoomOptions.h index 323b3b5825..0adfb5f132 100644 --- a/src/include/stir/ZoomOptions.h +++ b/src/include/stir/ZoomOptions.h @@ -1,27 +1,61 @@ -#ifndef ZOOMOPTIONS_H -#define ZOOMOPTIONS_H +/* + Copyright (C) 2018-2019, University College London + This file is part of STIR. + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details + */ -#include "stir/common.h" +#ifndef __stir_ZOOMOPTIONS_H__ +#define __stir_ZOOMOPTIONS_H__ + +/*! + \file + \brief Declaration of class stir::ZoomOptions + \ingroup buildblock + \author Ludovica Brusaferri + \author Kris Thielemans + + */ + +#include "stir/error.h" START_NAMESPACE_STIR /*! - \brief - a class containing an enumeration type that can be used by functions to signal - successful operation or not - - Example: - \code - Succeeded f() { do_something; return Succeeded::yes; } - void g() { if (f() == Succeeded::no) error("Error calling f"); } - \endcode -*/ + \brief + This class enables the user to choose between different zooming options + \ingroup buildblock + + The 3 possible values determine a global scale factor used for the end result: + (i) preserve sum (locally) + (ii) preserve values (like interpolation) + (iii) preserve projections: using a STIR forward projector on the zoomed image will give (approximately) the same projections. + + \see zoom_image + */ + class ZoomOptions{ - public: - enum ZO {preserve_sum, preserve_values, preserve_projections}; - ZoomOptions(const ZO& v) : v(v) {} - private: - ZO v; +public: + enum Scaling {preserve_sum, preserve_values, preserve_projections}; + //! constructor from Scaling + /*! calls error() if out-of-range + */ + ZoomOptions(const Scaling v = preserve_sum) : v(v) + { + // need to catch out-of-range in case somebody did a static_cast from an int (e.g. SWIG does) + if ((v < preserve_sum) || (v > preserve_projections)) + error("ZoomOptions initialised with out-of-range value"); + } + Scaling get_scaling_option() const { return v; } +private: + Scaling v; }; END_NAMESPACE_STIR diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 99bd6bb442..8092546ac7 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -1,99 +1,84 @@ -// -// /* - Copyright (C) 2000 PARAPET partners - Copyright (C) 2000- 2007, Hammersmith Imanet Ltd - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ + Copyright (C) 2000 PARAPET partners + Copyright (C) 2000- 2007, Hammersmith Imanet Ltd + Copyright (C) 2018-2019, University College London + This file is part of STIR. + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details + */ #ifndef __stir_ZOOM_H__ #define __stir_ZOOM_H__ /*! - \file + \file - \brief This file declares various zooming functions. - \ingroup buildblock - \author Kris Thielemans - \author Claire Labbe - \author PARAPET project - - - - These functions can be used for zooming of projection data or image data. - Zooming requires interpolation. Currently, this is done using - stir::overlap_interpolate. - - The first set of functions allows zooming and translation in transaxial - planes only. These parameters are the same for projection data or image data. - That is, zoomed projection data are (approximately) the forward projections - of zoomed images with the same parameters. These functions have the following - parameters: - - \param zoom scales the projection bins (zoom larger than 1 means more detail, so smaller pixels) - \param x_offset_in_mm x-coordinate of new origin (in mm) - \param y_offset_in_mm y-coordinate of new origin (in mm) - - \par Projection data - - This allows 2-dimensional - zooming and translation on arccorrected data, here translation means a translation in - 'image' space which gives a \c sin shift of origin in the \c s - coordinate in - projection space. - The new range of \c s coordinates is given by - \param min_tang_pos_num [for projection data only] the minimum tangential position number in the new - projection line - \param max_tang_pos_num [for projection data only] the maximum tangential position number in the new - projection line - Note that the (projection of the) centre of the scanner axis is supposed to be - at \a tang_pos_num = 0. - - \par images - - It allows three-dimensional - zooming and translation. Parameters are derived either from - stir::CartesianCoordinate3D objects, or from the information in the \a in and \a out - images. - - In the case that the offsets are 0, the following holds: -
    -
  • If \c size is equal to \c zoom*old_size, the same amount of data is represented. -
  • If it is less, data are truncated. -
  • If it is larger, the outer ends are filled with 0. -
- - - \warning Because overlap_interpolate is used, the zooming is 'count-preserving', - i.e. when the output range is large enough, the in.sum() == out.sum(). - - \warning In STIR 1.x, origins were taken relative to the centre of the coordinate range: -\code - x_in_mm = (x_index - x_ctr_index) * voxel_size.x() + origin.x() -\endcode - where -\code - x_ctr_index = (x_max_index + x_min_index)/2 -\endcode - This is no longer true. Instead we use - DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices. -*/ + \brief This file declares various zooming functions. + \ingroup buildblock + \author Kris Thielemans + \author Claire Labbe + \author PARAPET project + \author Ludovica Brusaferri + These functions can be used for zooming of projection data or image data. + Zooming requires interpolation. Currently, this is done using + stir::overlap_interpolate. + + The first set of functions allows zooming and translation in transaxial + planes only. These parameters are the same for projection data or image data. + That is, zoomed projection data are (approximately) the forward projections + of zoomed images with the same parameters. These functions have the following + parameters: + + \param zoom scales the projection bins (zoom larger than 1 means more detail, so smaller pixels) + \param x_offset_in_mm x-coordinate of new origin (in mm) + \param y_offset_in_mm y-coordinate of new origin (in mm) + \par Projection data + This allows 2-dimensional + zooming and translation on arccorrected data, here translation means a translation in + 'image' space which gives a \c sin shift of origin in the \c s - coordinate in + projection space. + The new range of \c s coordinates is given by + \param min_tang_pos_num [for projection data only] the minimum tangential position number in the new + projection line + \param max_tang_pos_num [for projection data only] the maximum tangential position number in the new + projection line + Note that the (projection of the) centre of the scanner axis is supposed to be + at \a tang_pos_num = 0. + \par images + It allows three-dimensional + zooming and translation. Parameters are derived either from + stir::CartesianCoordinate3D objects, or from the information in the \a in and \a out + images. + + In the case that the offsets are 0, the following holds: +
    +
  • If \c size is equal to \c zoom*old_size, the same amount of data is represented. +
  • If it is less, data are truncated. +
  • If it is larger, the outer ends are filled with 0. +
+ + + \warning Because overlap_interpolate is used, the zooming is 'count-preserving', + i.e. when the output range is large enough, the in.sum() == out.sum(). + \warning In STIR 1.x, origins were taken relative to the centre of the coordinate range: + \code + x_in_mm = (x_index - x_ctr_index) * voxel_size.x() + origin.x() + \endcode + where + \code + x_ctr_index = (x_max_index + x_min_index)/2 + \endcode + This is no longer true. Instead we use + DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices. + */ #include "stir/common.h" -#include "stir/DiscretisedDensity.h" -#include "stir/PostFiltering.h" -#include "stir/DataProcessor.h" -#include "stir/SeparableGaussianImageFilter.h" #include "stir/ZoomOptions.h" START_NAMESPACE_STIR @@ -104,152 +89,140 @@ template class VoxelsOnCartesianGrid; template class PixelsOnCartesianGrid; template class CartesianCoordinate3D; template class BasicCoordinate; + /*! \ingroup buildblock - \name Functions for interpolating data to new pixel/bin sizes -*/ + \name Functions for interpolating data to new pixel/bin sizes + */ //@{ /*! - \brief zoom a RelatedViewgrams object, replacing it with the new data - \see zoom.h for parameter info -*/ + \brief zoom a RelatedViewgrams object, replacing it with the new data + \see zoom.h for parameter info + */ void -zoom_viewgrams (RelatedViewgrams& viewgrams, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); +zoom_viewgrams (RelatedViewgrams& viewgrams, + const float zoom, + const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); /*! - \brief zoom \a viewgram, replacing it with the new data - \see zoom.h for parameter info -*/ + \brief zoom \a viewgram, replacing it with the new data + \see zoom.h for parameter info + */ void -zoom_viewgram (Viewgram& viewgram, - const float zoom, - const int min_tang_pos_num, const int max_tang_pos_num, - const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); +zoom_viewgram (Viewgram& viewgram, + const float zoom, + const int min_tang_pos_num, const int max_tang_pos_num, + const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); /*! - \brief zoom \a in_viewgram, replacing \a out_viewgram with the new data - - This version of zoom_viewgram gets the info on the new sizes, sampling etc. - from \a out_viewgram. + \brief zoom \a in_viewgram, replacing \a out_viewgram with the new data + + This version of zoom_viewgram gets the info on the new sizes, sampling etc. + from \a out_viewgram. \see zoom.h for parameter info -*/ + */ void -zoom_viewgram (Viewgram& out_viewgram, - const Viewgram& in_viewgram, - const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); +zoom_viewgram (Viewgram& out_viewgram, + const Viewgram& in_viewgram, + const float x_offset_in_mm = 0, const float y_offset_in_mm = 0); /*! - \brief zoom \a image, returning the new image - \see zoom.h for parameter info - - \see zoom_image_in_place -*/ + \brief zoom \a image, returning the new image + \see zoom.h for parameter info + \see zoom_image_in_place + */ VoxelsOnCartesianGrid zoom_image(const VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes); - -/*! - \brief - zoom \a image, replacing the first argument with the new data. - Full 3D shifts and zooms. - \see zoom.h for parameter info. - - Zooming is done such that the physical coordinates of a point - (as returned by - DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices) - remain the same. - - The index range of the new image is according to the standard STIR - conventions (z starts from 0, but x and y from -(new_size/2)). - The origin is then chosen such that the geometric centres of the - images satisfy - \verbatim - offsets_in_mm == new_middle - old_middle - \endverbatim - The geometric centre is determined by the average of the physical - coordinates of the min and max indices. - - \warning: For even-sized images, this convention can lead to somewhat - non-intuitive results (half-pixel shifts etc). -*/ + const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, + const BasicCoordinate<3,int>& new_sizes, + const ZoomOptions = ZoomOptions::preserve_sum); + +/*! + \brief + zoom \a image, replacing the first argument with the new data. + Full 3D shifts and zooms. + \see zoom.h for parameter info. + Zooming is done such that the physical coordinates of a point + (as returned by + DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices) + remain the same. + The index range of the new image is according to the standard STIR + conventions (z starts from 0, but x and y from -(new_size/2)). + The origin is then chosen such that the geometric centres of the + images satisfy + \verbatim + offsets_in_mm == new_middle - old_middle + \endverbatim + The geometric centre is determined by the average of the physical + coordinates of the min and max indices. + \warning: For even-sized images, this convention can lead to somewhat + non-intuitive results (half-pixel shifts etc). + */ void zoom_image_in_place(VoxelsOnCartesianGrid &image, - const CartesianCoordinate3D& zooms, - const CartesianCoordinate3D& offsets_in_mm, - const BasicCoordinate<3,int>& new_sizes); + const CartesianCoordinate3D& zooms, + const CartesianCoordinate3D& offsets_in_mm, + const BasicCoordinate<3,int>& new_sizes, + const ZoomOptions = ZoomOptions::preserve_sum); /*! \brief zoom \a image_in according to dimensions, origin and voxel_size of \a image_out. - \see zoom.h for parameter info - - Zooming is done such that the physical coordinates of a point - (as returned by - DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices) - remain the same. -*/ - - -void -zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const ZoomOptions::ZO &zo = ZoomOptions::preserve_sum); - - + \see zoom.h for parameter info + Zooming is done such that the physical coordinates of a point + (as returned by + DiscretisedDensity\<3,float\>::get_physical_coordinates_for_indices) + remain the same. + The code also provides for three possible rescaling options: + (i) preserving the image values: should be used when zooming an attenuation image + (ii) preserving the image projectors: should be used when zooming an activity image + (iii) preserving the image sum: default + */ void zoom_image(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const ZoomOptions::ZO &zo = ZoomOptions::preserve_sum); - - - -void -zoom_image_matlab(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const std::string& postfilter_parameter_filename, const int &zoom_option = 0); - + const VoxelsOnCartesianGrid &image_in, + const ZoomOptions = ZoomOptions::preserve_sum); -void -zoom_image_matlab(VoxelsOnCartesianGrid &image_out, - const VoxelsOnCartesianGrid &image_in, const int &zoom_option = 0); //------------------ 2D zooms--------------------- -/*! -\brief -zoom \a image2D_in according to dimensions, origin and pixel_size of -\a image2D_out. - \see zoom.h for parameter info -*/ +/*! + \brief + zoom \a image2D_in according to dimensions, origin and pixel_size of + \a image2D_out. + \see zoom.h for parameter info + */ void -zoom_image(PixelsOnCartesianGrid &image2D_out, - const PixelsOnCartesianGrid &image2D_in); +zoom_image(PixelsOnCartesianGrid &image2D_out, + const PixelsOnCartesianGrid &image2D_in, + const ZoomOptions = ZoomOptions::preserve_sum); /*! - \brief zoom \a image, replacing the first argument with the new data - \see zoom.h for parameter info -*/ + \brief zoom \a image, replacing the first argument with the new data + \see zoom.h for parameter info + */ VoxelsOnCartesianGrid zoom_image(const VoxelsOnCartesianGrid &image, - const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size); + const float zoom, + const float x_offset_in_mm, const float y_offset_in_mm, + const int new_size, + const ZoomOptions = ZoomOptions::preserve_sum); /*! - \brief zoom \a image, replacing the first argument with the new data - \see zoom.h for parameter info -*/ + \brief zoom \a image, replacing the first argument with the new data + \see zoom.h for parameter info + */ void zoom_image_in_place(VoxelsOnCartesianGrid &image, - const float zoom, - const float x_offset_in_mm, const float y_offset_in_mm, - const int new_size); + const float zoom, + const float x_offset_in_mm, const float y_offset_in_mm, + const int new_size, + const ZoomOptions = ZoomOptions::preserve_sum); //@} END_NAMESPACE_STIR #endif - From e0e3adc848c44f8279d9e50105e3f960a7967f3e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 4 Jul 2019 12:44:44 +0100 Subject: [PATCH 104/274] unit test --- src/buildblock/extend_projdata.cxx | 1 - src/test/test_upsample.cxx | 95 ++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 14f144eebb..d2b7f529cc 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -189,7 +189,6 @@ extend_segment_in_views(const SegmentBySinogram& sino, extend_sinogram_in_views(sino[ax_pos_num],sino[ax_pos_num], *(sino.get_proj_data_info_ptr()), min_view_extension, max_view_extension); - //out[min[1]]=out[min[1]+1]; } return out; } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 7ea89bf774..99bfc02720 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -36,6 +36,9 @@ #include "stir/ProjDataInfoCylindricalNoArcCorr.h" #include "stir/scatter/SingleScatterSimulation.h" #include "stir/scatter/ScatterEstimation.h" +#include "stir/Sinogram.h" +#include "stir/Array.h" + START_NAMESPACE_STIR @@ -53,53 +56,83 @@ run_tests() { std::cout << "-------- Testing Upsampling and Downsampling --------\n"; - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); shared_ptr exam_info_sptr(new ExamInfo); shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr - (ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ false)); //creating low resolution proj data info - shared_ptr LR_proj_data_info_sptr - (ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ false)); + shared_ptr LR_proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ false)); + // construct y + ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); + // construct x + ProjDataInMemory x(LR_exam_info_sptr, LR_proj_data_info_sptr); - // construct projdata - ProjDataInMemory proj_data(exam_info_sptr, proj_data_info_sptr); - { - Sinogram sinogram = proj_data.get_sinogram(0,0); - check_if_equal(sinogram.find_min(),0.F,"test constructor and get_sinogram"); - } + // construct Ax + ProjDataInMemory Ax(exam_info_sptr, proj_data_info_sptr); + // construct x + ProjDataInMemory Aty(LR_exam_info_sptr, LR_proj_data_info_sptr); - // construct LR projdata - ProjDataInMemory LR_proj_data(LR_exam_info_sptr, LR_proj_data_info_sptr); - { - Sinogram LR_sinogram = LR_proj_data.get_sinogram(0,0); - check_if_equal(LR_sinogram.find_min(), 0.F, "test constructor and get_sinogram"); - } - proj_data.fill(1); - LR_proj_data.fill(1); - std::cout << "TEST: 3D size:"<< proj_data.get_num_segments() << "x"<< proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; -std::cout << "TEST LR: 3D size:"<< LR_proj_data.get_num_segments() << "x"<< LR_proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << LR_proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; + x.fill(1); + y.fill(1); - ProjDataInMemory scaled_proj_data = proj_data; - scaled_proj_data.fill(1); + Ax.fill(0); //initialise output + Aty.fill(0); //initialise output - //std::cout << "TEST: g scaled size:"<< scaled_proj_data.get_num_segments() << "x"<< scaled_proj_data.get_segment_by_sinogram(0).get_num_views()<< "x" << scaled_proj_data.get_segment_by_sinogram(0).get_num_tangential_poss()<< '\n'; - - std::cout << "-------- Testing Pull --------\n"; - ScatterEstimation::pull_scatter_estimate(scaled_proj_data,proj_data,LR_proj_data,true); + bool remove_interleaving = false; + std::cout << "-------- Testing Pull --------\n"; + ScatterEstimation::pull_scatter_estimate(Ax,y,x,remove_interleaving); std::cout << "-------- Testing Push --------\n"; - ProjDataInMemory LR_scaled_proj_data = LR_proj_data; - LR_scaled_proj_data.fill(1); - ScatterEstimation::push_scatter_estimate(LR_scaled_proj_data,LR_proj_data,scaled_proj_data,true); - + ScatterEstimation::push_scatter_estimate(Aty,x,y,remove_interleaving); + + std::cout << "-------- = --------\n"; + + float cdot1 = 0; + float cdot2 = 0; + + for ( int segment_num = y.get_min_segment_num(); segment_num <= y.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = y.get_min_axial_pos_num(segment_num); axial_pos <= y.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram y_sinogram = y.get_sinogram(axial_pos, segment_num); + const Sinogram Ax_sinogram = Ax.get_sinogram(axial_pos, segment_num); + + for ( int view_num = y.get_min_view_num(); view_num <= y.get_max_view_num();view_num++) + { + for ( int tang_pos = y.get_min_tangential_pos_num(); tang_pos <= y.get_max_tangential_pos_num(); tang_pos++) + { + cdot1 += Ax_sinogram[view_num][tang_pos]*y_sinogram[view_num][tang_pos]; + } + } + } + } + + for ( int segment_num = x.get_min_segment_num(); segment_num <= x.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = x.get_min_axial_pos_num(segment_num); axial_pos <= x.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram x_sinogram = x.get_sinogram(axial_pos, segment_num); + const Sinogram Aty_sinogram = Aty.get_sinogram(axial_pos, segment_num); + + for ( int view_num = x.get_min_view_num(); view_num <= x.get_max_view_num();view_num++) + { + for ( int tang_pos = x.get_min_tangential_pos_num(); tang_pos <= x.get_max_tangential_pos_num(); tang_pos++) + { + cdot2 += x_sinogram[view_num][tang_pos]*Aty_sinogram[view_num][tang_pos]; + } + } + } + } + + std::cout << cdot1 << "=" << cdot2 << '\n'; } From fc81ae6084c5d928a5c4cba8ae788d51fd35a3fb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 4 Jul 2019 12:57:25 +0100 Subject: [PATCH 105/274] ok --- src/buildblock/extend_projdata.cxx | 13 ++++++++++--- src/test/test_upsample.cxx | 6 +++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index d2b7f529cc..82a59cae2d 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -137,8 +137,8 @@ namespace detail const float min_view_compression, const float max_view_compression) { //* Check if projdata are from 0 to pi-phi - bool min_is_extended=false; - bool max_is_extended=false; + bool min_is_compressed=false; + bool max_is_compressed=false; BasicCoordinate<2,int> min_in, max_in; if (!sino_segment.get_regular_range(min_in, max_in)) { @@ -151,6 +151,13 @@ namespace detail min_in[1]+=min_view_compression; //here the new min is bigger than the original max_in[1]-=max_view_compression; //here the new max is smaller than the original + const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); + const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); + + const float sampling_phi = + proj_data_info.get_phi(Bin(0,1,0,0)) - min_phi; + const int num_views_for_180 = round(_PI/sampling_phi); + IndexRange<2> compressed_range(min_in, max_in); Array<2,float> input_compressed_view(compressed_range); @@ -160,7 +167,7 @@ namespace detail } // loop over views - input_compressed_view[min_in[1]]+=sino_segment[max_in[1]+1];//boundary condition + input_compressed_view[min_in[1]]+=sino_segment[min_in[1]+num_views_for_180];//boundary condition return input_compressed_view; } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 99bfc02720..6d9c84b95b 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -61,10 +61,10 @@ run_tests() shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ false)); //creating low resolution proj data info - shared_ptr LR_proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ false)); + shared_ptr LR_proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ false)); // construct y ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); @@ -77,7 +77,7 @@ run_tests() ProjDataInMemory Aty(LR_exam_info_sptr, LR_proj_data_info_sptr); - x.fill(1); + x.fill(0.2); y.fill(1); Ax.fill(0); //initialise output From 87d55747a3dcf289e6962bad8202b6e4b616542f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 4 Jul 2019 15:10:34 +0100 Subject: [PATCH 106/274] test --- src/test/test_upsample.cxx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 6d9c84b95b..cde9570c86 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -54,17 +54,16 @@ void UpsampleDownsampleTests:: run_tests() { - std::cout << "-------- Testing Upsampling and Downsampling --------\n"; + std::cout << "-------- Testing Upsampling and Downsampling ---------\n"; - shared_ptr scanner_sptr(new Scanner(Scanner::E953)); + shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); shared_ptr exam_info_sptr(new ExamInfo); shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 96, /*tang_pos*/128, /*arc_corrected*/ false)); - + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); //creating low resolution proj data info - shared_ptr LR_proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 24, /*tang_pos*/32, /*arc_corrected*/ false)); + shared_ptr LR_proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 21, /*tang_pos*/31, /*arc_corrected*/ false)); // construct y ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); @@ -77,7 +76,7 @@ run_tests() ProjDataInMemory Aty(LR_exam_info_sptr, LR_proj_data_info_sptr); - x.fill(0.2); + x.fill(1); y.fill(1); Ax.fill(0); //initialise output From c0238d8c9befd645ebda09c36a21601d8b6c0c12 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 4 Jul 2019 21:37:22 +0100 Subject: [PATCH 107/274] works only for segm 0 --- src/include/stir/scatter/ScatterSimulation.h | 12 +- src/scatter_buildblock/ScatterSimulation.cxx | 125 ++++++++++++++----- src/test/test_upsample.cxx | 20 ++- 3 files changed, 120 insertions(+), 37 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 9f006dfc82..0a71e3dbc0 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -144,11 +144,18 @@ class ScatterSimulation : public RegisteredObject, shared_ptr get_output_proj_data_sptr(); + //! Get the template ProjDataInfo + shared_ptr get_template_proj_data_info_sptr() const; + //! Get the ExamInfo as shared pointer + shared_ptr get_ExamInfo_sptr() const; + //! \details Load the scatter template and perform basic checks. - void set_template_proj_data_info_sptr(const shared_ptr&); + void set_template_proj_data_info_sptr(shared_ptr); void set_template_proj_data_info(const std::string&); + void set_template_proj_data_info(const ProjDataInfo&); + void set_activity_image_sptr(const shared_ptr >&); void set_activity_image(const std::string& filename); @@ -205,6 +212,8 @@ class ScatterSimulation : public RegisteredObject, //@} +Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); + protected: //! computes scatter for one viewgram @@ -216,7 +225,6 @@ class ScatterSimulation : public RegisteredObject, compute_emis_to_det_points_solid_angle_factor(const CartesianCoordinate3D& emis_point, const CartesianCoordinate3D& detector_coord); - shared_ptr downsample_scanner(shared_ptr arg); virtual void set_defaults(); virtual void initialise_keymap(); diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 477ae61b90..972805fcc8 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -516,26 +516,13 @@ set_output_proj_data_sptr(shared_ptr& arg) void ScatterSimulation:: -set_template_proj_data_info_sptr(const shared_ptr& arg) +set_template_proj_data_info_sptr(shared_ptr arg) { this->proj_data_info_cyl_noarc_cor_sptr.reset(dynamic_cast(arg->clone())); if (is_null_ptr(this->proj_data_info_cyl_noarc_cor_sptr)) error("ScatterSimulation: Can only handle non-arccorrected data"); - if (downsample_scanner_dets > 1 || downsample_scanner_rings > 1) - this->proj_data_info_cyl_noarc_cor_sptr.reset( - dynamic_cast(downsample_scanner(proj_data_info_cyl_noarc_cor_sptr)->clone()) ); - - - if (this->proj_data_info_cyl_noarc_cor_sptr->get_num_segments() > 1) // do SSRB - { - info("ScatterSimulation: Performing SSRB on template info ..."); - this->proj_data_info_cyl_noarc_cor_sptr.reset( - dynamic_cast(SSRB(* this->proj_data_info_cyl_noarc_cor_sptr, - this->proj_data_info_cyl_noarc_cor_sptr->get_num_segments(), 1, false))); - } - // find final size of detection_points_vector this->total_detectors = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_rings()* @@ -549,6 +536,20 @@ set_template_proj_data_info_sptr(const shared_ptr& arg) this->remove_cache_for_integrals_over_activity(); } + +shared_ptr +ScatterSimulation:: +get_template_proj_data_info_sptr() const +{ + return this->proj_data_info_cyl_noarc_cor_sptr; +} + +shared_ptr +ScatterSimulation::get_ExamInfo_sptr() const +{ + return this->template_exam_info_sptr; +} + void ScatterSimulation:: set_template_proj_data_info(const std::string& filename) @@ -564,6 +565,29 @@ set_template_proj_data_info(const std::string& filename) this->set_template_proj_data_info_sptr(tmp_proj_data_info_sptr); + if (downsample_scanner_dets > 1 || downsample_scanner_rings > 1) + downsample_scanner(); +} + +void +ScatterSimulation::set_template_proj_data_info(const ProjDataInfo& arg) +{ + this->proj_data_info_cyl_noarc_cor_sptr.reset(dynamic_cast(arg.clone())); + + if (is_null_ptr(this->proj_data_info_cyl_noarc_cor_sptr)) + error("ScatterSimulation: Can only handle non-arccorrected data"); + + // find final size of detection_points_vector + this->total_detectors = + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_rings()* + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_detectors_per_ring (); + + // reserve space to avoid reallocation, but the actual size will grow dynamically + this->detection_points_vector.reserve(static_cast(this->total_detectors)); + + // remove any cached values as they'd be incorrect if the sizes changes + this->remove_cache_for_integrals_over_attenuation(); + this->remove_cache_for_integrals_over_activity(); } void @@ -573,30 +597,69 @@ set_exam_info_sptr(const shared_ptr& arg) this->template_exam_info_sptr = arg; } -shared_ptr -ScatterSimulation:: -downsample_scanner(shared_ptr arg) +Succeeded +ScatterSimulation::downsample_scanner(int new_num_rings, int new_num_dets) { + if (new_num_rings == -1) + if(downsample_scanner_rings > -1) + new_num_rings = downsample_scanner_rings; + else + return Succeeded::no; - // copy localy. - info("ScatterSimulator: Downsampling scanner of template info ..."); - shared_ptr new_scanner_sptr( new Scanner(*arg->get_scanner_ptr())); + if (new_num_dets == -1) + if(downsample_scanner_dets > -1) + new_num_dets = downsample_scanner_dets; + else + return Succeeded::no; - // preserve the lenght of the scanner - float scanner_lenght = new_scanner_sptr->get_num_rings()* new_scanner_sptr->get_ring_spacing(); - new_scanner_sptr->set_num_rings(static_cast(new_scanner_sptr->get_num_rings()/downsample_scanner_rings)); - new_scanner_sptr->set_num_detectors_per_ring(static_cast(new_scanner_sptr->get_num_detectors_per_ring()/downsample_scanner_dets)); - new_scanner_sptr->set_ring_spacing(static_cast(scanner_lenght/new_scanner_sptr->get_num_rings())); + info("ScatterSimulator: Downsampling scanner of template info ..."); + // copy localy. + shared_ptr new_scanner_sptr( new Scanner(*this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr())); + + // preserve the length of the scanner + float scanner_length = new_scanner_sptr->get_num_rings()* new_scanner_sptr->get_ring_spacing(); + + new_scanner_sptr->set_num_rings(new_num_rings); + new_scanner_sptr->set_num_detectors_per_ring(new_num_dets); + new_scanner_sptr->set_ring_spacing(static_cast(scanner_length/new_scanner_sptr->get_num_rings())); + new_scanner_sptr->set_max_num_non_arccorrected_bins(new_num_dets-1); + new_scanner_sptr->set_default_bin_size(new_scanner_sptr->get_default_bin_size()*2); + + // Find how much is the delta ring + // If the previous projdatainfo had max segment == 1 then should be from SSRB + // in ScatterEstimation. Otherwise use the max possible. + int delta_ring = proj_data_info_cyl_noarc_cor_sptr->get_num_segments() == 1 ? delta_ring = 0 : + new_scanner_sptr->get_num_rings()-1; + + this->proj_data_info_cyl_noarc_cor_sptr.reset(dynamic_cast( + ProjDataInfo::ProjDataInfoCTI(new_scanner_sptr, + 1, delta_ring, + new_scanner_sptr->get_num_detectors_per_ring()/2, + new_scanner_sptr->get_max_num_non_arccorrected_bins(), + false)->clone())); + + if(!is_null_ptr(output_proj_data_sptr)) + { + this->output_proj_data_sptr.reset(new ProjDataInMemory(this->template_exam_info_sptr, + this->proj_data_info_cyl_noarc_cor_sptr->create_shared_clone())); + this->output_proj_data_sptr->fill(0.0); + info("ScatterSimulation: output projection data created."); + } + // find final size of detection_points_vector + this->total_detectors = + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_rings()* + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_num_detectors_per_ring (); - ProjDataInfo * tmp_proj_data_info_2d_ptr = ProjDataInfo::ProjDataInfoCTI(new_scanner_sptr, - 1, 0, - new_scanner_sptr->get_num_detectors_per_ring()/2, - new_scanner_sptr->get_num_detectors_per_ring()/2, - false); + // reserve space to avoid reallocation, but the actual size will grow dynamically + this->detection_points_vector.reserve(static_cast(this->total_detectors)); + + // remove any cached values as they'd be incorrect if the sizes changes + this->remove_cache_for_integrals_over_attenuation(); + this->remove_cache_for_integrals_over_activity(); - return tmp_proj_data_info_2d_ptr->create_shared_clone(); + return Succeeded::yes; } void diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index cde9570c86..7e4a38c90b 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -39,6 +39,8 @@ #include "stir/Sinogram.h" #include "stir/Array.h" +#include "stir/IO/write_to_file.h" + START_NAMESPACE_STIR @@ -62,19 +64,28 @@ run_tests() //creating proj data info shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + + //shared_ptr HR = ProjData::read_from_file("projdata_UU.hs"); + + shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU.hs"); //creating low resolution proj data info - shared_ptr LR_proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 21, /*tang_pos*/31, /*arc_corrected*/ false)); + // construct y + //ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); + + // construct y + //ProjDataInMemory y(*HR); ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); + // construct x - ProjDataInMemory x(LR_exam_info_sptr, LR_proj_data_info_sptr); + ProjDataInMemory x(*LR); // construct Ax + // ProjDataInMemory Ax(*HR); ProjDataInMemory Ax(exam_info_sptr, proj_data_info_sptr); // construct x - ProjDataInMemory Aty(LR_exam_info_sptr, LR_proj_data_info_sptr); - + ProjDataInMemory Aty(*LR); x.fill(1); y.fill(1); @@ -132,6 +143,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; + check_if_equal(cdot1, cdot2, "test adjoint"); } From 3c53a9b17d03963bd64dccb278a823cd139b7c69 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 5 Jul 2019 08:40:51 +0100 Subject: [PATCH 108/274] status --- src/buildblock/interpolate_projdata.cxx | 1 + src/test/test_upsample.cxx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index c42275544f..679ec05b72 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -734,6 +734,7 @@ interpolate_projdata_push(ProjData& proj_data_out, SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 7e4a38c90b..7fe43860af 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -67,6 +67,7 @@ run_tests() //shared_ptr HR = ProjData::read_from_file("projdata_UU.hs"); + //system("cd /Users/luto/Documents/STIR/test_sino"); shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU.hs"); //creating low resolution proj data info // construct y From a0a6398e3f2e4c782caa5517eecdde17c84e4803 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 5 Jul 2019 09:10:06 +0100 Subject: [PATCH 109/274] bug fixed --- src/buildblock/interpolate_projdata.cxx | 8 -------- src/buildblock/inverse_SSRB.cxx | 2 ++ src/test/test_upsample.cxx | 13 ++----------- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 679ec05b72..bda1f89e25 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -557,7 +557,6 @@ interpolate_projdata_pull(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //here we are doubling the number of views extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) - extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; open_write_binary(s, "extended_before_interopolation.data"); write_data(s,extended); @@ -574,7 +573,6 @@ interpolate_projdata_pull(ProjData& proj_data_out, { Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) - extend_axial_position(extended); // here we are adding one axial position before and after max and min index (for the interpolation) std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -671,7 +669,6 @@ interpolate_projdata_push(ProjData& proj_data_out, const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_out.get_segment_by_sinogram(0)); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment,2,2); //extend the views extend_tangential_position(extended); //extend the tangential positions - extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; // ===========================PUSH ================================== @@ -681,7 +678,6 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== - transpose_extend_axial_position(extended); //reduce axial positions transpose_extend_tangential_position(extended); //reduce tangential positions SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out @@ -709,7 +705,6 @@ interpolate_projdata_push(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); //extend the views extend_tangential_position(extended); //extend the tangential positions - extend_axial_position(extended); //extend the axial positions std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; @@ -720,7 +715,6 @@ interpolate_projdata_push(ProjData& proj_data_out, //sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== - transpose_extend_axial_position(extended); transpose_extend_tangential_position(extended); shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended @@ -738,8 +732,6 @@ interpolate_projdata_push(ProjData& proj_data_out, proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) - // proj_data_out.set_segment(sino_3D_out); - // if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; } diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 6db6cb4d97..404d4bc505 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -66,9 +66,11 @@ inverse_SSRB(ProjData& proj_data_4D, Sinogram sino_4D = proj_data_4D. get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + std::cout<< "SSRB-4D" << proj_data_4D.get_max_axial_pos_num(0) << '\n'; Sinogram sino_3D = proj_data_3D. get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); + std::cout<< "SSRB-3D"<< proj_data_3D.get_max_axial_pos_num(0) << '\n'; for (int out_segment_num = proj_data_4D.get_min_segment_num(); out_segment_num <= proj_data_4D.get_max_segment_num(); diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 7fe43860af..0ee93aa241 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -65,31 +65,22 @@ run_tests() //creating proj data info shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); - //shared_ptr HR = ProjData::read_from_file("projdata_UU.hs"); - - //system("cd /Users/luto/Documents/STIR/test_sino"); shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU.hs"); - //creating low resolution proj data info - // construct y - //ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); - - // construct y - //ProjDataInMemory y(*HR); ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); // construct x ProjDataInMemory x(*LR); // construct Ax - // ProjDataInMemory Ax(*HR); + ProjDataInMemory Ax(exam_info_sptr, proj_data_info_sptr); // construct x ProjDataInMemory Aty(*LR); x.fill(1); - y.fill(1); + y.fill(2); Ax.fill(0); //initialise output Aty.fill(0); //initialise output From d4f2e4a81fa9477923fd6c2c3cdce419e736b4ea Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 5 Jul 2019 10:50:17 +0100 Subject: [PATCH 110/274] test ok --- src/buildblock/interpolate_projdata.cxx | 4 +- src/test/test_upsample.cxx | 66 ++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index bda1f89e25..04e68615f9 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -228,9 +228,9 @@ namespace detail_interpolate_projdata //CORNERS out_sinogram[first_view][in_sinogram.get_min_tangential_pos_num()] = - (in_sinogram[first_view][(in_sinogram.get_max_tangential_pos_num()-1)])/4; + (in_sinogram[first_view][(in_sinogram.get_max_tangential_pos_num())])/4; out_sinogram[first_view][in_sinogram.get_max_tangential_pos_num()] = - (in_sinogram[first_view][(in_sinogram.get_min_tangential_pos_num()+1)])/4; + (in_sinogram[first_view][(in_sinogram.get_min_tangential_pos_num())])/4; } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 0ee93aa241..bd3c6abf99 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -65,7 +65,7 @@ run_tests() //creating proj data info shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); - shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU.hs"); + shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); // construct y ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); @@ -86,6 +86,9 @@ run_tests() Aty.fill(0); //initialise output bool remove_interleaving = false; + + std::cout << "========== REMOVE INTERLEAVING = FALSE =========== \n"; + std::cout << "-------- Testing Pull --------\n"; ScatterEstimation::pull_scatter_estimate(Ax,y,x,remove_interleaving); @@ -137,6 +140,67 @@ run_tests() std::cout << cdot1 << "=" << cdot2 << '\n'; check_if_equal(cdot1, cdot2, "test adjoint"); + + std::cout << "========== REMOVE INTERLEAVING = TRUE =========== \n"; + + Ax.fill(0); //initialise output + Aty.fill(0); //initialise output + + remove_interleaving = true; + + std::cout << "-------- Testing Pull --------\n"; + ScatterEstimation::pull_scatter_estimate(Ax,y,x,remove_interleaving); + + std::cout << "-------- Testing Push --------\n"; + + ScatterEstimation::push_scatter_estimate(Aty,x,y,remove_interleaving); + + std::cout << "-------- = --------\n"; + + cdot1 = 0; + cdot2 = 0; + + for ( int segment_num = y.get_min_segment_num(); segment_num <= y.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = y.get_min_axial_pos_num(segment_num); axial_pos <= y.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram y_sinogram = y.get_sinogram(axial_pos, segment_num); + const Sinogram Ax_sinogram = Ax.get_sinogram(axial_pos, segment_num); + + for ( int view_num = y.get_min_view_num(); view_num <= y.get_max_view_num();view_num++) + { + for ( int tang_pos = y.get_min_tangential_pos_num(); tang_pos <= y.get_max_tangential_pos_num(); tang_pos++) + { + cdot1 += Ax_sinogram[view_num][tang_pos]*y_sinogram[view_num][tang_pos]; + } + } + } + } + + for ( int segment_num = x.get_min_segment_num(); segment_num <= x.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = x.get_min_axial_pos_num(segment_num); axial_pos <= x.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram x_sinogram = x.get_sinogram(axial_pos, segment_num); + const Sinogram Aty_sinogram = Aty.get_sinogram(axial_pos, segment_num); + + for ( int view_num = x.get_min_view_num(); view_num <= x.get_max_view_num();view_num++) + { + for ( int tang_pos = x.get_min_tangential_pos_num(); tang_pos <= x.get_max_tangential_pos_num(); tang_pos++) + { + cdot2 += x_sinogram[view_num][tang_pos]*Aty_sinogram[view_num][tang_pos]; + } + } + } + } + + std::cout << cdot1 << "=" << cdot2 << '\n'; + check_if_equal(cdot1, cdot2, "test adjoint"); + + + } END_NAMESPACE_STIR From 1b067ff7763bfb69521c2025957a5ec8987e75eb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 5 Jul 2019 11:20:40 +0100 Subject: [PATCH 111/274] test ok --- src/test/test_upsample.cxx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index bd3c6abf99..0a25c83ddd 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -65,19 +65,32 @@ run_tests() //creating proj data info shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); - shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); + // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); + // construct y ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); + + unique_ptr sss(new SingleScatterSimulation()); + sss->set_template_proj_data_info_sptr(proj_data_info_sptr); + int down_rings = static_cast(scanner_sptr->get_num_rings()/8); + int down_dets = static_cast(scanner_sptr->get_max_num_views()/12); + + sss->downsample_scanner(down_rings, down_dets); + + + shared_ptr sss_projdata(sss->get_template_proj_data_info_sptr()); + + // construct x - ProjDataInMemory x(*LR); + ProjDataInMemory x(sss->get_ExamInfo_sptr(), sss->get_template_proj_data_info_sptr()); // construct Ax ProjDataInMemory Ax(exam_info_sptr, proj_data_info_sptr); // construct x - ProjDataInMemory Aty(*LR); + ProjDataInMemory Aty(sss->get_ExamInfo_sptr(), sss->get_template_proj_data_info_sptr()); x.fill(1); y.fill(2); From fb066e29fba7bd99459a00b2ececc043e5939dc3 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 5 Jul 2019 20:10:38 +0100 Subject: [PATCH 112/274] works for 0 --- src/buildblock/inverse_SSRB.cxx | 70 +++++++++++++++++++ src/include/stir/inverse_SSRB.h | 3 + .../upsample_and_fit_scatter_estimate.cxx | 20 +++--- src/test/test_upsample.cxx | 2 + 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 404d4bc505..eef8afb9db 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -123,4 +123,74 @@ inverse_SSRB(ProjData& proj_data_4D, } return Succeeded::yes; } + + +Succeeded +transpose_inverse_SSRB(ProjData& proj_data_3D, + const ProjData& proj_data_4D) +{ + const ProjDataInfo * const proj_data_3D_info_ptr = + dynamic_cast + (proj_data_3D.get_proj_data_info_ptr()); + const ProjDataInfo * const proj_data_4D_info_ptr = + dynamic_cast + (proj_data_4D.get_proj_data_info_ptr()); + if ((proj_data_3D_info_ptr->get_min_view_num() != + proj_data_4D_info_ptr->get_min_view_num()) || + (proj_data_3D_info_ptr->get_min_view_num() != + proj_data_4D_info_ptr->get_min_view_num())) + { + warning("inverse_SSRB: incompatible view-information"); + return Succeeded::no; + } + if ((proj_data_3D_info_ptr->get_min_tangential_pos_num() != + proj_data_4D_info_ptr->get_min_tangential_pos_num()) || + (proj_data_3D_info_ptr->get_min_tangential_pos_num() != + proj_data_4D_info_ptr->get_min_tangential_pos_num())) + { + warning("inverse_SSRB: incompatible tangential_pos-information"); + return Succeeded::no; + } + + // keep sinograms out of the loop to avoid reallocations + // initialise to something because there's no default constructor + Sinogram sino_4D = + proj_data_4D. + get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + std::cout<< "SSRB-4D" << proj_data_4D.get_max_axial_pos_num(0) << '\n'; + Sinogram sino_3D = + proj_data_3D. + get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); + std::cout<< "SSRB-3D"<< proj_data_3D.get_max_axial_pos_num(0) << '\n'; + + for (int out_segment_num = proj_data_4D.get_min_segment_num(); + out_segment_num <= proj_data_4D.get_max_segment_num(); + ++out_segment_num) + { + for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); + out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); + ++out_ax_pos_num ) + { + sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num); + const float out_m = + proj_data_4D_info_ptr-> + get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); + int num_contributing_sinos = 0; + + for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); + out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); + ++out_ax_pos_num ) + { + sino_3D = proj_data_3D.get_sinogram(out_ax_pos_num,0); + sino_4D = proj_data_4D.get_sinogram(out_ax_pos_num,out_segment_num); + sino_3D+=sino_4D; + sino_3D*=0.5; + + proj_data_3D.set_sinogram(sino_3D); + } + } + } + return Succeeded::yes; +} + END_NAMESPACE_STIR diff --git a/src/include/stir/inverse_SSRB.h b/src/include/stir/inverse_SSRB.h index 06c41464ab..ccbfee0c6a 100644 --- a/src/include/stir/inverse_SSRB.h +++ b/src/include/stir/inverse_SSRB.h @@ -56,5 +56,8 @@ Succeeded inverse_SSRB(ProjData& proj_data_4D, const ProjData& proj_data_3D); +Succeeded +transpose_inverse_SSRB(ProjData& proj_data_4D, + const ProjData& proj_data_3D); END_NAMESPACE_STIR diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 2e852302f1..2a6e922545 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -180,19 +180,23 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, const bool remove_interleaving) { - shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(scatter_proj_data.get_proj_data_info_ptr()->clone()); + ProjDataInMemory interpolated_direct_scatter(scatter_proj_data.get_exam_info_sptr(),interpolated_direct_scatter_proj_data_info_sptr); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); - info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); - ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), - interpolated_direct_scatter_proj_data_info_sptr); + //transpose SSRB on scatter_proj_data + transpose_inverse_SSRB(interpolated_direct_scatter, scatter_proj_data); - interpolate_projdata_push(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); - std::cerr << "PUSH.." << '\n'; - // Perform Inverse Single Slice Rebinning - inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + + interpolate_projdata_push(scaled_scatter_proj_data, interpolated_direct_scatter, remove_interleaving); + + //transpose reduce segment on interpolated_direct_scatter + + + //extend segment } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 0a25c83ddd..fdf71302bf 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -151,6 +151,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; + set_tolerance(0.05); check_if_equal(cdot1, cdot2, "test adjoint"); @@ -210,6 +211,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; + set_tolerance(0.05); check_if_equal(cdot1, cdot2, "test adjoint"); From 7807b2e14e2289333a905b38b96a8341d9224464 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 5 Jul 2019 20:28:18 +0100 Subject: [PATCH 113/274] ok --- src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx | 2 +- src/test/test_upsample.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 2a6e922545..ad1fafe227 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -181,9 +181,9 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, { shared_ptr interpolated_direct_scatter_proj_data_info_sptr(scatter_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); ProjDataInMemory interpolated_direct_scatter(scatter_proj_data.get_exam_info_sptr(),interpolated_direct_scatter_proj_data_info_sptr); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); //transpose SSRB on scatter_proj_data diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index fdf71302bf..db765f8e22 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -63,7 +63,7 @@ run_tests() shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); From 8f1c215974e44202b3f4be6c0b62c051ea2f07c7 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 5 Jul 2019 20:35:59 +0100 Subject: [PATCH 114/274] check loop --- src/buildblock/inverse_SSRB.cxx | 31 ++++++++++++++----------------- src/test/test_upsample.cxx | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index eef8afb9db..147ac76d5a 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -163,26 +163,23 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); std::cout<< "SSRB-3D"<< proj_data_3D.get_max_axial_pos_num(0) << '\n'; - for (int out_segment_num = proj_data_4D.get_min_segment_num(); - out_segment_num <= proj_data_4D.get_max_segment_num(); - ++out_segment_num) - { - for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); - out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); + + for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); + out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) { - sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num); - const float out_m = - proj_data_4D_info_ptr-> - get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); - int num_contributing_sinos = 0; - - for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); - out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); - ++out_ax_pos_num ) + sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); + + for (int in_segment_num = proj_data_4D.get_min_segment_num(); + in_segment_num <= proj_data_4D.get_max_segment_num(); + ++in_segment_num) + { + + for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num); + in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); + ++in_ax_pos_num ) { - sino_3D = proj_data_3D.get_sinogram(out_ax_pos_num,0); - sino_4D = proj_data_4D.get_sinogram(out_ax_pos_num,out_segment_num); + sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); sino_3D+=sino_4D; sino_3D*=0.5; diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index db765f8e22..fdf71302bf 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -63,7 +63,7 @@ run_tests() shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); From 449d59586f27496fbdfee83cfad9b3f82ea8659d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 6 Jul 2019 10:50:06 +0100 Subject: [PATCH 115/274] ssrb --- src/buildblock/inverse_SSRB.cxx | 21 ++++++++++++++++++--- src/test/test_upsample.cxx | 29 +++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 147ac76d5a..2b475f9181 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -169,6 +169,7 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, ++out_ax_pos_num ) { sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); + const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); for (int in_segment_num = proj_data_4D.get_min_segment_num(); in_segment_num <= proj_data_4D.get_max_segment_num(); @@ -179,11 +180,25 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num ) { + + const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, out_ax_pos_num, 0)); sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); - sino_3D+=sino_4D; - sino_3D*=0.5; + if (fabs(in_m - out_m) < 1E-2) + { + sino_3D += sino_4D; + sino_3D*=.5F; + proj_data_3D.set_sinogram(sino_3D); + } + const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? + -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, in_ax_pos_num+1, 0)); + + if (fabs(.5F*(out_m + out_m_next-in_m)) < 1E-2) + { + sino_3D+=sino_4D; + sino_3D+=proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); + proj_data_3D.set_sinogram(sino_3D); + } - proj_data_3D.set_sinogram(sino_3D); } } } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index fdf71302bf..41d65f6cb3 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -50,8 +50,31 @@ class UpsampleDownsampleTests: public RunTests { public: void run_tests(); + void fill_projdata_with_random(ProjData & projdata); }; +void +UpsampleDownsampleTests:: +fill_projdata_with_random(ProjData & projdata) +{ + for ( int segment_num = projdata.get_min_segment_num(); segment_num <= projdata.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = projdata.get_min_axial_pos_num(segment_num); axial_pos <= projdata.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram p_sinogram = projdata.get_sinogram(axial_pos, segment_num); + + for ( int view_num = projdata.get_min_view_num(); view_num <= projdata.get_max_view_num();view_num++) + { + for ( int tang_pos = projdata.get_min_tangential_pos_num(); tang_pos <= projdata.get_max_tangential_pos_num(); tang_pos++) + { + //p_sinogram[view_num][tang_pos]=2; + projdata.set_sinogram(p_sinogram); + } + } + } + } +} void UpsampleDownsampleTests:: run_tests() @@ -63,7 +86,7 @@ run_tests() shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); @@ -92,8 +115,10 @@ run_tests() // construct x ProjDataInMemory Aty(sss->get_ExamInfo_sptr(), sss->get_template_proj_data_info_sptr()); - x.fill(1); + x.fill(0.5); y.fill(2); + // fill_projdata_with_random(x); + // fill_projdata_with_random(y); Ax.fill(0); //initialise output Aty.fill(0); //initialise output From fa10a0443f4d97abfc0ae9b284d3d79a86ed1202 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 8 Jul 2019 14:18:24 +0100 Subject: [PATCH 116/274] ok --- .../upsample_and_fit_scatter_estimate.cxx | 20 ++++++------------- src/test/test_upsample.cxx | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index ad1fafe227..275e4ba2d5 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -157,7 +157,7 @@ pull_scatter_estimate(ProjData& scaled_scatter_proj_data, { shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); //create the output template info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); @@ -180,23 +180,15 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, const bool remove_interleaving) { - shared_ptr interpolated_direct_scatter_proj_data_info_sptr(scatter_proj_data.get_proj_data_info_ptr()->clone()); - interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); - ProjDataInMemory interpolated_direct_scatter(scatter_proj_data.get_exam_info_sptr(),interpolated_direct_scatter_proj_data_info_sptr); - - - - //transpose SSRB on scatter_proj_data - - transpose_inverse_SSRB(interpolated_direct_scatter, scatter_proj_data); - + shared_ptr new_input_proj_data_info_sptr(scatter_proj_data.get_proj_data_info_ptr()->clone()); + new_input_proj_data_info_sptr->reduce_segment_range(0,0); //create input template - interpolate_projdata_push(scaled_scatter_proj_data, interpolated_direct_scatter, remove_interleaving); + ProjDataInMemory new_input(scatter_proj_data.get_exam_info_sptr(),new_input_proj_data_info_sptr); + transpose_inverse_SSRB(new_input, scatter_proj_data); - //transpose reduce segment on interpolated_direct_scatter + interpolate_projdata_push(scaled_scatter_proj_data, new_input, remove_interleaving); - //extend segment } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 41d65f6cb3..9f3e1e1ab3 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -86,7 +86,7 @@ run_tests() shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); From ff710e06d4e647eba89de6ab7db8427a02dad265 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 9 Jul 2019 12:01:36 +0100 Subject: [PATCH 117/274] compiles ok --- src/buildblock/inverse_SSRB.cxx | 107 ++++++++++++-------------------- src/test/test_upsample.cxx | 2 +- 2 files changed, 42 insertions(+), 67 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 2b475f9181..695e19c2d1 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -129,79 +129,54 @@ Succeeded transpose_inverse_SSRB(ProjData& proj_data_3D, const ProjData& proj_data_4D) { - const ProjDataInfo * const proj_data_3D_info_ptr = - dynamic_cast - (proj_data_3D.get_proj_data_info_ptr()); - const ProjDataInfo * const proj_data_4D_info_ptr = - dynamic_cast - (proj_data_4D.get_proj_data_info_ptr()); - if ((proj_data_3D_info_ptr->get_min_view_num() != - proj_data_4D_info_ptr->get_min_view_num()) || - (proj_data_3D_info_ptr->get_min_view_num() != - proj_data_4D_info_ptr->get_min_view_num())) - { - warning("inverse_SSRB: incompatible view-information"); - return Succeeded::no; - } - if ((proj_data_3D_info_ptr->get_min_tangential_pos_num() != - proj_data_4D_info_ptr->get_min_tangential_pos_num()) || - (proj_data_3D_info_ptr->get_min_tangential_pos_num() != - proj_data_4D_info_ptr->get_min_tangential_pos_num())) - { - warning("inverse_SSRB: incompatible tangential_pos-information"); - return Succeeded::no; - } - - // keep sinograms out of the loop to avoid reallocations - // initialise to something because there's no default constructor - Sinogram sino_4D = - proj_data_4D. - get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - std::cout<< "SSRB-4D" << proj_data_4D.get_max_axial_pos_num(0) << '\n'; - Sinogram sino_3D = - proj_data_3D. - get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); - std::cout<< "SSRB-3D"<< proj_data_3D.get_max_axial_pos_num(0) << '\n'; + //construct projdata info + const ProjDataInfo * const proj_data_3D_info_ptr = dynamic_cast (proj_data_3D.get_proj_data_info_ptr()); + const ProjDataInfo * const proj_data_4D_info_ptr = dynamic_cast (proj_data_4D.get_proj_data_info_ptr()); + + // keep sinograms out of the loop to avoid reallocations. initialise to something because there's no default constructor + Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); + Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + + for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(0); ++out_ax_pos_num ) + { + sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); + const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); + + for (int in_segment_num = proj_data_4D.get_min_segment_num(); + in_segment_num <= proj_data_4D.get_max_segment_num(); + ++in_segment_num) + { + for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num); + in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); + ++in_ax_pos_num ) + { - for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); - out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); - ++out_ax_pos_num ) - { - sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); - const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); + sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); + const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); + int num_contributing_sinos = 0; - for (int in_segment_num = proj_data_4D.get_min_segment_num(); - in_segment_num <= proj_data_4D.get_max_segment_num(); - ++in_segment_num) - { + if (fabs(out_m - in_m) < 1E-2) + { + ++num_contributing_sinos; + sino_3D += sino_4D; + } + const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? + -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); - for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num); - in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); - ++in_ax_pos_num ) + if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { + ++num_contributing_sinos; + sino_3D += 20; + } + } + } - const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, out_ax_pos_num, 0)); - sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); - if (fabs(in_m - out_m) < 1E-2) - { - sino_3D += sino_4D; - sino_3D*=.5F; - proj_data_3D.set_sinogram(sino_3D); - } - const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? - -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, in_ax_pos_num+1, 0)); - - if (fabs(.5F*(out_m + out_m_next-in_m)) < 1E-2) - { - sino_3D+=sino_4D; - sino_3D+=proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); - proj_data_3D.set_sinogram(sino_3D); - } - - } + proj_data_3D.set_sinogram(sino_3D); } - } + + + return Succeeded::yes; } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 9f3e1e1ab3..41d65f6cb3 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -86,7 +86,7 @@ run_tests() shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); From f36818c09bce0579405a1811ba6e08a0598fb31d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 9 Jul 2019 12:10:10 +0100 Subject: [PATCH 118/274] todo boundary --- src/buildblock/inverse_SSRB.cxx | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 695e19c2d1..de5f249e60 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -161,13 +161,26 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, ++num_contributing_sinos; sino_3D += sino_4D; } - const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? - -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); + const float in_m_next = in_ax_pos_num == proj_data_4D.get_max_axial_pos_num(in_segment_num) ? + -1000000.F : proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num+1, 0)); - if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) + const float in_m_prev = in_ax_pos_num == proj_data_4D.get_min_axial_pos_num(in_segment_num) ? + -1000000.F : proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num-1, 0)); + + if (fabs(out_m - .5F*(in_m + in_m_next)) < 1E-2) { ++num_contributing_sinos; - sino_3D += 20; + sino_3D += proj_data_4D.get_sinogram(in_ax_pos_num+1,in_segment_num); + sino_3D*=.5F; + sino_3D += sino_4D; + } + + if (fabs(out_m - .5F*(in_m + in_m_prev)) < 1E-2) + { + ++num_contributing_sinos; + sino_3D += proj_data_4D.get_sinogram(in_ax_pos_num-1,in_segment_num); + sino_3D*=.5F; + sino_3D += sino_4D; } } } From ae3af2e939e2e4d9c048e89ffaaf4e1f52571e39 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 9 Jul 2019 12:13:55 +0100 Subject: [PATCH 119/274] bound --- src/test/test_upsample.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 41d65f6cb3..37b9ba8d2d 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -176,7 +176,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.05); + set_tolerance(0.02); check_if_equal(cdot1, cdot2, "test adjoint"); @@ -236,7 +236,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.05); + set_tolerance(0.02); check_if_equal(cdot1, cdot2, "test adjoint"); From 3ab419d038470a36c726e31a38ca1fdf8f9559d6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 9 Jul 2019 15:18:29 +0100 Subject: [PATCH 120/274] seg 0 only --- src/buildblock/inverse_SSRB.cxx | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index de5f249e60..a6d5a19ac7 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -137,7 +137,7 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(0); ++out_ax_pos_num ) + for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) { sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); @@ -147,7 +147,7 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, ++in_segment_num) { for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num); - in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); + in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num)-1; ++in_ax_pos_num ) { @@ -161,27 +161,7 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, ++num_contributing_sinos; sino_3D += sino_4D; } - const float in_m_next = in_ax_pos_num == proj_data_4D.get_max_axial_pos_num(in_segment_num) ? - -1000000.F : proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num+1, 0)); - const float in_m_prev = in_ax_pos_num == proj_data_4D.get_min_axial_pos_num(in_segment_num) ? - -1000000.F : proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num-1, 0)); - - if (fabs(out_m - .5F*(in_m + in_m_next)) < 1E-2) - { - ++num_contributing_sinos; - sino_3D += proj_data_4D.get_sinogram(in_ax_pos_num+1,in_segment_num); - sino_3D*=.5F; - sino_3D += sino_4D; - } - - if (fabs(out_m - .5F*(in_m + in_m_prev)) < 1E-2) - { - ++num_contributing_sinos; - sino_3D += proj_data_4D.get_sinogram(in_ax_pos_num-1,in_segment_num); - sino_3D*=.5F; - sino_3D += sino_4D; - } } } From e8423d7fea95cd820ee1bfb945a327eb6653f4f2 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 9 Jul 2019 18:08:16 +0100 Subject: [PATCH 121/274] ok --- src/buildblock/inverse_SSRB.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index a6d5a19ac7..fed999de4f 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -141,7 +141,8 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, { sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); - + const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? + -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); for (int in_segment_num = proj_data_4D.get_min_segment_num(); in_segment_num <= proj_data_4D.get_max_segment_num(); ++in_segment_num) @@ -162,6 +163,12 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, sino_3D += sino_4D; } + if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) + { + + sino_3D += sino_4D; + } + } } From b84729fa859b4f3e9a2d1da45d122bf41b479c1d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 9 Jul 2019 19:10:43 +0100 Subject: [PATCH 122/274] ok --- src/buildblock/inverse_SSRB.cxx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index fed999de4f..cd52a1efa8 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -143,12 +143,14 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); + const float out_m_prev = out_ax_pos_num == proj_data_3D.get_min_axial_pos_num(0) ? + -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num-1, 0)); for (int in_segment_num = proj_data_4D.get_min_segment_num(); in_segment_num <= proj_data_4D.get_max_segment_num(); ++in_segment_num) { for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num); - in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num)-1; + in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num ) { @@ -166,6 +168,14 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { + sino_4D *= .5F; + sino_3D += sino_4D; + } + + if (fabs(in_m - .5F*(out_m + out_m_prev)) < 1E-2) + { + + sino_4D *= .5F; sino_3D += sino_4D; } From b4da3281c831ad75ac3aefdb68a4f6e54ae941a5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 10:04:38 +0100 Subject: [PATCH 123/274] test --- src/buildblock/inverse_SSRB.cxx | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index cd52a1efa8..0d4bbca5fe 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -143,38 +143,22 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); - const float out_m_prev = out_ax_pos_num == proj_data_3D.get_min_axial_pos_num(0) ? - -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num-1, 0)); - for (int in_segment_num = proj_data_4D.get_min_segment_num(); - in_segment_num <= proj_data_4D.get_max_segment_num(); - ++in_segment_num) + + for (int in_segment_num = proj_data_4D.get_min_segment_num(); in_segment_num <= proj_data_4D.get_max_segment_num(); ++in_segment_num) { - for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num); - in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); - ++in_ax_pos_num ) + for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num);in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num ) { - sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); - int num_contributing_sinos = 0; if (fabs(out_m - in_m) < 1E-2) { - ++num_contributing_sinos; sino_3D += sino_4D; } if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { - - sino_4D *= .5F; - sino_3D += sino_4D; - } - - if (fabs(in_m - .5F*(out_m + out_m_prev)) < 1E-2) - { - sino_4D *= .5F; sino_3D += sino_4D; } From 785110a54b0e9f8f7c9fe48a94fd9cdc9af1fa34 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 13:03:00 +0100 Subject: [PATCH 124/274] ssrb test --- src/test/CMakeLists.txt | 3 +- src/test/test_upsample.cxx | 78 +++++++++++- src/test/test_zoom_image_adjoint.cxx | 182 +++++++++++++++++++++++++++ 3 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 src/test/test_zoom_image_adjoint.cxx diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b33b4f4b99..8e35ab1367 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -64,7 +64,8 @@ set(buildblock_simple_tests test_proj_data_in_memory test_export_array test_GeneralisedPoissonNoiseGenerator - test_multiple_proj_data + test_multiple_proj_data + test_zoom_image_adjoint ) include(stir_test_exe_targets) diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 37b9ba8d2d..07a591d295 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -26,6 +26,7 @@ */ #include "stir/ProjDataInMemory.h" +#include "stir/inverse_SSRB.h" #include "stir/ExamInfo.h" #include "stir/ProjDataInfo.h" #include "stir/Sinogram.h" @@ -86,7 +87,7 @@ run_tests() shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); @@ -241,6 +242,81 @@ run_tests() + std::cout << "========== TEST SSRB =========== \n"; + + //creating proj data info + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr exam_info_sptr_4D(new ExamInfo); + ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); + + shared_ptr proj_data_info_sptr_3D(projdata_4D.get_proj_data_info_ptr()->clone()); + proj_data_info_sptr_3D->reduce_segment_range(0,0); //create input template + + ProjDataInMemory projdata_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); + + ProjDataInMemory A_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); + ProjDataInMemory A_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); + + projdata_4D.fill(1); + projdata_3D.fill(1); + A_4D.fill(0); //initialise output + A_3D.fill(0); //initialise output + + + std::cout << "-------- Testing Inverse SSRB --------\n"; + inverse_SSRB(A_4D,projdata_3D); + + std::cout << "-------- Testing Transpose Inverse SSRB --------\n"; + + transpose_inverse_SSRB(A_3D,projdata_4D); + + std::cout << "-------- = --------\n"; + + cdot1 = 0; + cdot2 = 0; + + for ( int segment_num = projdata_4D.get_min_segment_num(); segment_num <= projdata_4D.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = projdata_4D.get_min_axial_pos_num(segment_num); axial_pos <= projdata_4D.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram yy_sinogram = projdata_4D.get_sinogram(axial_pos, segment_num); + const Sinogram At_sinogram = A_4D.get_sinogram(axial_pos, segment_num); + + for ( int view_num = projdata_4D.get_min_view_num(); view_num <= projdata_4D.get_max_view_num();view_num++) + { + for ( int tang_pos = projdata_4D.get_min_tangential_pos_num(); tang_pos <= projdata_4D.get_max_tangential_pos_num(); tang_pos++) + { + cdot1 += At_sinogram[view_num][tang_pos]*yy_sinogram[view_num][tang_pos]; + } + } + } + } + + for ( int segment_num = projdata_3D.get_min_segment_num(); segment_num <= projdata_3D.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = projdata_3D.get_min_axial_pos_num(segment_num); axial_pos <= projdata_3D.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram xx_sinogram = projdata_3D.get_sinogram(axial_pos, segment_num); + const Sinogram A_sinogram = A_3D.get_sinogram(axial_pos, segment_num); + + for ( int view_num = projdata_3D.get_min_view_num(); view_num <= projdata_3D.get_max_view_num();view_num++) + { + for ( int tang_pos = projdata_3D.get_min_tangential_pos_num(); tang_pos <= projdata_3D.get_max_tangential_pos_num(); tang_pos++) + { + cdot2 += xx_sinogram[view_num][tang_pos]*A_sinogram[view_num][tang_pos]; + } + } + } + } + + std::cout << cdot1 << "=" << cdot2 << '\n'; + set_tolerance(0.02); + check_if_equal(cdot1, cdot2, "test adjoint"); + + + } END_NAMESPACE_STIR diff --git a/src/test/test_zoom_image_adjoint.cxx b/src/test/test_zoom_image_adjoint.cxx new file mode 100644 index 0000000000..ce6c2303ea --- /dev/null +++ b/src/test/test_zoom_image_adjoint.cxx @@ -0,0 +1,182 @@ +// +// +/* + Copyright (C) 2006- 2007, Hammersmith Imanet Ltd + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +/*! + \file + \ingroup test + + \brief Test program for stir::zoom_image (and stir::centre_of_gravity) + + \author Kris Thielemans + +*/ + +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/IndexRange.h" +#include "stir/zoom.h" +#include "stir/centre_of_gravity.h" + +#include +#include +#include "stir/RunTests.h" + +START_NAMESPACE_STIR + +/*! + \ingroup test + \brief Test class for zoom_image (and centre_of_gravity) + + The tests check if a point source remains in the same physical location + after zooming. This is done by checking the centre of gravity of the + zoomed image. +*/ +class zoom_imageTests : public RunTests +{ +public: + void run_tests(); +}; + + +void +zoom_imageTests::run_tests() + +{ + std::cerr << "Tests for zoom_image\n"; + + CartesianCoordinate3D origin (0,1,2); + CartesianCoordinate3D grid_spacing (3,4,5); + + IndexRange<3> + range(CartesianCoordinate3D(0,-15,-14), + CartesianCoordinate3D(4,14,15)); + + VoxelsOnCartesianGrid image(range,origin, grid_spacing); + image.fill(0.F); + + const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); + image[indices] = 1.F; + const CartesianCoordinate3D coord = + image.get_physical_coordinates_for_indices(indices); + + { + // check if centre_of_gravity_in_mm returns same point + check_if_equal(coord, + find_centre_of_gravity_in_mm(image), + "test on get_physical_coordinates_for_indices and find_centre_of_gravity_in_mm"); + } + + // we cannot have very good accuracy in the centre of gravity + // calculation for zooming a single pixel + // the following threshold seems very reasonable (.3mm distance) and works. + const double tolerance_for_distance = .3; + const double old_tolerance = this->get_tolerance(); + + // test 2 arg zoom_image + { + CartesianCoordinate3D new_origin (4.F,5.F,6.F); + CartesianCoordinate3D new_grid_spacing (2.2F,3.1F,4.3F); + + IndexRange<3> + new_range(CartesianCoordinate3D(-1,-16,-17), + CartesianCoordinate3D(5,15,20)); + + VoxelsOnCartesianGrid new_image(new_range,new_origin, new_grid_spacing); + zoom_image(new_image, image); + { + // check if centre_of_gravity_in_mm returns same point + this->set_tolerance(tolerance_for_distance); + check_if_equal(coord, + find_centre_of_gravity_in_mm(new_image), + "test on 2-argument zoom_image"); + this->set_tolerance(old_tolerance); + check_if_equal(new_range, new_image.get_index_range(), + "test on 2-argument argument zoom_image: index range"); + check_if_equal(new_grid_spacing, new_image.get_voxel_size(), + "test on 2-argument argument zoom_image: voxel size"); + check_if_equal(new_origin, new_image.get_origin(), + "test on 2-argument argument zoom_image: origin"); + + } + } + + + // test multiple argument zoom_image + { + const CartesianCoordinate3D zooms(1.3F,1.2F,1.5F); + const CartesianCoordinate3D offsets_in_mm(3.F,4.F,5.5F); + const Coordinate3D new_sizes(30,40,50); + const VoxelsOnCartesianGrid new_image = + zoom_image(image, zooms, offsets_in_mm, new_sizes); + { + // check if centre_of_gravity_in_mm returns same point + this->set_tolerance(tolerance_for_distance); + check_if_equal(coord, + find_centre_of_gravity_in_mm(new_image), + "test on multiple argument zoom_image"); + this->set_tolerance(old_tolerance); + check_if_equal(new_sizes, new_image.get_lengths(), + "test on multiple argument zoom_image: index range"); + check_if_equal(new_image.get_voxel_size(), image.get_voxel_size()/zooms, + "test on multiple argument zoom_image: voxel size"); + + } + } + + // test multiple argument zoom_image in 2D + { + const float zoom = 1.3F; + const CartesianCoordinate3D zooms(1.F,zoom,zoom); + const CartesianCoordinate3D offsets_in_mm(0.F,4.F,5.5F); + const int new_size = 30; + const VoxelsOnCartesianGrid new_image = + zoom_image(image, zoom, offsets_in_mm.x(), offsets_in_mm.y(), new_size); + { + // check if centre_of_gravity_in_mm returns same point + this->set_tolerance(tolerance_for_distance); + check_if_equal(coord, + find_centre_of_gravity_in_mm(new_image), + "test on multiple argument (2d) zoom_image"); + this->set_tolerance(old_tolerance); + check_if_equal(image.get_min_z(), new_image.get_min_z(), + "test on multiple argument (2d) zoom_image: min_z"); + check_if_equal(image.get_max_z(), new_image.get_max_z(), + "test on multiple argument (2d) zoom_image: max_z"); + check_if_equal(new_size, new_image.get_x_size(), + "test on multiple argument (2d) zoom_image: x_size"); + check_if_equal(new_size, new_image.get_y_size(), + "test on multiple argument (2d) zoom_image: y_size"); + check_if_equal(new_image.get_voxel_size(), image.get_voxel_size()/zooms, + "test on multiple argument (2d) zoom_image: voxel size"); + + } + } + +} + +END_NAMESPACE_STIR + + +USING_NAMESPACE_STIR + + +int main() +{ + zoom_imageTests tests; + tests.run_tests(); + return tests.main_return_value(); +} From 1ecc8e443d4ab053394ada3d55b9f374c5eebbb2 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 14:14:21 +0100 Subject: [PATCH 125/274] test --- src/buildblock/inverse_SSRB.cxx | 4 ++ src/test/test_upsample.cxx | 23 +++++------- src/test/test_zoom_image_adjoint.cxx | 56 ++-------------------------- 3 files changed, 17 insertions(+), 66 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 0d4bbca5fe..557d0ce0d2 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -136,6 +136,7 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, // keep sinograms out of the loop to avoid reallocations. initialise to something because there's no default constructor Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + Sinogram sino_4D2 = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) { @@ -161,6 +162,9 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, { sino_4D *= .5F; sino_3D += sino_4D; + sino_4D2 = proj_data_4D.get_sinogram(out_ax_pos_num+1, 0); + sino_4D2 *= .5F; + sino_3D += sino_4D2; } } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 07a591d295..40c089dcd1 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -58,21 +58,18 @@ void UpsampleDownsampleTests:: fill_projdata_with_random(ProjData & projdata) { + Viewgram view = projdata.get_viewgram(0,0); + view.fill(1); for ( int segment_num = projdata.get_min_segment_num(); segment_num <= projdata.get_max_segment_num(); ++segment_num) { - for (int axial_pos = projdata.get_min_axial_pos_num(segment_num); axial_pos <= projdata.get_max_axial_pos_num(segment_num); ++axial_pos) - { - - const Sinogram p_sinogram = projdata.get_sinogram(axial_pos, segment_num); - for ( int view_num = projdata.get_min_view_num(); view_num <= projdata.get_max_view_num();view_num++) { for ( int tang_pos = projdata.get_min_tangential_pos_num(); tang_pos <= projdata.get_max_tangential_pos_num(); tang_pos++) { - //p_sinogram[view_num][tang_pos]=2; - projdata.set_sinogram(p_sinogram); + view *=rand(); + projdata.set_viewgram(view); } - } + } } } @@ -116,8 +113,8 @@ run_tests() // construct x ProjDataInMemory Aty(sss->get_ExamInfo_sptr(), sss->get_template_proj_data_info_sptr()); - x.fill(0.5); - y.fill(2); + x.fill(2); + y.fill(3); // fill_projdata_with_random(x); // fill_projdata_with_random(y); @@ -245,7 +242,7 @@ run_tests() std::cout << "========== TEST SSRB =========== \n"; //creating proj data info - shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr exam_info_sptr_4D(new ExamInfo); ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); @@ -257,8 +254,8 @@ run_tests() ProjDataInMemory A_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); ProjDataInMemory A_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); - projdata_4D.fill(1); - projdata_3D.fill(1); + projdata_4D.fill(2); + projdata_3D.fill(3); A_4D.fill(0); //initialise output A_3D.fill(0); //initialise output diff --git a/src/test/test_zoom_image_adjoint.cxx b/src/test/test_zoom_image_adjoint.cxx index ce6c2303ea..44e763a0ca 100644 --- a/src/test/test_zoom_image_adjoint.cxx +++ b/src/test/test_zoom_image_adjoint.cxx @@ -66,7 +66,7 @@ zoom_imageTests::run_tests() CartesianCoordinate3D(4,14,15)); VoxelsOnCartesianGrid image(range,origin, grid_spacing); - image.fill(0.F); + image.fill(.5F); const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); image[indices] = 1.F; @@ -87,6 +87,7 @@ zoom_imageTests::run_tests() const double old_tolerance = this->get_tolerance(); // test 2 arg zoom_image + ZoomOptions zoom_options = ZoomOptions::preserve_values; { CartesianCoordinate3D new_origin (4.F,5.F,6.F); CartesianCoordinate3D new_grid_spacing (2.2F,3.1F,4.3F); @@ -96,7 +97,7 @@ zoom_imageTests::run_tests() CartesianCoordinate3D(5,15,20)); VoxelsOnCartesianGrid new_image(new_range,new_origin, new_grid_spacing); - zoom_image(new_image, image); + zoom_image(new_image, image, zoom_options); { // check if centre_of_gravity_in_mm returns same point this->set_tolerance(tolerance_for_distance); @@ -115,57 +116,6 @@ zoom_imageTests::run_tests() } - // test multiple argument zoom_image - { - const CartesianCoordinate3D zooms(1.3F,1.2F,1.5F); - const CartesianCoordinate3D offsets_in_mm(3.F,4.F,5.5F); - const Coordinate3D new_sizes(30,40,50); - const VoxelsOnCartesianGrid new_image = - zoom_image(image, zooms, offsets_in_mm, new_sizes); - { - // check if centre_of_gravity_in_mm returns same point - this->set_tolerance(tolerance_for_distance); - check_if_equal(coord, - find_centre_of_gravity_in_mm(new_image), - "test on multiple argument zoom_image"); - this->set_tolerance(old_tolerance); - check_if_equal(new_sizes, new_image.get_lengths(), - "test on multiple argument zoom_image: index range"); - check_if_equal(new_image.get_voxel_size(), image.get_voxel_size()/zooms, - "test on multiple argument zoom_image: voxel size"); - - } - } - - // test multiple argument zoom_image in 2D - { - const float zoom = 1.3F; - const CartesianCoordinate3D zooms(1.F,zoom,zoom); - const CartesianCoordinate3D offsets_in_mm(0.F,4.F,5.5F); - const int new_size = 30; - const VoxelsOnCartesianGrid new_image = - zoom_image(image, zoom, offsets_in_mm.x(), offsets_in_mm.y(), new_size); - { - // check if centre_of_gravity_in_mm returns same point - this->set_tolerance(tolerance_for_distance); - check_if_equal(coord, - find_centre_of_gravity_in_mm(new_image), - "test on multiple argument (2d) zoom_image"); - this->set_tolerance(old_tolerance); - check_if_equal(image.get_min_z(), new_image.get_min_z(), - "test on multiple argument (2d) zoom_image: min_z"); - check_if_equal(image.get_max_z(), new_image.get_max_z(), - "test on multiple argument (2d) zoom_image: max_z"); - check_if_equal(new_size, new_image.get_x_size(), - "test on multiple argument (2d) zoom_image: x_size"); - check_if_equal(new_size, new_image.get_y_size(), - "test on multiple argument (2d) zoom_image: y_size"); - check_if_equal(new_image.get_voxel_size(), image.get_voxel_size()/zooms, - "test on multiple argument (2d) zoom_image: voxel size"); - - } - } - } END_NAMESPACE_STIR From 0c2ded6df675a11bc953e38f002eae27f3cb931f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 15:31:40 +0100 Subject: [PATCH 126/274] random generator --- src/test/test_upsample.cxx | 59 ++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 40c089dcd1..fc8e81a454 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -58,20 +58,37 @@ void UpsampleDownsampleTests:: fill_projdata_with_random(ProjData & projdata) { - Viewgram view = projdata.get_viewgram(0,0); - view.fill(1); - for ( int segment_num = projdata.get_min_segment_num(); segment_num <= projdata.get_max_segment_num(); ++segment_num) - { - for ( int view_num = projdata.get_min_view_num(); view_num <= projdata.get_max_view_num();view_num++) - { - for ( int tang_pos = projdata.get_min_tangential_pos_num(); tang_pos <= projdata.get_max_tangential_pos_num(); tang_pos++) - { - view *=rand(); - projdata.set_viewgram(view); - } - - } - } + Bin bin; + { + for (bin.segment_num()=projdata.get_min_segment_num(); + bin.segment_num()<=projdata.get_max_segment_num(); + ++bin.segment_num()) + for (bin.axial_pos_num()= + projdata.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) + { + + Sinogram sino = projdata.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); + + for (bin.view_num()=sino.get_min_view_num(); + bin.view_num()<=sino.get_max_view_num(); + ++bin.view_num()) + { + for (bin.tangential_pos_num()= + sino.get_min_tangential_pos_num(); + bin.tangential_pos_num()<= + sino.get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) + sino[bin.view_num()][bin.tangential_pos_num()]= rand()%2;//((double) rand() / (1)) + 1; + + projdata.set_sinogram(sino); + + } + + } + + } } void UpsampleDownsampleTests:: @@ -95,8 +112,8 @@ run_tests() unique_ptr sss(new SingleScatterSimulation()); sss->set_template_proj_data_info_sptr(proj_data_info_sptr); - int down_rings = static_cast(scanner_sptr->get_num_rings()/8); - int down_dets = static_cast(scanner_sptr->get_max_num_views()/12); + int down_rings = static_cast(scanner_sptr->get_num_rings()/4); + int down_dets = static_cast(scanner_sptr->get_max_num_views()/4); sss->downsample_scanner(down_rings, down_dets); @@ -113,10 +130,8 @@ run_tests() // construct x ProjDataInMemory Aty(sss->get_ExamInfo_sptr(), sss->get_template_proj_data_info_sptr()); - x.fill(2); - y.fill(3); - // fill_projdata_with_random(x); - // fill_projdata_with_random(y); + fill_projdata_with_random(x); + fill_projdata_with_random(y); Ax.fill(0); //initialise output Aty.fill(0); //initialise output @@ -254,8 +269,8 @@ run_tests() ProjDataInMemory A_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); ProjDataInMemory A_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); - projdata_4D.fill(2); - projdata_3D.fill(3); + fill_projdata_with_random(projdata_4D); + fill_projdata_with_random(projdata_3D); A_4D.fill(0); //initialise output A_3D.fill(0); //initialise output From 4c0a9a40ebd1dc9ac1117f94743ed0f8f5d3a5e9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 16:09:19 +0100 Subject: [PATCH 127/274] loop --- src/buildblock/inverse_SSRB.cxx | 9 +- src/buildblock/inverse_SSRB.cxx.autosave | 178 +++++++++++++++++++++++ src/test/test_upsample.cxx | 19 ++- 3 files changed, 193 insertions(+), 13 deletions(-) create mode 100644 src/buildblock/inverse_SSRB.cxx.autosave diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 557d0ce0d2..07c1513b67 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -162,9 +162,12 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, { sino_4D *= .5F; sino_3D += sino_4D; - sino_4D2 = proj_data_4D.get_sinogram(out_ax_pos_num+1, 0); - sino_4D2 *= .5F; - sino_3D += sino_4D2; + } + + if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) + { + sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num+1,in_segment_num+1); + sino_3D += sino_4D; } } diff --git a/src/buildblock/inverse_SSRB.cxx.autosave b/src/buildblock/inverse_SSRB.cxx.autosave new file mode 100644 index 0000000000..656e8ec543 --- /dev/null +++ b/src/buildblock/inverse_SSRB.cxx.autosave @@ -0,0 +1,178 @@ +// +// +/* + Copyright (C) 2005- 2007, Hammersmith Imanet Ltd + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +/*! + \file + \ingroup projdata + \brief Implementation of stir::inverse_SSRB + + \author Charalampos Tsoumpas + \author Kris Thielemans + +*/ +#include "stir/ProjData.h" +#include "stir/ProjDataInfo.h" +#include "stir/inverse_SSRB.h" +#include "stir/Sinogram.h" +#include "stir/Bin.h" +#include "stir/Succeeded.h" + +START_NAMESPACE_STIR + +Succeeded +inverse_SSRB(ProjData& proj_data_4D, + const ProjData& proj_data_3D) +{ + const ProjDataInfo * const proj_data_3D_info_ptr = + dynamic_cast + (proj_data_3D.get_proj_data_info_ptr()); + const ProjDataInfo * const proj_data_4D_info_ptr = + dynamic_cast + (proj_data_4D.get_proj_data_info_ptr()); + if ((proj_data_3D_info_ptr->get_min_view_num() != + proj_data_4D_info_ptr->get_min_view_num()) || + (proj_data_3D_info_ptr->get_min_view_num() != + proj_data_4D_info_ptr->get_min_view_num())) + { + warning("inverse_SSRB: incompatible view-information"); + return Succeeded::no; + } + if ((proj_data_3D_info_ptr->get_min_tangential_pos_num() != + proj_data_4D_info_ptr->get_min_tangential_pos_num()) || + (proj_data_3D_info_ptr->get_min_tangential_pos_num() != + proj_data_4D_info_ptr->get_min_tangential_pos_num())) + { + warning("inverse_SSRB: incompatible tangential_pos-information"); + return Succeeded::no; + } + + // keep sinograms out of the loop to avoid reallocations + // initialise to something because there's no default constructor + Sinogram sino_4D = + proj_data_4D. + get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + std::cout<< "SSRB-4D" << proj_data_4D.get_max_axial_pos_num(0) << '\n'; + Sinogram sino_3D = + proj_data_3D. + get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); + std::cout<< "SSRB-3D"<< proj_data_3D.get_max_axial_pos_num(0) << '\n'; + + for (int out_segment_num = proj_data_4D.get_min_segment_num(); + out_segment_num <= proj_data_4D.get_max_segment_num(); + ++out_segment_num) + { + for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); + out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); + ++out_ax_pos_num ) + { + sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num); + const float out_m = + proj_data_4D_info_ptr-> + get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); + int num_contributing_sinos = 0; + + for (int in_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); + in_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); + ++in_ax_pos_num ) + { + sino_3D = proj_data_3D.get_sinogram(in_ax_pos_num,0); + const float in_m = + proj_data_3D_info_ptr->get_m(Bin(0, 0, in_ax_pos_num, 0)); + + if (fabs(out_m - in_m) < 1E-2) + { + ++num_contributing_sinos; + sino_4D += sino_3D; + if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) + return Succeeded::no; + break; + } + const float in_m_next = in_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? + -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, in_ax_pos_num+1, 0)); + + if (fabs(out_m - .5F*(in_m + in_m_next)) < 1E-2) + { + ++num_contributing_sinos; + sino_4D += sino_3D; + sino_4D += proj_data_3D.get_sinogram(in_ax_pos_num+1,0); + sino_4D *= .5F; + if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) + return Succeeded::no; + break; + } + } + if (num_contributing_sinos == 0) + warning("inverse_SSRB: no sinogram contributes to segment %d, axial_pos_num %d", + out_segment_num, out_ax_pos_num); + } + } + return Succeeded::yes; +} + + +Succeeded +transpose_inverse_SSRB(ProjData& proj_data_3D, + const ProjData& proj_data_4D) +{ + //construct projdata info + const ProjDataInfo * const proj_data_3D_info_ptr = dynamic_cast (proj_data_3D.get_proj_data_info_ptr()); + const ProjDataInfo * const proj_data_4D_info_ptr = dynamic_cast (proj_data_4D.get_proj_data_info_ptr()); + + // keep sinograms out of the loop to avoid reallocations. initialise to something because there's no default constructor + Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); + Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + Sinogram sino_4D2 = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + + for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) + { + sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); + const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); + const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? + -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); + + for (int in_segment_num = proj_data_4D.get_min_segment_num(); in_segment_num <= proj_data_4D.get_max_segment_num(); ++in_segment_num) + { + for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num);in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num ) + { + + sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); + const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); + + if (fabs(out_m - in_m) < 1E-2) + { + sino_3D += sino_4D; + } + + if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) + { + sino_4D *= .5F; + sino_3D += sino_4D; + } + + } + } + + proj_data_3D.set_sinogram(sino_3D); + } + + + + return Succeeded::yes; +} + +END_NAMESPACE_STIR diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index fc8e81a454..dbd966f982 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -94,20 +94,20 @@ void UpsampleDownsampleTests:: run_tests() { - std::cout << "-------- Testing Upsampling and Downsampling ---------\n"; +// std::cout << "-------- Testing Upsampling and Downsampling ---------\n"; shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); - shared_ptr exam_info_sptr(new ExamInfo); - shared_ptr LR_exam_info_sptr(new ExamInfo); + //shared_ptr exam_info_sptr(new ExamInfo); + //shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + // shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); // construct y - ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); + /* ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); unique_ptr sss(new SingleScatterSimulation()); @@ -250,14 +250,13 @@ run_tests() std::cout << cdot1 << "=" << cdot2 << '\n'; set_tolerance(0.02); - check_if_equal(cdot1, cdot2, "test adjoint"); - + check_if_equal(cdot1, cdot2, "test adjoint");*/ std::cout << "========== TEST SSRB =========== \n"; //creating proj data info - shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr exam_info_sptr_4D(new ExamInfo); ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); @@ -284,8 +283,8 @@ run_tests() std::cout << "-------- = --------\n"; - cdot1 = 0; - cdot2 = 0; + int cdot1 = 0; + int cdot2 = 0; for ( int segment_num = projdata_4D.get_min_segment_num(); segment_num <= projdata_4D.get_max_segment_num(); ++segment_num) { From 487855bfebe829aa679a6f84b6167f8e7e07be30 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 16:09:33 +0100 Subject: [PATCH 128/274] loop --- src/buildblock/inverse_SSRB.cxx | 6 - src/buildblock/inverse_SSRB.cxx.autosave | 178 ----------------------- 2 files changed, 184 deletions(-) delete mode 100644 src/buildblock/inverse_SSRB.cxx.autosave diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 07c1513b67..656e8ec543 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -164,12 +164,6 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, sino_3D += sino_4D; } - if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) - { - sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num+1,in_segment_num+1); - sino_3D += sino_4D; - } - } } diff --git a/src/buildblock/inverse_SSRB.cxx.autosave b/src/buildblock/inverse_SSRB.cxx.autosave deleted file mode 100644 index 656e8ec543..0000000000 --- a/src/buildblock/inverse_SSRB.cxx.autosave +++ /dev/null @@ -1,178 +0,0 @@ -// -// -/* - Copyright (C) 2005- 2007, Hammersmith Imanet Ltd - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ -/*! - \file - \ingroup projdata - \brief Implementation of stir::inverse_SSRB - - \author Charalampos Tsoumpas - \author Kris Thielemans - -*/ -#include "stir/ProjData.h" -#include "stir/ProjDataInfo.h" -#include "stir/inverse_SSRB.h" -#include "stir/Sinogram.h" -#include "stir/Bin.h" -#include "stir/Succeeded.h" - -START_NAMESPACE_STIR - -Succeeded -inverse_SSRB(ProjData& proj_data_4D, - const ProjData& proj_data_3D) -{ - const ProjDataInfo * const proj_data_3D_info_ptr = - dynamic_cast - (proj_data_3D.get_proj_data_info_ptr()); - const ProjDataInfo * const proj_data_4D_info_ptr = - dynamic_cast - (proj_data_4D.get_proj_data_info_ptr()); - if ((proj_data_3D_info_ptr->get_min_view_num() != - proj_data_4D_info_ptr->get_min_view_num()) || - (proj_data_3D_info_ptr->get_min_view_num() != - proj_data_4D_info_ptr->get_min_view_num())) - { - warning("inverse_SSRB: incompatible view-information"); - return Succeeded::no; - } - if ((proj_data_3D_info_ptr->get_min_tangential_pos_num() != - proj_data_4D_info_ptr->get_min_tangential_pos_num()) || - (proj_data_3D_info_ptr->get_min_tangential_pos_num() != - proj_data_4D_info_ptr->get_min_tangential_pos_num())) - { - warning("inverse_SSRB: incompatible tangential_pos-information"); - return Succeeded::no; - } - - // keep sinograms out of the loop to avoid reallocations - // initialise to something because there's no default constructor - Sinogram sino_4D = - proj_data_4D. - get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - std::cout<< "SSRB-4D" << proj_data_4D.get_max_axial_pos_num(0) << '\n'; - Sinogram sino_3D = - proj_data_3D. - get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); - std::cout<< "SSRB-3D"<< proj_data_3D.get_max_axial_pos_num(0) << '\n'; - - for (int out_segment_num = proj_data_4D.get_min_segment_num(); - out_segment_num <= proj_data_4D.get_max_segment_num(); - ++out_segment_num) - { - for (int out_ax_pos_num = proj_data_4D.get_min_axial_pos_num(out_segment_num); - out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); - ++out_ax_pos_num ) - { - sino_4D = proj_data_4D.get_empty_sinogram(out_ax_pos_num, out_segment_num); - const float out_m = - proj_data_4D_info_ptr-> - get_m(Bin(out_segment_num, 0, out_ax_pos_num, 0)); - int num_contributing_sinos = 0; - - for (int in_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); - in_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); - ++in_ax_pos_num ) - { - sino_3D = proj_data_3D.get_sinogram(in_ax_pos_num,0); - const float in_m = - proj_data_3D_info_ptr->get_m(Bin(0, 0, in_ax_pos_num, 0)); - - if (fabs(out_m - in_m) < 1E-2) - { - ++num_contributing_sinos; - sino_4D += sino_3D; - if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) - return Succeeded::no; - break; - } - const float in_m_next = in_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? - -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, in_ax_pos_num+1, 0)); - - if (fabs(out_m - .5F*(in_m + in_m_next)) < 1E-2) - { - ++num_contributing_sinos; - sino_4D += sino_3D; - sino_4D += proj_data_3D.get_sinogram(in_ax_pos_num+1,0); - sino_4D *= .5F; - if (proj_data_4D.set_sinogram(sino_4D) == Succeeded::no) - return Succeeded::no; - break; - } - } - if (num_contributing_sinos == 0) - warning("inverse_SSRB: no sinogram contributes to segment %d, axial_pos_num %d", - out_segment_num, out_ax_pos_num); - } - } - return Succeeded::yes; -} - - -Succeeded -transpose_inverse_SSRB(ProjData& proj_data_3D, - const ProjData& proj_data_4D) -{ - //construct projdata info - const ProjDataInfo * const proj_data_3D_info_ptr = dynamic_cast (proj_data_3D.get_proj_data_info_ptr()); - const ProjDataInfo * const proj_data_4D_info_ptr = dynamic_cast (proj_data_4D.get_proj_data_info_ptr()); - - // keep sinograms out of the loop to avoid reallocations. initialise to something because there's no default constructor - Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); - Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - Sinogram sino_4D2 = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - - for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) - { - sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); - const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); - const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? - -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); - - for (int in_segment_num = proj_data_4D.get_min_segment_num(); in_segment_num <= proj_data_4D.get_max_segment_num(); ++in_segment_num) - { - for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num);in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num ) - { - - sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); - const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); - - if (fabs(out_m - in_m) < 1E-2) - { - sino_3D += sino_4D; - } - - if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) - { - sino_4D *= .5F; - sino_3D += sino_4D; - } - - } - } - - proj_data_3D.set_sinogram(sino_3D); - } - - - - return Succeeded::yes; -} - -END_NAMESPACE_STIR From bbb454bd52fc5db689e9e1f8dc6b08d79c0368ec Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 17:49:10 +0100 Subject: [PATCH 129/274] test --- src/buildblock/inverse_SSRB.cxx | 19 ++++++++++++++++--- src/test/test_upsample.cxx | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 656e8ec543..895abd99a4 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -138,9 +138,13 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); Sinogram sino_4D2 = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + + for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) { sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); + + const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); @@ -160,14 +164,23 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { - sino_4D *= .5F; - sino_3D += sino_4D; + + sino_3D += proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); + sino_3D *= .5F; + int new_index = in_ax_pos_num - in_segment_num ; + + if(new_index>=proj_data_4D.get_min_axial_pos_num(in_segment_num)&&new_index<=proj_data_4D.get_max_axial_pos_num(in_segment_num)) + { + sino_3D += proj_data_4D.get_sinogram(new_index,-in_segment_num); + } + + } } } - proj_data_3D.set_sinogram(sino_3D); + proj_data_3D.set_sinogram(sino_3D); } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index dbd966f982..fd6276151f 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -256,7 +256,7 @@ run_tests() std::cout << "========== TEST SSRB =========== \n"; //creating proj data info - shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 2,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr exam_info_sptr_4D(new ExamInfo); ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); From 09c79bf1958ec4400c9b3db0266eb897f9b8b1e9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 18:01:50 +0100 Subject: [PATCH 130/274] add new index --- src/buildblock/inverse_SSRB.cxx | 11 ++++++----- src/test/test_upsample.cxx | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 895abd99a4..a64d803bcc 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -164,14 +164,15 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { - - sino_3D += proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); - sino_3D *= .5F; - int new_index = in_ax_pos_num - in_segment_num ; + sino_4D *= .5F; + sino_3D += sino_4D; + int new_index = in_ax_pos_num + in_segment_num ; if(new_index>=proj_data_4D.get_min_axial_pos_num(in_segment_num)&&new_index<=proj_data_4D.get_max_axial_pos_num(in_segment_num)) { - sino_3D += proj_data_4D.get_sinogram(new_index,-in_segment_num); + sino_4D2 = proj_data_4D.get_sinogram(new_index,-in_segment_num); + sino_4D2 *= .5F; + sino_3D += sino_4D2; } diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index fd6276151f..dbd966f982 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -256,7 +256,7 @@ run_tests() std::cout << "========== TEST SSRB =========== \n"; //creating proj data info - shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 2,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr exam_info_sptr_4D(new ExamInfo); ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); From 6da59ea9b8782b70a18bb4fa2e2ff2feae3c53a1 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 10 Jul 2019 21:03:29 +0100 Subject: [PATCH 131/274] missing LORs --- src/buildblock/inverse_SSRB.cxx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index a64d803bcc..e5b6d8e5a6 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -136,8 +136,6 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, // keep sinograms out of the loop to avoid reallocations. initialise to something because there's no default constructor Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - Sinogram sino_4D2 = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) @@ -156,6 +154,8 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); + const float in_m_prev = in_ax_pos_num == proj_data_4D.get_max_axial_pos_num(in_segment_num) ? + -1000000.F : proj_data_4D_info_ptr->get_m(Bin(-in_segment_num, 0, out_ax_pos_num+in_segment_num, 0)); if (fabs(out_m - in_m) < 1E-2) { @@ -166,15 +166,6 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, { sino_4D *= .5F; sino_3D += sino_4D; - int new_index = in_ax_pos_num + in_segment_num ; - - if(new_index>=proj_data_4D.get_min_axial_pos_num(in_segment_num)&&new_index<=proj_data_4D.get_max_axial_pos_num(in_segment_num)) - { - sino_4D2 = proj_data_4D.get_sinogram(new_index,-in_segment_num); - sino_4D2 *= .5F; - sino_3D += sino_4D2; - } - } From 29b45f744d43b9cad5b33a40bbe61efc717b8874 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 11 Jul 2019 11:56:08 +0100 Subject: [PATCH 132/274] zoom transpose --- src/buildblock/interpolate_projdata.cxx | 22 ++--- src/buildblock/zoom.cxx | 107 ++++++++++++++++++++++++ src/include/stir/zoom.h | 6 ++ src/test/test_upsample.cxx | 33 ++++---- src/test/test_zoom_image_adjoint.cxx | 88 ++++++++++++++++--- 5 files changed, 218 insertions(+), 38 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 04e68615f9..d324bb4707 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -573,8 +573,8 @@ interpolate_projdata_pull(ProjData& proj_data_out, { Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) - std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; + // std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; + // std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation proj_data_out.set_segment(sino_3D_out); //fill the output @@ -670,7 +670,7 @@ interpolate_projdata_push(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(non_interleaved_segment,2,2); //extend the views extend_tangential_position(extended); //extend the tangential positions - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; + // std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; // ===========================PUSH ================================== SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments @@ -681,8 +681,8 @@ interpolate_projdata_push(ProjData& proj_data_out, transpose_extend_tangential_position(extended); //reduce tangential positions SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + // std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + // std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================TRANSPOSE REMOVE INTERLEAVING ==================== SegmentBySinogram compressed_output(out, non_interleaved_proj_data_info_sptr, 0); @@ -691,8 +691,8 @@ interpolate_projdata_push(ProjData& proj_data_out, shared_ptr new_proj_data_info_sptr = proj_data_out_info.create_shared_clone(); SegmentBySinogram transpose_interleaved_segment = transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, compressed_output); - std::cout<<"FINAL:" << transpose_interleaved_segment.get_num_views() << "x" << transpose_interleaved_segment.get_num_tangential_poss() << '\n'; - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + // std::cout<<"FINAL:" << transpose_interleaved_segment.get_num_views() << "x" << transpose_interleaved_segment.get_num_tangential_poss() << '\n'; + // std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; // ======================== CREATE OUTPUT ============================= proj_data_out.set_segment(transpose_interleaved_segment); @@ -720,14 +720,14 @@ interpolate_projdata_push(ProjData& proj_data_out, SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + // std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; + // std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // ======================== CREATE OUTPUT ============================= SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; + //std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; + //std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 497007dc68..d7198ee047 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -539,4 +539,111 @@ zoom_image(PixelsOnCartesianGrid &image2D_out, } + +void +transpose_zoom_image(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, + const ZoomOptions zoom_options) +{ + image_out.set_exam_info(image_in.get_exam_info()); + /* + interpolation routine uses the following relation: + x_in_index = x_out_index/zoom + offset + compare to 'physical' coordinates + x_phys = (x_index) * voxel_size.x + origin.x + + as x_in_phys == x_out_phys, we find + (x_in_index)* voxel_size_in.x + origin_in.x == + (x_out_index )* voxel_size_out.x + origin_out.x + <=> + x_in_index = (x_out_index * voxel_size_out.x + + origin_out.x - origin_in.x) + / voxel_size_in.x + so, zoom= voxel_size_in.x/ voxel_size_out.x + offset = (origin_out.x - origin_in.x)/ voxel_size_in.x + */ + // check relation between indices and physical coordinates + { + const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); + if (norm(image_in.get_physical_coordinates_for_indices(indices) + - (image_in.get_voxel_size() * BasicCoordinate<3,float>(indices) + image_in.get_origin()) + ) > 2.F) + error("zoom_image is confused about the relation between indices and physical coordinates"); + } + const float zoom_x = + image_in.get_voxel_size().x() / image_out.get_voxel_size().x(); + const float zoom_y = + image_in.get_voxel_size().y() / image_out.get_voxel_size().y(); + const float zoom_z = + image_in.get_voxel_size().z() / image_out.get_voxel_size().z(); + const float x_offset = + (image_out.get_origin().x() - image_in.get_origin().x()) + / image_in.get_voxel_size().x(); + const float y_offset = + (image_out.get_origin().y() - image_in.get_origin().y()) + / image_in.get_voxel_size().y(); + const float z_offset = + (image_out.get_origin().z() - image_in.get_origin().z()) + / image_in.get_voxel_size().z(); + + + if(zoom_x==1.0F && zoom_y==1.0F && zoom_z==1.0F && + x_offset == 0.F && y_offset == 0.F && z_offset == 0.F && + image_in.get_index_range() == image_out.get_index_range() + ) + { + image_out = image_in; + return; + } + + // TODO creating a lot of new images here... + Array<3,float> + temp(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), + image_in.get_min_y(), image_in.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); + + for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) + for (int y=image_in.get_min_y(); y<=image_in.get_max_y(); y++) + overlap_interpolate(temp[z][y], image_in[z][y], zoom_x, x_offset); + + Array<3,float> temp2(IndexRange3D(image_in.get_min_z(), image_in.get_max_z(), + image_out.get_min_y(), image_out.get_max_y(), + image_out.get_min_x(), image_out.get_max_x())); + + for (int z=image_in.get_min_z(); z<=image_in.get_max_z(); z++) + overlap_interpolate(temp2[z], temp[z], zoom_y, y_offset); + + temp.recycle(); + + overlap_interpolate(image_out, temp2, zoom_z, z_offset); + + float scale_image = 1.F; + + switch (zoom_options.get_scaling_option()) + { + case ZoomOptions::preserve_values: + { + return; + } + + case ZoomOptions::preserve_projections: + + { + scale_image = zoom_x; + break; + } + + case ZoomOptions::preserve_sum: + { + scale_image = zoom_x*zoom_y*zoom_z; + break; + } + + } + + if (scale_image != 1.F) + image_out*= scale_image; + +} + END_NAMESPACE_STIR diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 8092546ac7..ece6b9125a 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -186,6 +186,12 @@ zoom_image(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, const ZoomOptions = ZoomOptions::preserve_sum); +void +transpose_zoom_image(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, + const ZoomOptions = ZoomOptions::preserve_sum); + + //------------------ 2D zooms--------------------- /*! diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index dbd966f982..5aa6372c4a 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -80,7 +80,7 @@ fill_projdata_with_random(ProjData & projdata) bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - sino[bin.view_num()][bin.tangential_pos_num()]= rand()%2;//((double) rand() / (1)) + 1; + sino[bin.view_num()][bin.tangential_pos_num()]= rand()%10;//((double) rand() / (1)) + 1; projdata.set_sinogram(sino); @@ -97,23 +97,23 @@ run_tests() // std::cout << "-------- Testing Upsampling and Downsampling ---------\n"; shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); - //shared_ptr exam_info_sptr(new ExamInfo); - //shared_ptr LR_exam_info_sptr(new ExamInfo); + shared_ptr exam_info_sptr(new ExamInfo); + shared_ptr LR_exam_info_sptr(new ExamInfo); //creating proj data info - // shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); // shared_ptr LR = ProjData::read_from_file("simulated_scatter_sino_UU2.hs"); // construct y - /* ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); + ProjDataInMemory y(exam_info_sptr, proj_data_info_sptr); unique_ptr sss(new SingleScatterSimulation()); sss->set_template_proj_data_info_sptr(proj_data_info_sptr); - int down_rings = static_cast(scanner_sptr->get_num_rings()/4); - int down_dets = static_cast(scanner_sptr->get_max_num_views()/4); + int down_rings = static_cast(scanner_sptr->get_num_rings()/6); + int down_dets = static_cast(scanner_sptr->get_max_num_views()/6); sss->downsample_scanner(down_rings, down_dets); @@ -189,7 +189,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.02); + set_tolerance(0.004); check_if_equal(cdot1, cdot2, "test adjoint"); @@ -249,18 +249,18 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.02); - check_if_equal(cdot1, cdot2, "test adjoint");*/ + set_tolerance(0.004); + check_if_equal(cdot1, cdot2, "test adjoint"); std::cout << "========== TEST SSRB =========== \n"; //creating proj data info - shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); - shared_ptr exam_info_sptr_4D(new ExamInfo); - ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); + //shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + //shared_ptr exam_info_sptr_4D(new ExamInfo); + //ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); - shared_ptr proj_data_info_sptr_3D(projdata_4D.get_proj_data_info_ptr()->clone()); + /*shared_ptr proj_data_info_sptr_3D(projdata_4D.get_proj_data_info_ptr()->clone()); proj_data_info_sptr_3D->reduce_segment_range(0,0); //create input template ProjDataInMemory projdata_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); @@ -283,8 +283,7 @@ run_tests() std::cout << "-------- = --------\n"; - int cdot1 = 0; - int cdot2 = 0; + for ( int segment_num = projdata_4D.get_min_segment_num(); segment_num <= projdata_4D.get_max_segment_num(); ++segment_num) { @@ -324,7 +323,7 @@ run_tests() std::cout << cdot1 << "=" << cdot2 << '\n'; set_tolerance(0.02); - check_if_equal(cdot1, cdot2, "test adjoint"); + check_if_equal(cdot1, cdot2, "test adjoint");*/ diff --git a/src/test/test_zoom_image_adjoint.cxx b/src/test/test_zoom_image_adjoint.cxx index 44e763a0ca..e93488bb38 100644 --- a/src/test/test_zoom_image_adjoint.cxx +++ b/src/test/test_zoom_image_adjoint.cxx @@ -3,27 +3,21 @@ /* Copyright (C) 2006- 2007, Hammersmith Imanet Ltd This file is part of STIR. - This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - See STIR/LICENSE.txt for details */ /*! \file \ingroup test - \brief Test program for stir::zoom_image (and stir::centre_of_gravity) - \author Kris Thielemans - */ #include "stir/VoxelsOnCartesianGrid.h" @@ -40,7 +34,6 @@ START_NAMESPACE_STIR /*! \ingroup test \brief Test class for zoom_image (and centre_of_gravity) - The tests check if a point source remains in the same physical location after zooming. This is done by checking the centre of gravity of the zoomed image. @@ -49,8 +42,43 @@ class zoom_imageTests : public RunTests { public: void run_tests(); + void fill_image_with_random(VoxelsOnCartesianGrid & image); + float dot_product(VoxelsOnCartesianGrid & image1, VoxelsOnCartesianGrid & image2); }; +void +zoom_imageTests::fill_image_with_random(VoxelsOnCartesianGrid & image) +{ + for(int i=0 ; i & image1,VoxelsOnCartesianGrid & image2) +{ + float cdot = 0; + for(int i=0 ; i(4,14,15)); VoxelsOnCartesianGrid image(range,origin, grid_spacing); - image.fill(.5F); + image.fill(0.F); const BasicCoordinate<3,int> indices = make_coordinate(1,2,3); image[indices] = 1.F; @@ -87,7 +115,6 @@ zoom_imageTests::run_tests() const double old_tolerance = this->get_tolerance(); // test 2 arg zoom_image - ZoomOptions zoom_options = ZoomOptions::preserve_values; { CartesianCoordinate3D new_origin (4.F,5.F,6.F); CartesianCoordinate3D new_grid_spacing (2.2F,3.1F,4.3F); @@ -97,7 +124,11 @@ zoom_imageTests::run_tests() CartesianCoordinate3D(5,15,20)); VoxelsOnCartesianGrid new_image(new_range,new_origin, new_grid_spacing); - zoom_image(new_image, image, zoom_options); + + VoxelsOnCartesianGrid A(new_range,new_origin, new_grid_spacing); + VoxelsOnCartesianGrid At(range,origin, grid_spacing); + + zoom_image(new_image, image); { // check if centre_of_gravity_in_mm returns same point this->set_tolerance(tolerance_for_distance); @@ -113,9 +144,46 @@ zoom_imageTests::run_tests() "test on 2-argument argument zoom_image: origin"); } + + + fill_image_with_random(image); + fill_image_with_random(new_image); + + //test preserve projections + zoom_image(A, image,ZoomOptions::preserve_projections); + transpose_zoom_image(At, new_image,ZoomOptions::preserve_projections); + float cdot1 = dot_product(A,new_image); + float cdot2 = dot_product(At,image); + + set_tolerance(0.004); + check_if_equal(cdot1,cdot2,"test on zoom option : preserve_projections"); + + //test preserve values + zoom_image(A, image,ZoomOptions::preserve_values); + transpose_zoom_image(At, new_image,ZoomOptions::preserve_values); + cdot1 = dot_product(A,new_image); + cdot2 = dot_product(At,image); + + set_tolerance(0.004); + check_if_equal(cdot1,cdot2,"test on zoom option : preserve_values"); + + //test preserve sum + zoom_image(A, image,ZoomOptions::preserve_sum); + transpose_zoom_image(At, new_image,ZoomOptions::preserve_sum); + cdot1 = dot_product(A,new_image); + cdot2 = dot_product(At,image); + + set_tolerance(0.004); + check_if_equal(cdot1,cdot2,"test on zoom option : preserve_sum"); + + + + } + + } END_NAMESPACE_STIR From 6de581e536d537990c99189792c9f176fd9b2eba Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 11 Jul 2019 14:52:32 +0100 Subject: [PATCH 133/274] new tests --- src/test/CMakeLists.txt | 1 + src/test/test_SSRB.cxx | 116 +++++++++++++++++++++++++++ src/test/test_zoom_image_adjoint.cxx | 10 +-- 3 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/test/test_SSRB.cxx diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 8e35ab1367..b433f2a7b9 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -43,6 +43,7 @@ Set(${dir_INVOLVED_TEST_EXE_SOURCES} test_display test_interpolate test_upsample + test_SSRB ) set(buildblock_simple_tests diff --git a/src/test/test_SSRB.cxx b/src/test/test_SSRB.cxx new file mode 100644 index 0000000000..6d13860198 --- /dev/null +++ b/src/test/test_SSRB.cxx @@ -0,0 +1,116 @@ +// +// +/*! + + \file + \ingroup test + + \author Ludovica Brusaferri + +*/ +/* + Copyright (C) 2015, University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ + +#include "stir/ProjDataInMemory.h" +#include "stir/inverse_SSRB.h" +#include "stir/ExamInfo.h" +#include "stir/ProjDataInfo.h" +#include "stir/Sinogram.h" +#include "stir/Viewgram.h" +#include "stir/Succeeded.h" +#include "stir/RunTests.h" +#include "stir/Scanner.h" +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/scatter/SingleScatterSimulation.h" +#include "stir/scatter/ScatterEstimation.h" +#include "stir/Sinogram.h" +#include "stir/Array.h" + +#include "stir/IO/write_to_file.h" + + + +START_NAMESPACE_STIR + + +class SSRBTests: public RunTests +{ +public: + void run_tests(); + void fill_projdata_with_random(ProjData & projdata); +}; + +void +SSRBTests:: +fill_projdata_with_random(ProjData & projdata) +{ + Bin bin; + { + for (bin.segment_num()=projdata.get_min_segment_num(); + bin.segment_num()<=projdata.get_max_segment_num(); + ++bin.segment_num()) + for (bin.axial_pos_num()= + projdata.get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) + { + + Sinogram sino = projdata.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); + + for (bin.view_num()=sino.get_min_view_num(); + bin.view_num()<=sino.get_max_view_num(); + ++bin.view_num()) + { + for (bin.tangential_pos_num()= + sino.get_min_tangential_pos_num(); + bin.tangential_pos_num()<= + sino.get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) + sino[bin.view_num()][bin.tangential_pos_num()]= rand()%10;//((double) rand() / (1)) + 1; + + projdata.set_sinogram(sino); + + } + + } + + } +} +void +SSRBTests:: +run_tests() +{ +// std::cout << "-------- Testing Upsampling and Downsampling ---------\n"; + + std::cout << "DONE" <<'\n'; + + + + +} + +END_NAMESPACE_STIR + + +USING_NAMESPACE_STIR + +int main() +{ + SSRBTests tests; + tests.run_tests(); + return tests.main_return_value(); +} diff --git a/src/test/test_zoom_image_adjoint.cxx b/src/test/test_zoom_image_adjoint.cxx index e93488bb38..53bc86df54 100644 --- a/src/test/test_zoom_image_adjoint.cxx +++ b/src/test/test_zoom_image_adjoint.cxx @@ -38,7 +38,7 @@ START_NAMESPACE_STIR after zooming. This is done by checking the centre of gravity of the zoomed image. */ -class zoom_imageTests : public RunTests +class zoom_imageAdjointTests : public RunTests { public: void run_tests(); @@ -47,7 +47,7 @@ class zoom_imageTests : public RunTests }; void -zoom_imageTests::fill_image_with_random(VoxelsOnCartesianGrid & image) +zoom_imageAdjointTests::fill_image_with_random(VoxelsOnCartesianGrid & image) { for(int i=0 ; i & image) } float -zoom_imageTests::dot_product(VoxelsOnCartesianGrid & image1,VoxelsOnCartesianGrid & image2) +zoom_imageAdjointTests::dot_product(VoxelsOnCartesianGrid & image1,VoxelsOnCartesianGrid & image2) { float cdot = 0; for(int i=0 ; i & image1,VoxelsOnCarte void -zoom_imageTests::run_tests() +zoom_imageAdjointTests::run_tests() { std::cerr << "Tests for zoom_image\n"; @@ -194,7 +194,7 @@ USING_NAMESPACE_STIR int main() { - zoom_imageTests tests; + zoom_imageAdjointTests tests; tests.run_tests(); return tests.main_return_value(); } From 51b7c081f34111c04755d670a42367a85ea7c6ee Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 11 Jul 2019 15:04:28 +0100 Subject: [PATCH 134/274] random generator in test --- src/test/test_SSRB.cxx | 77 +++++++++++++++++++++++++- src/test/test_upsample.cxx | 82 +++------------------------- src/test/test_zoom_image_adjoint.cxx | 8 ++- 3 files changed, 89 insertions(+), 78 deletions(-) diff --git a/src/test/test_SSRB.cxx b/src/test/test_SSRB.cxx index 6d13860198..1acdb6b320 100644 --- a/src/test/test_SSRB.cxx +++ b/src/test/test_SSRB.cxx @@ -94,9 +94,82 @@ void SSRBTests:: run_tests() { -// std::cout << "-------- Testing Upsampling and Downsampling ---------\n"; - std::cout << "DONE" <<'\n'; + + std::cout << "========== TEST SSRB =========== \n"; + + shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); + + //creating proj data info + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr exam_info_sptr_4D(new ExamInfo); + ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); + + shared_ptr proj_data_info_sptr_3D(projdata_4D.get_proj_data_info_ptr()->clone()); + proj_data_info_sptr_3D->reduce_segment_range(0,0); //create input template + + ProjDataInMemory projdata_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); + + ProjDataInMemory A_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); + ProjDataInMemory A_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); + + fill_projdata_with_random(projdata_4D); + fill_projdata_with_random(projdata_3D); + A_4D.fill(0); //initialise output + A_3D.fill(0); //initialise output + + + std::cout << "-------- Testing Inverse SSRB --------\n"; + inverse_SSRB(A_4D,projdata_3D); + + std::cout << "-------- Testing Transpose Inverse SSRB --------\n"; + + transpose_inverse_SSRB(A_3D,projdata_4D); + + std::cout << "-------- = --------\n"; + + float cdot1 = 0; + float cdot2 = 0; + + for ( int segment_num = projdata_4D.get_min_segment_num(); segment_num <= projdata_4D.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = projdata_4D.get_min_axial_pos_num(segment_num); axial_pos <= projdata_4D.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram yy_sinogram = projdata_4D.get_sinogram(axial_pos, segment_num); + const Sinogram At_sinogram = A_4D.get_sinogram(axial_pos, segment_num); + + for ( int view_num = projdata_4D.get_min_view_num(); view_num <= projdata_4D.get_max_view_num();view_num++) + { + for ( int tang_pos = projdata_4D.get_min_tangential_pos_num(); tang_pos <= projdata_4D.get_max_tangential_pos_num(); tang_pos++) + { + cdot1 += At_sinogram[view_num][tang_pos]*yy_sinogram[view_num][tang_pos]; + } + } + } + } + + for ( int segment_num = projdata_3D.get_min_segment_num(); segment_num <= projdata_3D.get_max_segment_num(); ++segment_num) + { + for (int axial_pos = projdata_3D.get_min_axial_pos_num(segment_num); axial_pos <= projdata_3D.get_max_axial_pos_num(segment_num); ++axial_pos) + { + + const Sinogram xx_sinogram = projdata_3D.get_sinogram(axial_pos, segment_num); + const Sinogram A_sinogram = A_3D.get_sinogram(axial_pos, segment_num); + + for ( int view_num = projdata_3D.get_min_view_num(); view_num <= projdata_3D.get_max_view_num();view_num++) + { + for ( int tang_pos = projdata_3D.get_min_tangential_pos_num(); tang_pos <= projdata_3D.get_max_tangential_pos_num(); tang_pos++) + { + cdot2 += xx_sinogram[view_num][tang_pos]*A_sinogram[view_num][tang_pos]; + } + } + } + } + + std::cout << cdot1 << "=" << cdot2 << '\n'; + set_tolerance(0.02); + check_if_equal(cdot1, cdot2, "test adjoint"); diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 5aa6372c4a..24dbca42b4 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -42,6 +42,8 @@ #include "stir/IO/write_to_file.h" +#include + START_NAMESPACE_STIR @@ -58,6 +60,10 @@ void UpsampleDownsampleTests:: fill_projdata_with_random(ProjData & projdata) { + + std::random_device random_device; + std::mt19937 random_number_generator(random_device()); + std::uniform_real_distribution number_distribution(0,10); Bin bin; { for (bin.segment_num()=projdata.get_min_segment_num(); @@ -80,7 +86,7 @@ fill_projdata_with_random(ProjData & projdata) bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - sino[bin.view_num()][bin.tangential_pos_num()]= rand()%10;//((double) rand() / (1)) + 1; + sino[bin.view_num()][bin.tangential_pos_num()]= number_distribution(random_number_generator); projdata.set_sinogram(sino); @@ -253,80 +259,6 @@ run_tests() check_if_equal(cdot1, cdot2, "test adjoint"); - std::cout << "========== TEST SSRB =========== \n"; - - //creating proj data info - //shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); - //shared_ptr exam_info_sptr_4D(new ExamInfo); - //ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); - - /*shared_ptr proj_data_info_sptr_3D(projdata_4D.get_proj_data_info_ptr()->clone()); - proj_data_info_sptr_3D->reduce_segment_range(0,0); //create input template - - ProjDataInMemory projdata_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); - - ProjDataInMemory A_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); - ProjDataInMemory A_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); - - fill_projdata_with_random(projdata_4D); - fill_projdata_with_random(projdata_3D); - A_4D.fill(0); //initialise output - A_3D.fill(0); //initialise output - - - std::cout << "-------- Testing Inverse SSRB --------\n"; - inverse_SSRB(A_4D,projdata_3D); - - std::cout << "-------- Testing Transpose Inverse SSRB --------\n"; - - transpose_inverse_SSRB(A_3D,projdata_4D); - - std::cout << "-------- = --------\n"; - - - - for ( int segment_num = projdata_4D.get_min_segment_num(); segment_num <= projdata_4D.get_max_segment_num(); ++segment_num) - { - for (int axial_pos = projdata_4D.get_min_axial_pos_num(segment_num); axial_pos <= projdata_4D.get_max_axial_pos_num(segment_num); ++axial_pos) - { - - const Sinogram yy_sinogram = projdata_4D.get_sinogram(axial_pos, segment_num); - const Sinogram At_sinogram = A_4D.get_sinogram(axial_pos, segment_num); - - for ( int view_num = projdata_4D.get_min_view_num(); view_num <= projdata_4D.get_max_view_num();view_num++) - { - for ( int tang_pos = projdata_4D.get_min_tangential_pos_num(); tang_pos <= projdata_4D.get_max_tangential_pos_num(); tang_pos++) - { - cdot1 += At_sinogram[view_num][tang_pos]*yy_sinogram[view_num][tang_pos]; - } - } - } - } - - for ( int segment_num = projdata_3D.get_min_segment_num(); segment_num <= projdata_3D.get_max_segment_num(); ++segment_num) - { - for (int axial_pos = projdata_3D.get_min_axial_pos_num(segment_num); axial_pos <= projdata_3D.get_max_axial_pos_num(segment_num); ++axial_pos) - { - - const Sinogram xx_sinogram = projdata_3D.get_sinogram(axial_pos, segment_num); - const Sinogram A_sinogram = A_3D.get_sinogram(axial_pos, segment_num); - - for ( int view_num = projdata_3D.get_min_view_num(); view_num <= projdata_3D.get_max_view_num();view_num++) - { - for ( int tang_pos = projdata_3D.get_min_tangential_pos_num(); tang_pos <= projdata_3D.get_max_tangential_pos_num(); tang_pos++) - { - cdot2 += xx_sinogram[view_num][tang_pos]*A_sinogram[view_num][tang_pos]; - } - } - } - } - - std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.02); - check_if_equal(cdot1, cdot2, "test adjoint");*/ - - - } END_NAMESPACE_STIR diff --git a/src/test/test_zoom_image_adjoint.cxx b/src/test/test_zoom_image_adjoint.cxx index 53bc86df54..9f8911ddde 100644 --- a/src/test/test_zoom_image_adjoint.cxx +++ b/src/test/test_zoom_image_adjoint.cxx @@ -29,6 +29,8 @@ #include #include "stir/RunTests.h" +#include + START_NAMESPACE_STIR /*! @@ -49,11 +51,15 @@ class zoom_imageAdjointTests : public RunTests void zoom_imageAdjointTests::fill_image_with_random(VoxelsOnCartesianGrid & image) { + std::random_device random_device; + std::mt19937 random_number_generator(random_device()); + std::uniform_real_distribution number_distribution(0,10); + for(int i=0 ; i Date: Mon, 15 Jul 2019 14:19:37 +0100 Subject: [PATCH 135/274] added gradient from est data --- .../SingleScatterLikelihoodAndGradient.cxx | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 5a0bf41494..f7d12bd428 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -636,5 +636,189 @@ if(compute_gradient) +double +SingleScatterLikelihoodAndGradient:: +L_G_function_from_est_data(const ProjData& data,const ProjData &est_data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) +{ + + this->output_proj_data_sptr->fill(0.f); + + std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + + if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) + { + std::cout << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + + } + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + std::cout << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + double sum = 0; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + sum+=this->L_G_for_view_segment_number_from_est_data(data, est_data,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); + + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + std::cout<< bin_counter << " / "<< total_bins <get_num_rings() << "\n"; + std::cout << "rings GATE:" << root_file_sptr->get_num_rings() << "\n"; ok = false; } if (scanner_sptr->get_num_detectors_per_ring() != root_file_sptr->get_num_dets_per_ring()) { stream << "the number of detector per ring, "; + std::cout << "n det STIR:" << scanner_sptr->get_num_detectors_per_ring() << "\n"; + std::cout << "n det GATE:" << root_file_sptr->get_num_dets_per_ring() << "\n"; ok = false; } diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index ae487f0824..20a697c6e5 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -643,11 +643,18 @@ process_data() assert(current_time>=start_time); process_new_time_event(record.time()); } + + if(record.is_energy()) + { + std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; + std::cout<< "energyB: " << record.energy().get_energyB_in_keV() << '\n'; + } // note: could do "else if" here if we would be sure that // a record can never be both timing and coincidence event // and there might be a scanner around that has them both combined. if (record.is_event()) { + std::cout<< "i'm here" << '\n'; assert(start_time <= current_time); Bin bin; // set value in case the event decoder doesn't touch it From 13d1fe60441820f7852cff1ecf04f21c6c939c16 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 27 Jul 2019 23:52:37 +0100 Subject: [PATCH 138/274] changes ok --- src/IO/interfile.cxx | 52 -- src/buildblock/zoom.cxx | 8 + src/include/stir/scatter/ScatterSimulation.h | 3 +- .../SingleScatterLikelihoodAndGradient.h | 9 +- src/include/stir/zoom.h | 4 + ...ingleScatterLikelihoodAndGradient copy.cxx | 824 ++++++++++++++++++ .../SingleScatterLikelihoodAndGradient.cxx | 141 +-- .../scatter_detection_modelling.cxx | 2 +- ...scatter_estimate_for_one_scatter_point.cxx | 17 +- 9 files changed, 919 insertions(+), 141 deletions(-) create mode 100644 src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx diff --git a/src/IO/interfile.cxx b/src/IO/interfile.cxx index 9d97191025..82570a612c 100644 --- a/src/IO/interfile.cxx +++ b/src/IO/interfile.cxx @@ -1400,61 +1400,9 @@ write_basic_interfile_PDFS_header(const string& header_file_name, output_header << scanner.parameter_info(); - - //Write the number of energy windows available - - if (pdfs.get_exam_info_ptr()->get_num_energy_windows() > 0) - { - output_header <<"number of energy windows := " << - pdfs.get_exam_info_ptr()->get_num_energy_windows() << '\n'; - } - - else - { - // need to write this anyway to allow vectored keys below - output_header <<"number of energy windows := 1"; - } - - // Write energy window lower and upper thresholds for all the energy windows available, if they are not -1 - - - - for (unsigned int num_windows = 0; num_windows < pdfs.get_exam_info_ptr()->get_num_energy_windows(); ++num_windows) - { - - if (pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows ) >= 0 && - pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows ) >= 0) - { - output_header << "energy window lower level [" << num_windows +1 << "] := " << - pdfs.get_exam_info_ptr()->get_low_energy_thres(num_windows) << '\n'; - output_header << "energy window upper level [" << num_windows +1 << "] := " << - pdfs.get_exam_info_ptr()->get_high_energy_thres(num_windows) << '\n'; - } - - } - - - //just for en_win>1 - - -if (pdfs.get_exam_info_ptr()->get_num_energy_windows() > 1) -{ - output_header << "energy window pair :="<<" {"<< pdfs.get_exam_info_ptr()->get_energy_window_pair().first << - ',' << pdfs.get_exam_info_ptr()->get_energy_window_pair().second <<"}\n"; - } - output_header << "effective central bin size (cm) := " - << proj_data_info_ptr->get_sampling_in_s(Bin(0,0,0,0))/10. << endl; - - } // end of cylindrical scanner - else - { - // TODO something here - } - - // write time frame info and energy windows write_interfile_time_frame_definitions(output_header, pdfs.get_exam_info()); write_interfile_energy_windows(output_header, pdfs.get_exam_info()); diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index d7198ee047..663abbf7c8 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -646,4 +646,12 @@ transpose_zoom_image(VoxelsOnCartesianGrid &image_out, } +void +zoom_image_swig(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const int zoom_option) +{ + ZoomOptions::Scaling zo = ZoomOptions::Scaling(zoom_option); + zoom_image(image_out, image_in,zo); +} + END_NAMESPACE_STIR diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 0a71e3dbc0..6257d44ae5 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -287,7 +287,7 @@ Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); //! average detection efficiency of unscattered counts double detection_efficiency_no_scatter(const unsigned det_num_A, - const unsigned det_num_B, int en_window) const; + const unsigned det_num_B) const; // next needs to be mutable because find_in_detection_points_vector is const mutable std::vector > detection_points_vector; @@ -370,6 +370,7 @@ Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); std::string output_proj_data_filename; //! Shared ptr to hold the simulated data. shared_ptr output_proj_data_sptr; + shared_ptr HR_output_proj_data_sptr; //! threshold below which a voxel in the attenuation image will not be considered as a candidate scatter point float attenuation_threshold; diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 2272a303c6..e3b2aa1aa9 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -64,8 +64,9 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); - double L_G_function_from_est_data(const ProjData& data,const ProjData &est_data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); - + void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); + ProjDataInMemory + likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); protected: @@ -102,10 +103,10 @@ class SingleScatterLikelihoodAndGradient : public double L_G_for_viewgram(const Viewgram& viewgram,const Viewgram& v_add, Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - double L_G_for_view_segment_number_from_est_data(const ProjData&data,const ProjData& est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu); + void L_G_for_view_segment_number_from_est_data(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu); - double L_G_for_viewgram_from_est_data(const Viewgram& viewgram,const Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); + void L_G_for_viewgram_from_est_data(const Viewgram& viewgram,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); }; diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index ece6b9125a..756ba10334 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -191,6 +191,10 @@ transpose_zoom_image(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, const ZoomOptions = ZoomOptions::preserve_sum); +void +zoom_image_swig(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const int zoom_option); + //------------------ 2D zooms--------------------- diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx new file mode 100644 index 0000000000..f7d12bd428 --- /dev/null +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx @@ -0,0 +1,824 @@ +/* + Copyright (C) 2016 University College London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/scatter/ScatterSimulation.h" +#include "stir/ViewSegmentNumbers.h" +#include "stir/Bin.h" + +#include "stir/Viewgram.h" +#include "stir/is_null_ptr.h" +#include "stir/IO/read_from_file.h" +#include "stir/IO/write_to_file.h" +#include "stir/info.h" +#include "stir/error.h" +#include +#include + +#include "stir/zoom.h" +#include "stir/SSRB.h" + +#include "stir/stir_math.h" +#include "stir/NumericInfo.h" + +START_NAMESPACE_STIR + +const char * const +SingleScatterLikelihoodAndGradient::registered_name = + "Single Scatter Likelihood And Gradient"; + + +SingleScatterLikelihoodAndGradient:: +SingleScatterLikelihoodAndGradient() : + base_type() +{ + this->set_defaults(); +} + + + +SingleScatterLikelihoodAndGradient:: +SingleScatterLikelihoodAndGradient(const std::string& parameter_filename) +{ + this->initialise(parameter_filename); +} + +SingleScatterLikelihoodAndGradient:: +~SingleScatterLikelihoodAndGradient() +{} + +static const float total_Compton_cross_section_511keV = +ScatterSimulation:: +total_Compton_cross_section(511.F); + +double +SingleScatterLikelihoodAndGradient:: +L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient, const bool isgradient_mu, const float rescale) +{ + + shared_ptr add_sino(new ProjDataInMemory(this->output_proj_data_sptr->get_exam_info_sptr(), + this->output_proj_data_sptr->get_proj_data_info_ptr()->create_shared_clone())); + add_sino->fill(0.000000000000000000001); + + L_G_function(data,*add_sino,gradient_image,compute_gradient,isgradient_mu,rescale); +} + +double +SingleScatterLikelihoodAndGradient:: +L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) +{ + + this->output_proj_data_sptr->fill(0.f); + + std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + + if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) + { + std::cout << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + + } + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + std::cout << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + double sum = 0; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + sum+=this->L_G_for_view_segment_number(data, add_sino,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); + + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + std::cout<< bin_counter << " / "<< total_bins < 1.E20) + warning("KL large at a=%g b=%g, threshold %g\n",a,b,threshold_a); +#ifdef ICHANGEDIT +#undef NDEBUG +#endif +#endif + assert(res>=-1.e-4); + return res; +} + + +double +SingleScatterLikelihoodAndGradient:: +L_G_for_viewgram(const Viewgram& viewgram, const Viewgram& v_add,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) +{ + + const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); + + // First construct a vector of all bins that we'll process. + // The reason for making this list before the actual calculation is that we can then parallelise over all bins + // without having to think about double loops. + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } + // now compute scatter for all bins + + double sum = 0; + + + VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); + +#ifdef STIR_OPENMP +#pragma omp parallel for reduction(+:total_scatter) schedule(dynamic) +#endif + + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { + //creates a template image to fill + tmp_gradient_image.fill(0); + + const Bin bin = all_bins[i]; + + //forward model + const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); + + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); + //in case a scaling factor for the data is needed,i.e. for adding different level of noise. By default is set to 1. + + float eps = v_add[bin.axial_pos_num()][bin.tangential_pos_num()]; + //float eps = 0.000000000000000000001; + sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-eps; + gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)-1); + if (sum != sum) error('Nan Here'); + } + + return sum; +} + + + + +double +SingleScatterLikelihoodAndGradient:: +L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, const bool compute_gradient,const bool isgradient_mu) +{ + double scatter_ratio_singles = 0; + unsigned det_num_B=0; + unsigned det_num_A=0; + + this->find_detectors(det_num_A, det_num_B,bin); + + for(std::size_t scatter_point_num =0; + scatter_point_num < this->scatt_points_vector.size(); + ++scatter_point_num) + { + + + + + scatter_ratio_singles += + L_G_for_one_scatter_point(gradient_image_bin, + scatter_point_num, + det_num_A, det_num_B,compute_gradient, isgradient_mu); + + } + + return scatter_ratio_singles; + //if (scatter_ratio_singles<0) std::cerr << "scatter_ratio_singles<0:" <& gradient, + const std::size_t scatter_point_num, + const unsigned det_num_A, + const unsigned det_num_B, const bool compute_gradient,const bool isgradient_mu) +{ + + // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. + + int low = 0; + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + + { + + int first_window=this->template_exam_info_sptr->get_energy_window_pair().first-1; + int second_window=this->template_exam_info_sptr->get_energy_window_pair().second-1; + + if(this->template_exam_info_sptr->get_low_energy_thres(first_window) <= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) + + { + low = first_window; + } + + else if(this->template_exam_info_sptr->get_low_energy_thres(first_window) >= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) + + { + low = second_window; + } + + } + + static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), + 2.f, + this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); + + //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); + + const CartesianCoordinate3D& scatter_point = + this->scatt_points_vector[scatter_point_num].coord; + const CartesianCoordinate3D& detector_coord_A = + this->detection_points_vector[det_num_A]; + const CartesianCoordinate3D& detector_coord_B = + this->detection_points_vector[det_num_B]; + // note: costheta is -cos_angle such that it is 1 for zero scatter angle + const float costheta = static_cast( + -cos_angle(detector_coord_A - scatter_point, + detector_coord_B - scatter_point)); + // note: costheta is identical for scatter to A or scatter to B + // Hence, the Compton_cross_section and energy are identical for both cases as well. + if(max_single_scatter_cos_angle>costheta) + return 0; + const float new_energy = + photon_energy_after_Compton_scatter_511keV(costheta); + + // The detection efficiency varies with respect to the energy window. + //The code can now compute the scatter for a combination of two windows X and Y + //Default: one window -> The code will combine the window with itself + + + //compute the probability of detection for two given energy windows X and Y + + + std::vectordetection_efficiency_scattered; + std::vectordetection_efficiency_unscattered; + + + detection_efficiency_scattered.push_back(0); + detection_efficiency_unscattered.push_back(0); + + + + //detection efficiency of each window for that energy + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); + detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); + } + + + int index0 = 0; + int index1 = 0; + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; + index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; + + } + + + float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; + float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; + + + + + const float emiss_to_detA = + cached_integral_over_activity_image_between_scattpoint_det + (static_cast (scatter_point_num), + det_num_A); + const float emiss_to_detB = + cached_integral_over_activity_image_between_scattpoint_det + (static_cast (scatter_point_num), + det_num_B); + if (emiss_to_detA==0 && emiss_to_detB==0) + return 0; + const float atten_to_detA = + cached_exp_integral_over_attenuation_image_between_scattpoint_det + (scatter_point_num, + det_num_A); + const float atten_to_detB = + cached_exp_integral_over_attenuation_image_between_scattpoint_det + (scatter_point_num, + det_num_B); + + const float dif_Compton_cross_section_value = + dif_Compton_cross_section(costheta, 511.F); + + const float rA_squared=static_cast(norm_squared(scatter_point-detector_coord_A)); + const float rB_squared=static_cast(norm_squared(scatter_point-detector_coord_B)); + + const float scatter_point_mu= + scatt_points_vector[scatter_point_num].mu_value; + + const CartesianCoordinate3D + detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); + const CartesianCoordinate3D + detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); + const float cos_incident_angle_AS = static_cast( + cos_angle(scatter_point - detector_coord_A, + detA_to_ring_center)); + const float cos_incident_angle_BS = static_cast( + cos_angle(scatter_point - detector_coord_B, + detB_to_ring_center)); + + if (cos_incident_angle_AS*cos_incident_angle_BS<0) + return 0; + +#ifndef NDEBUG + { + // check if mu-value ok + // currently terribly shift needed as in sample_scatter_points (TODO) + const VoxelsOnCartesianGrid& image = + dynamic_cast&>(*this->density_image_for_scatter_points_sptr); + const CartesianCoordinate3D voxel_size = image.get_voxel_size(); + const float z_to_middle = + (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; + CartesianCoordinate3D shifted=scatter_point; + shifted.z() += z_to_middle; + assert(scatter_point_mu== + (*this->density_image_for_scatter_points_sptr)[this->density_image_for_scatter_points_sptr->get_indices_closest_to_physical_coordinates(shifted)]); + } +#endif + +#ifndef NEWSCALE + /* projectors work in pixel units, so convert attenuation data + from cm^-1 to pixel_units^-1 */ + const float rescale = + dynamic_cast &>(*density_image_sptr). + get_grid_spacing()[3]/10; +#else + const float rescale = + 0.1F; +#endif + + + //normalisation + + + // we will divide by the effiency of the detector pair for unscattered photons + // (computed with the same detection model as used in the scatter code) + // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. + + // there is a scatter_volume factor for every scatter point, as the sum over scatter points + // is an approximation for the integral over the scatter point. + + // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code + + + // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window + //find the window that contains 511 keV + + int index_photopeak = 0; //default for one energy window + + if (this->template_exam_info_sptr->get_num_energy_windows()>1) + { + for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) + { + if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) + + { + + index_photopeak = i; + } + + } + } + + //normalisation factor between trues and scattered counts + + const double common_factor = + 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index_photopeak) * + scatter_volume/total_Compton_cross_section_511keV; + + + // Single ScatterForward Model + + float scatter_ratio=0; + + scatter_ratio= (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + + + /*Single Scatter Forward model Jacobian w.r.t. attenuation: + * The derivative is given by three terms, respectively in [A,S], [B,S] and [S] */ + + float contribution_AS_mu = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* + total_Compton_cross_section_relative_to_511keV(new_energy)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + float contribution_BS_mu = (detection_probability_XY*emiss_to_detA* + (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* + (total_Compton_cross_section_relative_to_511keV(new_energy)) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* + pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + float contribution_S = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) + +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + + /*Single Scatter Forward model Jacobian w.r.t. activity: + * + * The derivative is given by two terms, respectively in [A,S] and [B,S] */ + + + float contribution_AS_act = (detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + float contribution_BS_act = (detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *atten_to_detB + *atten_to_detA + *scatter_point_mu + *cos_incident_angle_AS + *cos_incident_angle_BS + *dif_Compton_cross_section_value + *common_factor; + + + //Fill gradient image along [A,S], [B,S] and in [S] + + +if(compute_gradient) +{ + if (isgradient_mu) + + { + line_contribution(gradient,rescale,scatter_point, + detector_coord_B,contribution_BS_mu); + + line_contribution(gradient,rescale,scatter_point, + detector_coord_A,contribution_AS_mu); + + s_contribution(gradient,scatter_point, + contribution_S); + + } + + else + + { + + line_contribution_act(gradient,scatter_point, + detector_coord_B,contribution_BS_act); + + line_contribution_act(gradient,scatter_point, + detector_coord_A,contribution_AS_act); + } + +} + + + + return scatter_ratio; + +} + + + +double +SingleScatterLikelihoodAndGradient:: +L_G_function_from_est_data(const ProjData& data,const ProjData &est_data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) +{ + + this->output_proj_data_sptr->fill(0.f); + + std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; + + if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && + this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) + { + std::cout << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; + + } + + + for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) + { + std::cout << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + double sum = 0; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + sum+=this->L_G_for_view_segment_number_from_est_data(data, est_data,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); + + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + std::cout<< bin_counter << " / "<< total_bins <& viewgram, const Viewgram& v_add,V VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); -#ifdef STIR_OPENMP -#pragma omp parallel for reduction(+:total_scatter) schedule(dynamic) -#endif - for (int i = 0; i < static_cast(all_bins.size()); ++i) { //creates a template image to fill @@ -496,26 +493,11 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window //find the window that contains 511 keV - int index_photopeak = 0; //default for one energy window - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) - { - if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) - - { - - index_photopeak = i; - } - - } - } //normalisation factor between trues and scattered counts const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index_photopeak) * + 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * scatter_volume/total_Compton_cross_section_511keV; @@ -636,30 +618,12 @@ if(compute_gradient) -double + +void SingleScatterLikelihoodAndGradient:: -L_G_function_from_est_data(const ProjData& data,const ProjData &est_data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) +L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) { - this->output_proj_data_sptr->fill(0.f); - - std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; - - if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && - this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) - { - std::cout << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; - - } - - - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - std::cout << "energy window lower level"<<"["<L_G_for_view_segment_number_from_est_data(data, est_data,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); + this->L_G_for_view_segment_number_from_est_data(data,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * @@ -734,32 +698,24 @@ L_G_function_from_est_data(const ProjData& data,const ProjData &est_data,VoxelsO } } - - - std::cout << "LIKELIHOOD:= " << sum << '\n'; - - - return sum; } -double +void SingleScatterLikelihoodAndGradient:: -L_G_for_view_segment_number_from_est_data(const ProjData&data, const ProjData& est_data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu) +L_G_for_view_segment_number_from_est_data(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu) { Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - Viewgram v_est=est_data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - double sum = L_G_for_viewgram_from_est_data(viewgram,v_est,gradient_image, rescale, compute_gradient,isgradient_mu); + L_G_for_viewgram_from_est_data(viewgram,gradient_image, rescale, compute_gradient,isgradient_mu); - return sum; } -double +void SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram_from_est_data(const Viewgram& viewgram, const Viewgram& v_est, VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) +L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) { const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); @@ -790,33 +746,84 @@ L_G_for_viewgram_from_est_data(const Viewgram& viewgram, const Viewgram tmp_gradient_image(gradient_image); -#ifdef STIR_OPENMP -#pragma omp parallel for reduction(+:total_scatter) schedule(dynamic) -#endif for (int i = 0; i < static_cast(all_bins.size()); ++i) { //creates a template image to fill tmp_gradient_image.fill(0); - const Bin bin = all_bins[i]; //forward model const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); - - //v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); - //in case a scaling factor for the data is needed,i.e. for adding different level of noise. By default is set to 1. - - sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()])- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]; - gradient_image += tmp_gradient_image*v_est[bin.axial_pos_num()][bin.tangential_pos_num()]; + gradient_image += tmp_gradient_image*viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; if (sum != sum) error('Nan Here'); } - - return sum; } +ProjDataInMemory +SingleScatterLikelihoodAndGradient:: +likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) +{ + ScatterSimulation::process_data(); + + gradient_image_LR.fill(0); + gradient_image_HR.fill(0); + + ProjDataInMemory ratio_HR(projdata); + ProjDataInMemory est_projdata_HR(projdata); + ProjDataInMemory ratio_LR(*(this->output_proj_data_sptr)); + + if((this->output_proj_data_sptr->get_num_views()!=projdata.get_num_views())||(this->output_proj_data_sptr->get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,*(this->output_proj_data_sptr),true); + else + est_projdata_HR.fill(*(this->output_proj_data_sptr)); + + Bin bin; + { + for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) + for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); + + for (bin.view_num()=sino.get_min_view_num(); + bin.view_num()<=sino.get_max_view_num(); + ++bin.view_num()) + { + for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; + ratio_HR.set_sinogram(ratio_sino); + } + + } + } + + if((this->output_proj_data_sptr->get_num_views()!=projdata.get_num_views())||(this->output_proj_data_sptr->get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::push_scatter_estimate(ratio_LR,*(this->output_proj_data_sptr),ratio_HR,true); + else + ratio_LR.fill(ratio_HR); + L_G_function_from_est_data(ratio_LR,gradient_image_LR,compute_gradient, isgradient_mu,1); + + this->HR_output_proj_data_sptr.reset(new ProjDataInMemory(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()->create_shared_clone())); + this->HR_output_proj_data_sptr->fill(est_projdata_HR); + + if((gradient_image_HR.get_x_size()!=gradient_image_LR.get_x_size())||(gradient_image_HR.get_y_size()!=gradient_image_LR.get_y_size())||(gradient_image_HR.get_z_size()!=gradient_image_LR.get_z_size())) + { + if(isgradient_mu==true) + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_values); + else + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_projections); + + } + + ProjDataInMemory est_data_HR = *(this->HR_output_proj_data_sptr); + return est_data_HR; + +} diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 7658849e5f..36ac0a1ffe 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -134,7 +134,7 @@ energy_lower_limit(const float low, const float approx, const float resolution_a double ScatterSimulation:: detection_efficiency_no_scatter(const unsigned det_num_A, - const unsigned det_num_B, int en_window) const + const unsigned det_num_B) const { // TODO: slightly dangerous to use a static here // it would give wrong results when the energy_thresholds are changed... diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 660d1edaf1..7d65f082b6 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -218,26 +218,11 @@ detection_efficiency_unscattered.push_back(0); // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window //find the window that contains 511 keV - int index_photopeak = 0; //default for one energy window - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) - { - if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) - - { - - index_photopeak = i; - } - - } - } //normalisation factor between trues and scattered counts const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index_photopeak) * + 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * scatter_volume/total_Compton_cross_section_511keV; From afbbcae7f27c432af3c369a94c59e8af638a58b3 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 29 Jul 2019 15:38:11 +0100 Subject: [PATCH 139/274] zoom and test --- src/buildblock/interpolate_projdata.cxx | 30 -- src/buildblock/inverse_SSRB.cxx | 2 - src/buildblock/zoom.cxx | 8 + .../SingleScatterLikelihoodAndGradient.h | 10 +- src/include/stir/zoom.h | 3 + .../SingleScatterLikelihoodAndGradient.cxx | 272 +++++++++++++++++- src/test/test_SSRB.cxx | 2 +- 7 files changed, 287 insertions(+), 40 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index d324bb4707..9fa272b15b 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -548,23 +548,10 @@ interpolate_projdata_pull(ProjData& proj_data_out, { shared_ptr non_interleaved_proj_data_info_sptr = make_non_interleaved_proj_data_info(proj_data_in_info); //create non interleaved projdata info const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_in.get_segment_by_sinogram(0)); //create non interleaved segment - std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; - std::cout<<"NON-INTERLEAVED:" << non_interleaved_segment.get_num_views() << "x" << non_interleaved_segment.get_num_tangential_poss() << '\n'; - std::fstream s; - open_write_binary(s, "noninterleaved.data"); - write_data(s,non_interleaved_segment); - s.close(); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //here we are doubling the number of views extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - open_write_binary(s, "extended_before_interopolation.data"); - write_data(s,extended); - s.close(); sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation - open_write_binary(s, "output.data"); - write_data(s,sino_3D_out); - s.close(); proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) return Succeeded::no; @@ -573,9 +560,6 @@ interpolate_projdata_pull(ProjData& proj_data_out, { Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) - // std::cout<<"ORIGINAL IN:" << proj_data_in_info.get_num_views() << "x" << proj_data_in_info.get_num_tangential_poss() << '\n'; - // std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) @@ -670,7 +654,6 @@ interpolate_projdata_push(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(non_interleaved_segment,2,2); //extend the views extend_tangential_position(extended); //extend the tangential positions - // std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; // ===========================PUSH ================================== SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments @@ -681,18 +664,13 @@ interpolate_projdata_push(ProjData& proj_data_out, transpose_extend_tangential_position(extended); //reduce tangential positions SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - // std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // =================TRANSPOSE REMOVE INTERLEAVING ==================== SegmentBySinogram compressed_output(out, non_interleaved_proj_data_info_sptr, 0); - std::cout<<"NON-INTERLEAVED:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; shared_ptr new_proj_data_info_sptr = proj_data_out_info.create_shared_clone(); SegmentBySinogram transpose_interleaved_segment = transpose_make_non_interleaved_segment(*new_proj_data_info_sptr, compressed_output); - // std::cout<<"FINAL:" << transpose_interleaved_segment.get_num_views() << "x" << transpose_interleaved_segment.get_num_tangential_poss() << '\n'; - // std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; // ======================== CREATE OUTPUT ============================= proj_data_out.set_segment(transpose_interleaved_segment); @@ -706,28 +684,20 @@ interpolate_projdata_push(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); //extend the views extend_tangential_position(extended); //extend the tangential positions - std::cout<<"EXT - ARRAY:" << extended.size_all()/(extended[0][0].size_all()*extended[0].size_all()/(extended[0][0].size_all())) << "x" << extended[0].size_all()/extended[0][0].size_all()<< "x" << extended[0][0].size_all() << '\n'; - // ===========================PUSH ================================== SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' - //sample_function_on_regular_grid_push(sino_3D_out,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== transpose_extend_tangential_position(extended); shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended - std::cout<<"EXT - SINO:" << extended_segment_sino.get_num_views() << "x" << extended_segment_sino.get_num_tangential_poss() << '\n'; Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out - // std::cout<<"EXT - TRANSPOSE:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; - // std::cout<<"EXT - TRANSPOSE Pt.2:" << out.size_all()/(out[0][0].size_all()*out[0].size_all()/(out[0][0].size_all())) << "x" << out[0].size_all()/out[0][0].size_all()<< "x" << out[0][0].size_all() << '\n'; // ======================== CREATE OUTPUT ============================= SegmentBySinogram compressed_output(out, extended_proj_data_info_sptr, 0); - //std::cout<<"FINAL:" << compressed_output.get_num_views() << "x" << compressed_output.get_num_tangential_poss() << '\n'; - //std::cout<<"OUT - CORRECT:" << sino_3D_out.get_num_views() << "x" << sino_3D_out.get_num_tangential_poss() << '\n'; proj_data_out.set_segment(compressed_output); if (proj_data_out.set_segment(compressed_output) == Succeeded::no) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index e5b6d8e5a6..176694d3be 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -66,11 +66,9 @@ inverse_SSRB(ProjData& proj_data_4D, Sinogram sino_4D = proj_data_4D. get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - std::cout<< "SSRB-4D" << proj_data_4D.get_max_axial_pos_num(0) << '\n'; Sinogram sino_3D = proj_data_3D. get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); - std::cout<< "SSRB-3D"<< proj_data_3D.get_max_axial_pos_num(0) << '\n'; for (int out_segment_num = proj_data_4D.get_min_segment_num(); out_segment_num <= proj_data_4D.get_max_segment_num(); diff --git a/src/buildblock/zoom.cxx b/src/buildblock/zoom.cxx index 663abbf7c8..5150c8298f 100644 --- a/src/buildblock/zoom.cxx +++ b/src/buildblock/zoom.cxx @@ -654,4 +654,12 @@ zoom_image_swig(VoxelsOnCartesianGrid &image_out, zoom_image(image_out, image_in,zo); } +void +transpose_zoom_image_swig(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const int zoom_option) +{ + ZoomOptions::Scaling zo = ZoomOptions::Scaling(zoom_option); + transpose_zoom_image(image_out, image_in,zo); +} + END_NAMESPACE_STIR diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index e3b2aa1aa9..874fa02125 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -66,8 +66,10 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); ProjDataInMemory - likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); + likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const ProjData &est_data, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); + ProjDataInMemory + likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); protected: void @@ -108,6 +110,12 @@ class SingleScatterLikelihoodAndGradient : public void L_G_for_viewgram_from_est_data(const Viewgram& viewgram,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); + void + get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); + void + low_res_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); + void low_res_jacobian_for_viewgram(Viewgram& v_est,std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); + void get_ratio(const ProjData& projdata,const ProjData &add_projdata, ProjData &est_projdata, std::vector &ratio_vector); }; diff --git a/src/include/stir/zoom.h b/src/include/stir/zoom.h index 756ba10334..5b3d6973c5 100644 --- a/src/include/stir/zoom.h +++ b/src/include/stir/zoom.h @@ -194,6 +194,9 @@ transpose_zoom_image(VoxelsOnCartesianGrid &image_out, void zoom_image_swig(VoxelsOnCartesianGrid &image_out, const VoxelsOnCartesianGrid &image_in, const int zoom_option); +void +transpose_zoom_image_swig(VoxelsOnCartesianGrid &image_out, + const VoxelsOnCartesianGrid &image_in, const int zoom_option); //------------------ 2D zooms--------------------- diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index e980d59d80..2ab14de69e 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -763,21 +763,23 @@ L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesia ProjDataInMemory SingleScatterLikelihoodAndGradient:: -likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) +likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata,const ProjData &est_data, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) { - ScatterSimulation::process_data(); + gradient_image_LR.fill(0); gradient_image_HR.fill(0); + // est_LR.fill(*(this->output_proj_data_sptr)); + ProjDataInMemory ratio_HR(projdata); ProjDataInMemory est_projdata_HR(projdata); - ProjDataInMemory ratio_LR(*(this->output_proj_data_sptr)); + ProjDataInMemory ratio_LR(est_data); if((this->output_proj_data_sptr->get_num_views()!=projdata.get_num_views())||(this->output_proj_data_sptr->get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,*(this->output_proj_data_sptr),true); + ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_data,true); else - est_projdata_HR.fill(*(this->output_proj_data_sptr)); + est_projdata_HR.fill(est_data); Bin bin; { @@ -802,7 +804,7 @@ likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const Pr } if((this->output_proj_data_sptr->get_num_views()!=projdata.get_num_views())||(this->output_proj_data_sptr->get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::push_scatter_estimate(ratio_LR,*(this->output_proj_data_sptr),ratio_HR,true); + ScatterEstimation::push_scatter_estimate(ratio_LR,est_data,ratio_HR,true); else ratio_LR.fill(ratio_HR); @@ -825,6 +827,264 @@ likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const Pr } +ProjDataInMemory +SingleScatterLikelihoodAndGradient:: +likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) +{ + gradient_image_LR.fill(0); + gradient_image_HR.fill(0); + int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only + std::vector > jacobian_array; + std::vector ratio; + jacobian_array.reserve(lenght); + ratio.reserve(lenght); + for (int i = 0 ; i <= lenght ; ++i) + { + jacobian_array.push_back(gradient_image_LR); + ratio.push_back(0); + } + + get_jacobian(jacobian_array, compute_gradient, isgradient_mu); + + get_ratio(projdata,add_projdata,*(this->output_proj_data_sptr),ratio); + + for (int i = 0 ; i <= lenght ; ++i) + { + gradient_image_LR += jacobian_array[i]*ratio[i]; + } + + if((gradient_image_HR.get_x_size()!=gradient_image_LR.get_x_size())||(gradient_image_HR.get_y_size()!=gradient_image_LR.get_y_size())||(gradient_image_HR.get_z_size()!=gradient_image_LR.get_z_size())) + { + if(isgradient_mu==true) + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_values); + else + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_projections); + + } + + ProjDataInMemory est_data_HR = *(this->HR_output_proj_data_sptr); + return est_data_HR; + +} + +void +SingleScatterLikelihoodAndGradient:: +get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) +{ + + this->output_proj_data_sptr->fill(0.f); + + this->remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + double sum = 0; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + this->low_res_jacobian_for_view_segment_number(gradient_image_array,vs_num,compute_gradient,isgradient_mu); + + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + std::cout<< bin_counter << " / "<< total_bins < > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) +{ + + Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); + + low_res_jacobian_for_viewgram(v_est,gradient_image_array, compute_gradient,isgradient_mu); + output_proj_data_sptr->set_viewgram(v_est); + +} + +void +SingleScatterLikelihoodAndGradient:: +low_res_jacobian_for_viewgram(Viewgram& v_est,std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) +{ + + const ViewSegmentNumbers vs_num(v_est.get_view_num(),v_est.get_segment_num()); + + // First construct a vector of all bins that we'll process. + // The reason for making this list before the actual calculation is that we can then parallelise over all bins + // without having to think about double loops. + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } + // now compute scatter for all bins + + + VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); + + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { + //creates a template image to fill + tmp_gradient_image.fill(0); + + const Bin bin = all_bins[i]; + + //forward model + const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); + + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); + gradient_image_array[i] += tmp_gradient_image; + } + +} + +void +SingleScatterLikelihoodAndGradient:: +get_ratio(const ProjData& projdata,const ProjData &add_projdata, ProjData &est_projdata, std::vector &ratio_vector) +{ + + ProjDataInMemory ratio_HR(projdata); + ProjDataInMemory est_projdata_HR(projdata); + ProjDataInMemory ratio_LR(est_projdata); + + if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,true); + else + est_projdata_HR.fill(est_projdata); + + Bin bin; + { + for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) + for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); + + for (bin.view_num()=sino.get_min_view_num(); + bin.view_num()<=sino.get_max_view_num(); + ++bin.view_num()) + { + for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; + ratio_HR.set_sinogram(ratio_sino); + } + + } + } + + if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::push_scatter_estimate(ratio_LR,est_projdata,ratio_HR,true); + else + ratio_LR.fill(ratio_HR); + + ViewSegmentNumbers vs_num; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num();vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); ++vs_num.view_num()) + { + + Viewgram viewgram = ratio_LR.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + + const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } + + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { + + const Bin bin = all_bins[i]; + + ratio_vector[i] = viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; + } + + } + } + + this->HR_output_proj_data_sptr.reset(new ProjDataInMemory(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()->create_shared_clone())); + this->HR_output_proj_data_sptr->fill(est_projdata_HR); + +} + END_NAMESPACE_STIR diff --git a/src/test/test_SSRB.cxx b/src/test/test_SSRB.cxx index 1acdb6b320..63e5394929 100644 --- a/src/test/test_SSRB.cxx +++ b/src/test/test_SSRB.cxx @@ -101,7 +101,7 @@ run_tests() shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); //creating proj data info - shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 1,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr exam_info_sptr_4D(new ExamInfo); ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); From 8ced950b5d4b38ef9b6c0d3fabb8baadbf5b0caf Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 30 Jul 2019 10:28:25 +0100 Subject: [PATCH 140/274] fixed bug root --- src/IO/InputStreamFromROOTFile.cxx | 10 ++++++---- .../InputStreamFromROOTFileForCylindricalPET.cxx | 12 ++++++------ src/IO/InputStreamFromROOTFileForECATPET.cxx | 12 ++++++------ src/include/stir/IO/InputStreamFromROOTFile.h | 12 ++++++------ src/include/stir/IO/InputStreamFromROOTFile.inl | 16 ++++++++-------- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/IO/InputStreamFromROOTFile.cxx b/src/IO/InputStreamFromROOTFile.cxx index 1517926d78..1790a5911d 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -53,8 +53,10 @@ InputStreamFromROOTFile::set_defaults() singles_readout_depth = -1; exclude_scattered = false; exclude_randoms = false; - low_energy_window = 0.f; - up_energy_window = 1000.f; + low_energy_window.resize(1); + up_energy_window.resize(1); + low_energy_window[0] = 0.f; + up_energy_window[0] = 1000.f; read_optional_root_fields=false; } @@ -67,8 +69,8 @@ InputStreamFromROOTFile::initialise_keymap() this->parser.add_key("exclude scattered events", &this->exclude_scattered); this->parser.add_key("exclude random events", &this->exclude_randoms); this->parser.add_key("offset (num of detectors)", &this->offset_dets); - this->parser.add_key("low energy window (keV)", &this->low_energy_window); - this->parser.add_key("upper energy window (keV)", &this->up_energy_window); + this->parser.add_key("low energy window (keV)", &this->low_energy_window[0]); + this->parser.add_key("upper energy window (keV)", &this->up_energy_window[0]); this->parser.add_key("read optional ROOT fields", &this->read_optional_root_fields); } diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index df1eef4517..1e5829216b 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -52,8 +52,8 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - low_energy_window = _low_energy_window; - up_energy_window = _up_energy_window; + low_energy_window[0] = _low_energy_window; + up_energy_window[0] = _up_energy_window; offset_dets = _offset_dets; half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; @@ -81,10 +81,10 @@ get_next_record(CListRecordROOT& record) continue; if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) continue; - if (this->energy1 < this->low_energy_window || - this->energy1 > this->up_energy_window || - this->energy2 < this->low_energy_window || - this->energy2 > this->up_energy_window) + if (this->energy1 < this->low_energy_window[0] || + this->energy1 > this->up_energy_window[0] || + this->energy2 < this->low_energy_window[0] || + this->energy2 > this->up_energy_window[0]) continue; break; diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 06693bad2b..f4146be303 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -49,8 +49,8 @@ InputStreamFromROOTFileForECATPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - low_energy_window = _low_energy_window; - up_energy_window = _up_energy_window; + low_energy_window[0] = _low_energy_window; + up_energy_window[0] = _up_energy_window; offset_dets = _offset_dets; half_block = crystal_repeater_y / 2 - 1; @@ -77,10 +77,10 @@ get_next_record(CListRecordROOT& record) continue; if ( eventID1 != eventID2 && exclude_randoms ) continue; - if (energy1 < low_energy_window || - energy1 > up_energy_window || - energy2 < low_energy_window || - energy2 > up_energy_window) + if (energy1 < low_energy_window[0] || + energy1 > up_energy_window[0] || + energy2 < low_energy_window[0] || + energy2 > up_energy_window[0]) continue; break; diff --git a/src/include/stir/IO/InputStreamFromROOTFile.h b/src/include/stir/IO/InputStreamFromROOTFile.h index c8cd98c4cb..ccbe2dab86 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.h +++ b/src/include/stir/IO/InputStreamFromROOTFile.h @@ -133,9 +133,9 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile virtual int get_num_trans_crystals_per_singles_unit() const = 0; //! Lower energy threshold - inline float get_low_energy_thres() const; + inline float get_low_energy_thres(int en_win = 0) const; //! Upper energy threshold - inline float get_up_energy_thres() const; + inline float get_up_energy_thres(int en_win = 0) const; //! Set singles_readout_depth inline void set_singles_readout_depth(int); @@ -150,9 +150,9 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile inline void set_detectors_offset(int); - inline void set_low_energy_window(float); + inline void set_low_energy_window(float, int en_win = 0); - inline void set_upper_energy_window(float); + inline void set_upper_energy_window(float, int en_win = 0); //! Set the read_optional_root_fields flag inline void set_optional_ROOT_fields(bool); @@ -197,9 +197,9 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! Skip random events (eventID1 != eventID2) bool exclude_randoms; //! Lower energy threshold - float low_energy_window; + std::vector low_energy_window; //! Upper energy threshold - float up_energy_window; + std::vector up_energy_window; //! This value will apply a rotation on the detectors' id in the same ring. int offset_dets; //!For the singles_readout_depth from GATE's online documentation: diff --git a/src/include/stir/IO/InputStreamFromROOTFile.inl b/src/include/stir/IO/InputStreamFromROOTFile.inl index 97d5a44486..21b87b0c57 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.inl +++ b/src/include/stir/IO/InputStreamFromROOTFile.inl @@ -81,16 +81,16 @@ set_saved_get_positions(const std::vector &poss) float InputStreamFromROOTFile:: -get_low_energy_thres() const +get_low_energy_thres(int en_win) const { - return low_energy_window; + return low_energy_window[en_win]; } float InputStreamFromROOTFile:: -get_up_energy_thres() const +get_up_energy_thres(int en_win) const { - return up_energy_window; + return up_energy_window[en_win]; } std::string @@ -137,15 +137,15 @@ InputStreamFromROOTFile::set_detectors_offset(int val) } void -InputStreamFromROOTFile::set_low_energy_window(float val) +InputStreamFromROOTFile::set_low_energy_window(float val, int en_win) { - low_energy_window = val; + low_energy_window[en_win] = val; } void -InputStreamFromROOTFile::set_upper_energy_window(float val) +InputStreamFromROOTFile::set_upper_energy_window(float val, int en_win) { - up_energy_window = val; + up_energy_window[en_win] = val; } void From b90c841224501fd2f47ed200de4017d853e6269d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 31 Jul 2019 12:36:14 +0100 Subject: [PATCH 141/274] test scatter --- src/test/CMakeLists.txt | 1 + src/test/test_ScatterGradient.cxx | 95 +++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/test/test_ScatterGradient.cxx diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b433f2a7b9..c2c2be71ca 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -44,6 +44,7 @@ Set(${dir_INVOLVED_TEST_EXE_SOURCES} test_interpolate test_upsample test_SSRB + test_ScatterGradient ) set(buildblock_simple_tests diff --git a/src/test/test_ScatterGradient.cxx b/src/test/test_ScatterGradient.cxx new file mode 100644 index 0000000000..64d59929a4 --- /dev/null +++ b/src/test/test_ScatterGradient.cxx @@ -0,0 +1,95 @@ +// +// +/* + Copyright (C) 2019, University of Hull + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + See STIR/LICENSE.txt for details +*/ +/*! + + \file + \ingroup test + + \brief Test program for ScatterGradient + + \author Ludovica Brusaferri + +*/ + +#include "stir/RunTests.h" +#include "stir/Scanner.h" +#include "stir/Viewgram.h" +#include "stir/Succeeded.h" +#include "stir/ProjDataInfoCylindricalNoArcCorr.h" +#include "stir/VoxelsOnCartesianGrid.h" +#include "stir/scatter/SingleScatterSimulation.h" +#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/recon_buildblock/ForwardProjectorByBin.h" +#include "stir/recon_buildblock/ForwardProjectorByBinUsingRayTracing.h" +#include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" +#include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" +#include "stir/recon_buildblock/BinNormalisationFromAttenuationImage.h" +#include "stir/Shape/EllipsoidalCylinder.h" +#include "stir/Shape/Box3D.h" +#include "stir/IO/write_to_file.h" +#include +#include +#include "stir/centre_of_gravity.h" + +using std::cerr; +using std::endl; +using std::string; + +START_NAMESPACE_STIR + +/*! + \ingroup test + \brief Test class for Scanner +*/ +class ScatterGradientTests: public RunTests +{ +public: + void run_tests(); +private: + void test_scatter_gradient(); + +}; + + + +void +ScatterGradientTests::test_scatter_gradient() +{ + //TODO +} + +void +ScatterGradientTests:: +run_tests() +{ + + test_scatter_gradient(); +} + + +END_NAMESPACE_STIR + + +int main() +{ + USING_NAMESPACE_STIR + + ScatterGradientTests tests; + tests.run_tests(); + return tests.main_return_value(); +} From d4c23653a13057a4e85f6d08be071fb4f0507529 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 31 Jul 2019 13:29:39 +0100 Subject: [PATCH 142/274] energy pair --- src/IO/interfile.cxx | 7 ++++--- src/listmode_buildblock/LmToProjData.cxx | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/IO/interfile.cxx b/src/IO/interfile.cxx index 82570a612c..800f3aa0a5 100644 --- a/src/IO/interfile.cxx +++ b/src/IO/interfile.cxx @@ -495,9 +495,10 @@ static void write_interfile_energy_windows(std::ostream& output_header, const Ex } } - //Write energy window pairs (only inf num_en win >1) - if (exam_info.get_num_energy_windows() > 1) - { output_header << "energy window pair :="<<" {"<< exam_info.get_energy_window_pair().first << + if (exam_info.get_energy_window_pair().first> 0 && + exam_info.get_energy_window_pair().second> 0) + { + output_header << "energy window pair :="<<" {"<< exam_info.get_energy_window_pair().first << ',' << exam_info.get_energy_window_pair().second <<"}\n"; } diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 20a697c6e5..92e76d8c94 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -654,7 +654,6 @@ process_data() // and there might be a scanner around that has them both combined. if (record.is_event()) { - std::cout<< "i'm here" << '\n'; assert(start_time <= current_time); Bin bin; // set value in case the event decoder doesn't touch it From ea1067755f04517361e0ea416bdaf4de35c6a17a Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 31 Jul 2019 19:40:00 +0100 Subject: [PATCH 143/274] root energy --- src/IO/InputStreamFromROOTFile.cxx | 5 +++-- src/IO/InputStreamFromROOTFileForCylindricalPET.cxx | 6 +++--- src/IO/InputStreamFromROOTFileForECATPET.cxx | 6 +++--- src/include/stir/IO/InputStreamFromROOTFile.h | 9 ++++++--- src/include/stir/IO/InputStreamFromROOTFile.inl | 7 +++++++ .../stir/IO/InputStreamFromROOTFileForCylindricalPET.h | 2 +- src/include/stir/IO/InputStreamFromROOTFileForECATPET.h | 2 +- src/include/stir/listmode/CListRecordROOT.h | 4 ++-- src/listmode_buildblock/CListModeDataROOT.cxx | 6 ++++-- 9 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/IO/InputStreamFromROOTFile.cxx b/src/IO/InputStreamFromROOTFile.cxx index 1790a5911d..5284f19327 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -69,8 +69,9 @@ InputStreamFromROOTFile::initialise_keymap() this->parser.add_key("exclude scattered events", &this->exclude_scattered); this->parser.add_key("exclude random events", &this->exclude_randoms); this->parser.add_key("offset (num of detectors)", &this->offset_dets); - this->parser.add_key("low energy window (keV)", &this->low_energy_window[0]); - this->parser.add_key("upper energy window (keV)", &this->up_energy_window[0]); + this->parser.add_key("number of energy windows", &this->num_en_windows); + this->parser.add_key("low energy window (MeV)", &this->low_energy_window); + this->parser.add_key("upper energy window (MeV)", &this->up_energy_window); this->parser.add_key("read optional ROOT fields", &this->read_optional_root_fields); } diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 1e5829216b..043355b736 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -38,7 +38,7 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, bool _exclude_scattered, bool _exclude_randoms, - float _low_energy_window, float _up_energy_window, + std::vector _low_energy_window, std::vector _up_energy_window, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), @@ -52,8 +52,8 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - low_energy_window[0] = _low_energy_window; - up_energy_window[0] = _up_energy_window; + low_energy_window = _low_energy_window; + up_energy_window = _up_energy_window; offset_dets = _offset_dets; half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index f4146be303..7a8cb5f3b2 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -37,7 +37,7 @@ InputStreamFromROOTFileForECATPET(std::string _filename, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int block_repeater, bool _exclude_scattered, bool _exclude_randoms, - float _low_energy_window, float _up_energy_window, + std::vector _low_energy_window, std::vector _up_energy_window, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), @@ -49,8 +49,8 @@ InputStreamFromROOTFileForECATPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - low_energy_window[0] = _low_energy_window; - up_energy_window[0] = _up_energy_window; + low_energy_window = _low_energy_window; + up_energy_window = _up_energy_window; offset_dets = _offset_dets; half_block = crystal_repeater_y / 2 - 1; diff --git a/src/include/stir/IO/InputStreamFromROOTFile.h b/src/include/stir/IO/InputStreamFromROOTFile.h index ccbe2dab86..83dc448469 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.h +++ b/src/include/stir/IO/InputStreamFromROOTFile.h @@ -136,7 +136,8 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile inline float get_low_energy_thres(int en_win = 0) const; //! Upper energy threshold inline float get_up_energy_thres(int en_win = 0) const; - + //! Upper number of energy windows + inline int get_number_of_energy_windows() const; //! Set singles_readout_depth inline void set_singles_readout_depth(int); @@ -197,9 +198,11 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! Skip random events (eventID1 != eventID2) bool exclude_randoms; //! Lower energy threshold - std::vector low_energy_window; + std::vector low_energy_window; //! Upper energy threshold - std::vector up_energy_window; + std::vector up_energy_window; + + int num_en_windows; //! This value will apply a rotation on the detectors' id in the same ring. int offset_dets; //!For the singles_readout_depth from GATE's online documentation: diff --git a/src/include/stir/IO/InputStreamFromROOTFile.inl b/src/include/stir/IO/InputStreamFromROOTFile.inl index 21b87b0c57..9cc1261eb6 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.inl +++ b/src/include/stir/IO/InputStreamFromROOTFile.inl @@ -79,6 +79,13 @@ set_saved_get_positions(const std::vector &poss) saved_get_positions = poss; } +int +InputStreamFromROOTFile:: +get_number_of_energy_windows() const +{ + return num_en_windows; +} + float InputStreamFromROOTFile:: get_low_energy_thres(int en_win) const diff --git a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h index b1263d2657..26d2f8a73e 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h @@ -101,7 +101,7 @@ class InputStreamFromROOTFileForCylindricalPET : public int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, bool exclude_scattered, bool exclude_randoms, - float low_energy_window, float up_energy_window, + std::vector low_energy_window, std::vector up_energy_window, int offset_dets); virtual ~InputStreamFromROOTFileForCylindricalPET() {} diff --git a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h index 235fe76da7..a319e821a2 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h @@ -94,7 +94,7 @@ class InputStreamFromROOTFileForECATPET : public int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int blocks_repeater, bool exclude_scattered, bool exclude_randoms, - float low_energy_window, float up_energy_window, + std::vector low_energy_window, std::vector up_energy_window, int offset_dets); virtual ~InputStreamFromROOTFileForECATPET() {} diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index dd72251add..e50cb252eb 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -148,11 +148,11 @@ class CListEnergyROOT : public CListEnergy //! Get the detection energy of the first photon //! in keV inline double get_energyA_in_keV() const - { return energyA * 1e3; } + { return energyA; } //! Get the detection energy of the second photon //! in keV inline double get_energyB_in_keV() const - { return energyB * 1e3; } + { return energyB; } private: diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index e089aabe10..a76635ee73 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -74,8 +74,10 @@ CListModeDataROOT(const std::string& hroot_filename) // Only PET scanners supported this->exam_info_sptr->imaging_modality = ImagingModality::PT; this->exam_info_sptr->originating_system = this->originating_system; - this->exam_info_sptr->set_low_energy_thres(this->root_file_sptr->get_low_energy_thres()); - this->exam_info_sptr->set_high_energy_thres(this->root_file_sptr->get_up_energy_thres()); + this->exam_info_sptr->set_num_energy_windows(this->root_file_sptr->get_number_of_energy_windows()); + this->exam_info_sptr->set_low_energy_thres(1e3*this->root_file_sptr->get_low_energy_thres()); + this->exam_info_sptr->set_high_energy_thres(1e3*this->root_file_sptr->get_up_energy_thres()); + shared_ptr this_scanner_sptr; From b108172cb2677a85ab7640add53a4580577f93e5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 31 Jul 2019 21:45:35 +0100 Subject: [PATCH 144/274] unlisting sino --- src/IO/InputStreamFromROOTFile.cxx | 19 +++++++----- ...putStreamFromROOTFileForCylindricalPET.cxx | 17 ++++++----- src/IO/InputStreamFromROOTFileForECATPET.cxx | 17 ++++++----- src/include/stir/ExamInfo.h | 6 +++- src/include/stir/ExamInfo.inl | 30 +++++++++++++++++++ src/include/stir/IO/InputStreamFromROOTFile.h | 20 ++++++++----- .../stir/IO/InputStreamFromROOTFile.inl | 30 ++++++++++++------- ...InputStreamFromROOTFileForCylindricalPET.h | 3 +- .../IO/InputStreamFromROOTFileForECATPET.h | 3 +- src/include/stir/listmode/CListRecordROOT.h | 4 +-- src/listmode_buildblock/CListModeDataROOT.cxx | 21 +++++++++++-- 11 files changed, 124 insertions(+), 46 deletions(-) diff --git a/src/IO/InputStreamFromROOTFile.cxx b/src/IO/InputStreamFromROOTFile.cxx index 5284f19327..660ee07208 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -36,11 +36,12 @@ InputStreamFromROOTFile:: InputStreamFromROOTFile(std::string filename, std::string chain_name, bool exclude_scattered, bool exclude_randoms, - float low_energy_window, float up_energy_window, + float low_energy_window_1, float up_energy_window_1, + float low_energy_window_2, float up_energy_window_2, int offset_dets) : filename(filename), chain_name(chain_name), exclude_scattered(exclude_scattered), exclude_randoms(exclude_randoms), - low_energy_window(low_energy_window), up_energy_window(up_energy_window), offset_dets(offset_dets) + low_energy_window_1(low_energy_window_1), up_energy_window_1(up_energy_window_1),low_energy_window_2(low_energy_window_2), up_energy_window_2(up_energy_window_2), offset_dets(offset_dets) { set_defaults(); reset(); @@ -53,10 +54,10 @@ InputStreamFromROOTFile::set_defaults() singles_readout_depth = -1; exclude_scattered = false; exclude_randoms = false; - low_energy_window.resize(1); - up_energy_window.resize(1); - low_energy_window[0] = 0.f; - up_energy_window[0] = 1000.f; + low_energy_window_1 = 0.f; + up_energy_window_1 = 1000.f; + low_energy_window_2 = 0.f; + up_energy_window_2 = 1000.f; read_optional_root_fields=false; } @@ -70,8 +71,10 @@ InputStreamFromROOTFile::initialise_keymap() this->parser.add_key("exclude random events", &this->exclude_randoms); this->parser.add_key("offset (num of detectors)", &this->offset_dets); this->parser.add_key("number of energy windows", &this->num_en_windows); - this->parser.add_key("low energy window (MeV)", &this->low_energy_window); - this->parser.add_key("upper energy window (MeV)", &this->up_energy_window); + this->parser.add_key("low energy window 1 (MeV)", &this->low_energy_window_1); + this->parser.add_key("upper energy window 1 (MeV)", &this->up_energy_window_1); + this->parser.add_key("low energy window 2 (MeV)", &this->low_energy_window_2); + this->parser.add_key("upper energy window 2 (MeV)", &this->up_energy_window_2); this->parser.add_key("read optional ROOT fields", &this->read_optional_root_fields); } diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 043355b736..4cc23b913b 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -38,7 +38,8 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, bool _exclude_scattered, bool _exclude_randoms, - std::vector _low_energy_window, std::vector _up_energy_window, + float _low_energy_window_1, float _up_energy_window_1, + float _low_energy_window_2, float _up_energy_window_2, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), @@ -52,8 +53,10 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - low_energy_window = _low_energy_window; - up_energy_window = _up_energy_window; + low_energy_window_1 = _low_energy_window_1; + up_energy_window_1 = _up_energy_window_1; + low_energy_window_2 = _low_energy_window_2; + up_energy_window_2 = _up_energy_window_2; offset_dets = _offset_dets; half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; @@ -81,10 +84,10 @@ get_next_record(CListRecordROOT& record) continue; if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) continue; - if (this->energy1 < this->low_energy_window[0] || - this->energy1 > this->up_energy_window[0] || - this->energy2 < this->low_energy_window[0] || - this->energy2 > this->up_energy_window[0]) + if (this->energy1 < this->low_energy_window_1 || + this->energy1 > this->up_energy_window_1 || + this->energy2 < this->low_energy_window_2 || + this->energy2 > this->up_energy_window_2) continue; break; diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 7a8cb5f3b2..32ec511e20 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -37,7 +37,8 @@ InputStreamFromROOTFileForECATPET(std::string _filename, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int block_repeater, bool _exclude_scattered, bool _exclude_randoms, - std::vector _low_energy_window, std::vector _up_energy_window, + float _low_energy_window_1, float _up_energy_window_1, + float _low_energy_window_2, float _up_energy_window_2, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), @@ -49,8 +50,10 @@ InputStreamFromROOTFileForECATPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - low_energy_window = _low_energy_window; - up_energy_window = _up_energy_window; + low_energy_window_1 = _low_energy_window_1; + up_energy_window_1 = _up_energy_window_1; + low_energy_window_2 = _low_energy_window_2; + up_energy_window_2 = _up_energy_window_2; offset_dets = _offset_dets; half_block = crystal_repeater_y / 2 - 1; @@ -77,10 +80,10 @@ get_next_record(CListRecordROOT& record) continue; if ( eventID1 != eventID2 && exclude_randoms ) continue; - if (energy1 < low_energy_window[0] || - energy1 > up_energy_window[0] || - energy2 < low_energy_window[0] || - energy2 > up_energy_window[0]) + if (energy1 < low_energy_window_1 || + energy1 > up_energy_window_1 || + energy2 < low_energy_window_2 || + energy2 > up_energy_window_2) continue; break; diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index f4b4bb5ecf..7fb4e11503 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -59,12 +59,14 @@ public : : start_time_in_secs_since_1970(0.) { - num_windows = 1; + num_windows = 2; low_energy_thres.resize(num_windows); up_energy_thres.resize(num_windows); en_win_pair.resize(2); low_energy_thres[0]=-1.F; up_energy_thres[0]=-1.F; + low_energy_thres[0]=1.F; + up_energy_thres[0]=1.F; en_win_pair[0]=-1.F; en_win_pair[1]=-1.F; @@ -108,6 +110,8 @@ public : //! Set the number of energy windows inline void set_num_energy_windows(int n_win); inline void set_energy_window_pair(std::vector val,int n_win); + inline void set_low_energy_thres_vect(std::vector new_val); + inline void set_high_energy_thres_vect(std::vector new_val); //@} //! Standard trick for a 'virtual copy-constructor' diff --git a/src/include/stir/ExamInfo.inl b/src/include/stir/ExamInfo.inl index f9f87daff9..f7d6eb3483 100644 --- a/src/include/stir/ExamInfo.inl +++ b/src/include/stir/ExamInfo.inl @@ -49,6 +49,36 @@ void ExamInfo::set_high_energy_thres(float new_val,int en_window) { up_energy_thres[en_window] = new_val; + +} + +void +ExamInfo::set_low_energy_thres_vect(std::vector new_val) +{ + low_energy_thres = new_val; + //TODO extend to the case of more than two + + //Decrescent ordering + if (new_val[0] new_val) +{ + up_energy_thres = new_val; + //TODO extend to the case of more than two + + //Decrescent ordering + if (new_val[0] get_low_energy_thres() const; //! Upper energy threshold - inline float get_up_energy_thres(int en_win = 0) const; + inline std::vector get_up_energy_thres() const; + //! Upper number of energy windows inline int get_number_of_energy_windows() const; //! Set singles_readout_depth @@ -151,9 +153,9 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile inline void set_detectors_offset(int); - inline void set_low_energy_window(float, int en_win = 0); + inline void set_low_energy_window(float); - inline void set_upper_energy_window(float, int en_win = 0); + inline void set_upper_energy_window(float); //! Set the read_optional_root_fields flag inline void set_optional_ROOT_fields(bool); @@ -198,9 +200,13 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! Skip random events (eventID1 != eventID2) bool exclude_randoms; //! Lower energy threshold - std::vector low_energy_window; + float low_energy_window_1; + //! Upper energy threshold + float up_energy_window_1; + //! Lower energy threshold + float low_energy_window_2; //! Upper energy threshold - std::vector up_energy_window; + float up_energy_window_2; int num_en_windows; //! This value will apply a rotation on the detectors' id in the same ring. diff --git a/src/include/stir/IO/InputStreamFromROOTFile.inl b/src/include/stir/IO/InputStreamFromROOTFile.inl index 9cc1261eb6..4db8fa894b 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.inl +++ b/src/include/stir/IO/InputStreamFromROOTFile.inl @@ -86,20 +86,30 @@ get_number_of_energy_windows() const return num_en_windows; } -float +std::vector InputStreamFromROOTFile:: -get_low_energy_thres(int en_win) const +get_low_energy_thres() const { - return low_energy_window[en_win]; + std::vector low_energy_window; + low_energy_window.resize(2); + low_energy_window[0]=1e3*low_energy_window_1; + low_energy_window[1]=1e3*low_energy_window_2; + return low_energy_window; } -float +std::vector InputStreamFromROOTFile:: -get_up_energy_thres(int en_win) const +get_up_energy_thres() const { - return up_energy_window[en_win]; + std::vector up_energy_window; + up_energy_window.resize(2); + up_energy_window[0]=1e3*up_energy_window_1; + up_energy_window[1]=1e3*up_energy_window_2; + return up_energy_window; } + + std::string InputStreamFromROOTFile:: get_ROOT_filename() const @@ -144,15 +154,15 @@ InputStreamFromROOTFile::set_detectors_offset(int val) } void -InputStreamFromROOTFile::set_low_energy_window(float val, int en_win) +InputStreamFromROOTFile::set_low_energy_window(float val) { - low_energy_window[en_win] = val; + low_energy_window_1= val; } void -InputStreamFromROOTFile::set_upper_energy_window(float val, int en_win) +InputStreamFromROOTFile::set_upper_energy_window(float val) { - up_energy_window[en_win] = val; + up_energy_window_1 = val; } void diff --git a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h index 26d2f8a73e..1a9650f777 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h @@ -101,7 +101,8 @@ class InputStreamFromROOTFileForCylindricalPET : public int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, bool exclude_scattered, bool exclude_randoms, - std::vector low_energy_window, std::vector up_energy_window, + float low_energy_window_1, float up_energy_window_1, + float low_energy_window_2, float up_energy_window_2, int offset_dets); virtual ~InputStreamFromROOTFileForCylindricalPET() {} diff --git a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h index a319e821a2..270bcaa842 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h @@ -94,7 +94,8 @@ class InputStreamFromROOTFileForECATPET : public int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int blocks_repeater, bool exclude_scattered, bool exclude_randoms, - std::vector low_energy_window, std::vector up_energy_window, + float low_energy_window_1, float up_energy_window_1, + float low_energy_window_2, float up_energy_window_2, int offset_dets); virtual ~InputStreamFromROOTFileForECATPET() {} diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index e50cb252eb..a7a5ba6737 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -241,10 +241,10 @@ class CListRecordROOT : public CListRecord // currently no gating yet time1,time2); - if(this->event_data.is_swapped()) + /* if(this->event_data.is_swapped()) this->energy_data.init_energy_from_data( energy2,energy1); - else + else*/ this->energy_data.init_energy_from_data( energy1,energy2); diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index a76635ee73..1e240c501e 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -75,8 +75,25 @@ CListModeDataROOT(const std::string& hroot_filename) this->exam_info_sptr->imaging_modality = ImagingModality::PT; this->exam_info_sptr->originating_system = this->originating_system; this->exam_info_sptr->set_num_energy_windows(this->root_file_sptr->get_number_of_energy_windows()); - this->exam_info_sptr->set_low_energy_thres(1e3*this->root_file_sptr->get_low_energy_thres()); - this->exam_info_sptr->set_high_energy_thres(1e3*this->root_file_sptr->get_up_energy_thres()); + +// /std::vector a; + // std::vector b; + + this->exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres()); + this->exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres()); + + std::vector val; + val.resize(2); + if(this->root_file_sptr->get_low_energy_thres()[0]>this->root_file_sptr->get_low_energy_thres()[1]) + {val[0]=1; + val[1]=2;} + else if(this->root_file_sptr->get_low_energy_thres()[1]>this->root_file_sptr->get_low_energy_thres()[0]) + {val[0]=2; + val[1]=1;} + else if(this->root_file_sptr->get_low_energy_thres()[1]==this->root_file_sptr->get_low_energy_thres()[0]) + {val[0]=1; + val[1]=1;} + this->exam_info_sptr->set_energy_window_pair(val,1); shared_ptr this_scanner_sptr; From 833ba26265cbb18e445ed7a6eff66262f4f45249 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 1 Aug 2019 12:51:58 +0100 Subject: [PATCH 145/274] unlist root --- src/include/stir/listmode/CListRecordROOT.h | 10 ++++++---- src/listmode_buildblock/LmToProjData.cxx | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index a7a5ba6737..12c3a19846 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -241,13 +241,15 @@ class CListRecordROOT : public CListRecord // currently no gating yet time1,time2); - /* if(this->event_data.is_swapped()) - this->energy_data.init_energy_from_data( - energy2,energy1); - else*/ + //if(this->event_data.is_swapped()) + //this->energy_data.init_energy_from_data( + // energy2,energy1); + //else this->energy_data.init_energy_from_data( energy1,energy2); + std::cout<< "energyA: " << energy1 << '\n'; + std::cout<< "energyB: " << energy2 << '\n'; // We can make a singature raw based on the two events IDs. // It is pretty unique. diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 92e76d8c94..823b9cd874 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -646,7 +646,7 @@ process_data() if(record.is_energy()) { - std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; + std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; std::cout<< "energyB: " << record.energy().get_energyB_in_keV() << '\n'; } // note: could do "else if" here if we would be sure that From 0109d44fa7bcae936097ca9cb94ebad5d0f8db75 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 2 Aug 2019 17:16:26 +0100 Subject: [PATCH 146/274] clist record --- ...putStreamFromROOTFileForCylindricalPET.cxx | 17 +++++++++-- src/IO/InputStreamFromROOTFileForECATPET.cxx | 19 ++++++++++--- src/IO/InterfileHeader.cxx | 3 ++ src/include/stir/ExamInfo.h | 5 ++++ src/include/stir/ExamInfo.inl | 19 +++++++++++++ src/include/stir/listmode/CListRecord.h | 3 ++ src/include/stir/listmode/CListRecordROOT.h | 11 +++----- src/listmode_buildblock/CListModeDataROOT.cxx | 4 +++ src/listmode_buildblock/LmToProjData.cxx | 28 ++++++++++++++++--- 9 files changed, 91 insertions(+), 18 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 4cc23b913b..22bf34eee8 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -84,11 +84,22 @@ get_next_record(CListRecordROOT& record) continue; if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) continue; - if (this->energy1 < this->low_energy_window_1 || - this->energy1 > this->up_energy_window_1 || - this->energy2 < this->low_energy_window_2 || + if((this->low_energy_window_1low_energy_window_2)) + { + if (this->energy1 < this->low_energy_window_1 || + this->energy1 > this->up_energy_window_2 || + this->energy2 < this->low_energy_window_1|| this->energy2 > this->up_energy_window_2) continue; + } + else + { + if (this->energy1 < this->low_energy_window_2 || + this->energy1 > this->up_energy_window_1 || + this->energy2 < this->low_energy_window_2|| + this->energy2 > this->up_energy_window_1) + continue; + } break; } diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 32ec511e20..f3065a1dd4 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -80,11 +80,22 @@ get_next_record(CListRecordROOT& record) continue; if ( eventID1 != eventID2 && exclude_randoms ) continue; - if (energy1 < low_energy_window_1 || - energy1 > up_energy_window_1 || - energy2 < low_energy_window_2 || - energy2 > up_energy_window_2) + if((this->low_energy_window_1low_energy_window_2)) + { + if (this->energy1 < this->low_energy_window_1 || + this->energy1 > this->up_energy_window_2 || + this->energy2 < this->low_energy_window_1|| + this->energy2 > this->up_energy_window_2) continue; + } + else + { + if (this->energy1 < this->low_energy_window_2 || + this->energy1 > this->up_energy_window_1 || + this->energy2 < this->low_energy_window_2|| + this->energy2 > this->up_energy_window_1) + continue; + } break; } diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index f4a4172182..1827d6697c 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -398,6 +398,9 @@ bool InterfileHeader::post_processing() exam_info_sptr->set_high_energy_thres(upper_en_window_thres[i],i); exam_info_sptr->set_low_energy_thres(lower_en_window_thres[i],i); + if (upper_en_window_thres[i] <=lower_en_window_thres[i]) + error("the upper energy threshold needs to be higher than the lower energy threshold"); + } } diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index 7fb4e11503..a9057dc0a6 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -95,6 +95,11 @@ public : inline float get_low_energy_thres(int en_window = 0) const; //! Get the high energy boundary inline float get_high_energy_thres(int en_window = 0) const; + + inline std::vector get_low_energy_thres_vect() const; + //! Get the high energy boundary + inline std::vector get_high_energy_thres_vect() const; + //! Get the number of energy windows inline int get_num_energy_windows() const; inline std::pair get_energy_window_pair() const; diff --git a/src/include/stir/ExamInfo.inl b/src/include/stir/ExamInfo.inl index f7d6eb3483..10092c35ce 100644 --- a/src/include/stir/ExamInfo.inl +++ b/src/include/stir/ExamInfo.inl @@ -121,6 +121,25 @@ ExamInfo::get_high_energy_thres(int en_window) const } + +std::vector +ExamInfo::get_low_energy_thres_vect() const +{ + return low_energy_thres; + +} + +//Get the high energy boundary for all the energy windows. en_window is set to 0 by default +//So that it will work also in the case of 1 energy window + +std::vector +ExamInfo::get_high_energy_thres_vect() const +{ + + return up_energy_thres; + +} + //Get the number of energy windows int ExamInfo::get_num_energy_windows() const diff --git a/src/include/stir/listmode/CListRecord.h b/src/include/stir/listmode/CListRecord.h index e9272f2579..400640ab09 100644 --- a/src/include/stir/listmode/CListRecord.h +++ b/src/include/stir/listmode/CListRecord.h @@ -65,6 +65,9 @@ class CListEvent bool is_prompt() const = 0; + bool is_swapped() const + { return false; } + //! Changes the event from prompt to delayed or vice versa /*! Default implementation just returns Succeeded::no. */ virtual diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index 12c3a19846..e0c3dfb592 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -241,16 +241,13 @@ class CListRecordROOT : public CListRecord // currently no gating yet time1,time2); - //if(this->event_data.is_swapped()) - //this->energy_data.init_energy_from_data( - // energy2,energy1); - //else + if(this->event_data.is_swapped()) + this->energy_data.init_energy_from_data( + energy2,energy1); + else this->energy_data.init_energy_from_data( energy1,energy2); - std::cout<< "energyA: " << energy1 << '\n'; - std::cout<< "energyB: " << energy2 << '\n'; - // We can make a singature raw based on the two events IDs. // It is pretty unique. raw[0] = event1; diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 1e240c501e..ccda26d303 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -82,6 +82,10 @@ CListModeDataROOT(const std::string& hroot_filename) this->exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres()); this->exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres()); + for(int i =0; iexam_info_sptr->get_num_energy_windows(); ++i) + if (this->exam_info_sptr->get_high_energy_thres(i)<=this->exam_info_sptr->get_low_energy_thres(i)) + error("the upper energy threshold needs to be higher than the lower energy threshold"); + std::vector val; val.resize(2); if(this->root_file_sptr->get_low_energy_thres()[0]>this->root_file_sptr->get_low_energy_thres()[1]) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 823b9cd874..f8428913a6 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -644,11 +644,29 @@ process_data() process_new_time_event(record.time()); } + int en_win_A = this_frame_exam_info.get_energy_window_pair().first-1; + int en_win_B = this_frame_exam_info.get_energy_window_pair().second-1; + std::vector low_en_thres = this_frame_exam_info.get_low_energy_thres_vect(); + std::vector up_en_thres = this_frame_exam_info.get_high_energy_thres_vect(); + if(record.is_energy()) { - std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; - std::cout<< "energyB: " << record.energy().get_energyB_in_keV() << '\n'; - } + + + int en_win_A = this_frame_exam_info.get_energy_window_pair().first-1; + int en_win_B = this_frame_exam_info.get_energy_window_pair().second-1; + std::vector low_en_thres = this_frame_exam_info.get_low_energy_thres_vect(); + std::vector up_en_thres = this_frame_exam_info.get_high_energy_thres_vect(); + if((record.energy().get_energyA_in_keV()) > 1e-3*low_en_thres[en_win_A]&&(record.energy().get_energyA_in_keV()) < 1e-3*up_en_thres[en_win_A]) + // std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; + if((record.energy().get_energyB_in_keV()) > 1e-3*low_en_thres[en_win_B]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_B]) + // std::cout<< "energyB: " << record.energy().get_energyB_in_keV() << '\n'; + if(record.event().is_swapped()==true) + std::cout<< 1<< '\n'; + else std::cout<< 0 << '\n'; + + + } // note: could do "else if" here if we would be sure that // a record can never be both timing and coincidence event // and there might be a scanner around that has them both combined. @@ -669,6 +687,7 @@ process_data() && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) ) { + assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); assert(bin.view_num()<=proj_data_ptr->get_max_view_num()); @@ -705,8 +724,9 @@ process_data() (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += bin.get_bin_value() * event_increment; - } + } + } else // event is rejected for some reason { if (interactive) From 8a9cd4de0f1f9a9dddaa2002588c6851cd6a20e7 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 2 Aug 2019 18:21:11 +0100 Subject: [PATCH 147/274] pu --- src/include/stir/listmode/CListRecord.h | 4 +-- .../stir/listmode/CListRecordECAT8_32bit.h | 1 + .../stir/listmode/CListRecordECAT962.h | 1 + .../stir/listmode/CListRecordECAT966.h | 1 + src/include/stir/listmode/CListRecordSAFIR.h | 1 + src/listmode_buildblock/LmToProjData.cxx | 28 +++++++------------ 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/include/stir/listmode/CListRecord.h b/src/include/stir/listmode/CListRecord.h index 400640ab09..da596fc48d 100644 --- a/src/include/stir/listmode/CListRecord.h +++ b/src/include/stir/listmode/CListRecord.h @@ -65,8 +65,8 @@ class CListEvent bool is_prompt() const = 0; - bool is_swapped() const - { return false; } + virtual bool is_swapped() const = 0; + //! Changes the event from prompt to delayed or vice versa /*! Default implementation just returns Succeeded::no. */ diff --git a/src/include/stir/listmode/CListRecordECAT8_32bit.h b/src/include/stir/listmode/CListRecordECAT8_32bit.h index f452f92a71..ad2fc37ec7 100644 --- a/src/include/stir/listmode/CListRecordECAT8_32bit.h +++ b/src/include/stir/listmode/CListRecordECAT8_32bit.h @@ -100,6 +100,7 @@ class CListEventECAT8_32bit : public CListEventCylindricalScannerWithDiscreteDet return Succeeded::yes; } inline bool is_prompt() const { return this->data.delayed == 1; } + inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } inline Succeeded set_prompt(const bool prompt = true) { if (prompt) this->data.delayed=1; else this->data.delayed=0; return Succeeded::yes; } diff --git a/src/include/stir/listmode/CListRecordECAT962.h b/src/include/stir/listmode/CListRecordECAT962.h index ee9c9a45ea..098485792f 100644 --- a/src/include/stir/listmode/CListRecordECAT962.h +++ b/src/include/stir/listmode/CListRecordECAT962.h @@ -64,6 +64,7 @@ class CListEventDataECAT962 { public: inline bool is_prompt() const { return random == 0; } + inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } inline Succeeded set_prompt(const bool prompt = true) { if (prompt) random=0; else random=1; return Succeeded::yes; } diff --git a/src/include/stir/listmode/CListRecordECAT966.h b/src/include/stir/listmode/CListRecordECAT966.h index 723a230ff4..02c88ecf54 100644 --- a/src/include/stir/listmode/CListRecordECAT966.h +++ b/src/include/stir/listmode/CListRecordECAT966.h @@ -128,6 +128,7 @@ class CListEventECAT966 : public CListEventCylindricalScannerWithViewTangRingRin return Succeeded::yes; } inline bool is_prompt() const { return this->data.random == 0; } + inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } inline Succeeded set_prompt(const bool prompt = true) { if (prompt) this->data.random=0; else this->data.random=1; return Succeeded::yes; } diff --git a/src/include/stir/listmode/CListRecordSAFIR.h b/src/include/stir/listmode/CListRecordSAFIR.h index e0e1b5e30e..6c86debdd3 100644 --- a/src/include/stir/listmode/CListRecordSAFIR.h +++ b/src/include/stir/listmode/CListRecordSAFIR.h @@ -81,6 +81,7 @@ class CListEventSAFIR : public CListEvent //! Returns 0 if event is prompt and 1 if random/delayed inline bool is_prompt() const { return !(static_cast(this)->is_prompt()); } + inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } //! Function to set map for detector indices to coordinates. inline void set_map( shared_ptr new_map ) { map = new_map; } diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index f8428913a6..d39c3e277b 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -649,29 +649,21 @@ process_data() std::vector low_en_thres = this_frame_exam_info.get_low_energy_thres_vect(); std::vector up_en_thres = this_frame_exam_info.get_high_energy_thres_vect(); - if(record.is_energy()) - { - - - int en_win_A = this_frame_exam_info.get_energy_window_pair().first-1; - int en_win_B = this_frame_exam_info.get_energy_window_pair().second-1; - std::vector low_en_thres = this_frame_exam_info.get_low_energy_thres_vect(); - std::vector up_en_thres = this_frame_exam_info.get_high_energy_thres_vect(); - if((record.energy().get_energyA_in_keV()) > 1e-3*low_en_thres[en_win_A]&&(record.energy().get_energyA_in_keV()) < 1e-3*up_en_thres[en_win_A]) - // std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; - if((record.energy().get_energyB_in_keV()) > 1e-3*low_en_thres[en_win_B]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_B]) - // std::cout<< "energyB: " << record.energy().get_energyB_in_keV() << '\n'; - if(record.event().is_swapped()==true) - std::cout<< 1<< '\n'; - else std::cout<< 0 << '\n'; - - - } // note: could do "else if" here if we would be sure that // a record can never be both timing and coincidence event // and there might be a scanner around that has them both combined. if (record.is_event()) { + if(record.event().is_swapped()) + { + + + if((record.energy().get_energyA_in_keV()) > 1e-3*low_en_thres[en_win_A]&&(record.energy().get_energyA_in_keV()) < 1e-3*up_en_thres[en_win_A]) + std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; + if((record.energy().get_energyB_in_keV()) > 1e-3*low_en_thres[en_win_B]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_B]) + std::cout<< "energyB: " << record.energy().get_energyB_in_keV() << '\n'; + } + assert(start_time <= current_time); Bin bin; // set value in case the event decoder doesn't touch it From 4f6418c0de810982b3d21feb58d688c0463e7f83 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 2 Aug 2019 18:49:02 +0100 Subject: [PATCH 148/274] ok --- src/listmode_buildblock/LmToProjData.cxx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index d39c3e277b..0cacacd9c1 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -654,16 +654,23 @@ process_data() // and there might be a scanner around that has them both combined. if (record.is_event()) { - if(record.event().is_swapped()) + if((record.event().is_swapped()==false)) { - - - if((record.energy().get_energyA_in_keV()) > 1e-3*low_en_thres[en_win_A]&&(record.energy().get_energyA_in_keV()) < 1e-3*up_en_thres[en_win_A]) - std::cout<< "energyA: " << record.energy().get_energyA_in_keV() << '\n'; + if((record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < 1e-3*up_en_thres[en_win_A])) + std::cout<< "energy 200: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; if((record.energy().get_energyB_in_keV()) > 1e-3*low_en_thres[en_win_B]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_B]) - std::cout<< "energyB: " << record.energy().get_energyB_in_keV() << '\n'; + std::cout<< "energy 300: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; + } + if(record.event().is_swapped()==true) + { + if((record.energy().get_energyA_in_keV()) > 1e-3*low_en_thres[en_win_B]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_B]) + std::cout<< "energy 300: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; + if((record.energy().get_energyB_in_keV()) > 1e-3*low_en_thres[en_win_A]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_A]) + std::cout<< "energy 200: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; } + + assert(start_time <= current_time); Bin bin; // set value in case the event decoder doesn't touch it From 7473d8ff8b236a2a4b1565b16087a419cf63459d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 2 Aug 2019 18:55:36 +0100 Subject: [PATCH 149/274] okk --- src/listmode_buildblock/LmToProjData.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 0cacacd9c1..f4bc008914 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -658,14 +658,14 @@ process_data() { if((record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < 1e-3*up_en_thres[en_win_A])) std::cout<< "energy 200: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; - if((record.energy().get_energyB_in_keV()) > 1e-3*low_en_thres[en_win_B]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_B]) + if((record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) std::cout<< "energy 300: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; } if(record.event().is_swapped()==true) { - if((record.energy().get_energyA_in_keV()) > 1e-3*low_en_thres[en_win_B]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_B]) + if((record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) std::cout<< "energy 300: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; - if((record.energy().get_energyB_in_keV()) > 1e-3*low_en_thres[en_win_A]&&(record.energy().get_energyB_in_keV()) < 1e-3*up_en_thres[en_win_A]) + if((record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_A])) std::cout<< "energy 200: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; } From 25a063370b8d00a3b761cb46fdcba1f551c4bd55 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 2 Aug 2019 23:42:14 +0100 Subject: [PATCH 150/274] correct --- src/listmode_buildblock/LmToProjData.cxx | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index f4bc008914..0486b9a879 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -654,23 +654,20 @@ process_data() // and there might be a scanner around that has them both combined. if (record.is_event()) { - if((record.event().is_swapped()==false)) - { - if((record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < 1e-3*up_en_thres[en_win_A])) - std::cout<< "energy 200: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; - if((record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) - std::cout<< "energy 300: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; + if((record.is_energy())&&(record.event().is_swapped()==false) + &&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < 1e-3*up_en_thres[en_win_A]) + &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) + { std::cout<< "energy 300: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; + std::cout<< "energy 200: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; } - if(record.event().is_swapped()==true) - { - if((record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) - std::cout<< "energy 300: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; - if((record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_A])) - std::cout<< "energy 200: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; + if((record.is_energy())&&(record.event().is_swapped()==true)&&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_B]) + &&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B]) + &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_A])) + { std::cout<< "energy 200: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; + std::cout<< "energy 300: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; } - assert(start_time <= current_time); Bin bin; // set value in case the event decoder doesn't touch it From 0d294cca955264a28ffa17df797673aafb59011c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 3 Aug 2019 00:10:24 +0100 Subject: [PATCH 151/274] status --- src/listmode_buildblock/LmToProjData.cxx | 103 ++++++++++++----------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 0486b9a879..95402dbdf9 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -654,19 +654,6 @@ process_data() // and there might be a scanner around that has them both combined. if (record.is_event()) { - if((record.is_energy())&&(record.event().is_swapped()==false) - &&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < 1e-3*up_en_thres[en_win_A]) - &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) - { std::cout<< "energy 300: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; - std::cout<< "energy 200: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; - } - if((record.is_energy())&&(record.event().is_swapped()==true)&&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_B]) - &&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B]) - &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_A])) - { std::cout<< "energy 200: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; - std::cout<< "energy 300: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; - } - assert(start_time <= current_time); Bin bin; @@ -682,47 +669,61 @@ process_data() && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) ) - { - assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); - assert(bin.view_num()<=proj_data_ptr->get_max_view_num()); - - // see if we increment or decrement the value in the sinogram - const int event_increment = - record.event().is_prompt() - ? ( store_prompts ? 1 : 0 ) // it's a prompt - : delayed_increment;//it is a delayed-coincidence event - - if (event_increment==0) - continue; - - if (!do_time_frame) - more_events-= event_increment; + { + if(((record.is_energy())&&(record.event().is_swapped()==false) + &&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < 1e-3*up_en_thres[en_win_A]) + &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) + ||((record.is_energy())&&(record.event().is_swapped()==true) + &&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B]) + &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_A]))) + + { + // std::cout<< "energy A: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; + // std::cout<< "energy B: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; + + assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); + assert(bin.view_num()<=proj_data_ptr->get_max_view_num()); - // now check if we have its segment in memory - if (bin.segment_num() >= start_segment_index && bin.segment_num()<=end_segment_index) - { - do_post_normalisation(bin); - - num_stored_events += event_increment; - if (record.event().is_prompt()) - ++num_prompts_in_frame; - else - ++num_delayeds_in_frame; - - if (num_stored_events%500000L==0) cout << "\r" << num_stored_events << " events stored" << flush; - - if (interactive) - printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g stored with incr %d \n", - bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), - current_time, event_increment); - else - (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += - bin.get_bin_value() * - event_increment; - - } + // see if we increment or decrement the value in the sinogram + const int event_increment = + record.event().is_prompt() + ? ( store_prompts ? 1 : 0 ) // it's a prompt + : delayed_increment;//it is a delayed-coincidence event + + if (event_increment==0) + continue; + + if (!do_time_frame) + more_events-= event_increment; + + // now check if we have its segment in memory + if (bin.segment_num() >= start_segment_index && bin.segment_num()<=end_segment_index) + { + do_post_normalisation(bin); + + num_stored_events += event_increment; + if (record.event().is_prompt()) + ++num_prompts_in_frame; + else + ++num_delayeds_in_frame; + + if (num_stored_events%500000L==0) cout << "\r" << num_stored_events << " events stored" << flush; + + if (interactive) + printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g stored with incr %d \n", + bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), + current_time, event_increment); + else + (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += + bin.get_bin_value() * + event_increment; + + } + } + + } else // event is rejected for some reason { if (interactive) From 4920e93eec085314d10bc1ea093a1c697c976027 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 5 Aug 2019 12:07:14 +0100 Subject: [PATCH 152/274] cleaned c++ --- src/IO/InterfileHeader.cxx | 4 - src/include/stir/scatter/ScatterSimulation.h | 2 +- .../SingleScatterLikelihoodAndGradient.h | 11 - .../SingleScatterLikelihoodAndGradient.cxx | 326 ------------------ 4 files changed, 1 insertion(+), 342 deletions(-) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index 1827d6697c..3d10d1365c 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -397,10 +397,6 @@ bool InterfileHeader::post_processing() { exam_info_sptr->set_high_energy_thres(upper_en_window_thres[i],i); exam_info_sptr->set_low_energy_thres(lower_en_window_thres[i],i); - - if (upper_en_window_thres[i] <=lower_en_window_thres[i]) - error("the upper energy threshold needs to be higher than the lower energy threshold"); - } } diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 6257d44ae5..635f391964 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,6 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} + float detection_efficiency(const float energy, int en_window = 0) const; Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); @@ -262,7 +263,6 @@ Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); * @{ */ - float detection_efficiency(const float energy, int en_window = 0) const; //! maximum angle to consider above which detection after Compton scatter is considered too small diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 874fa02125..a5243b33c7 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -65,11 +65,6 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); - ProjDataInMemory - likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata, const ProjData &est_data, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); - - ProjDataInMemory - likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); protected: void @@ -110,12 +105,6 @@ class SingleScatterLikelihoodAndGradient : public void L_G_for_viewgram_from_est_data(const Viewgram& viewgram,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - void - get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); - void - low_res_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); - void low_res_jacobian_for_viewgram(Viewgram& v_est,std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); - void get_ratio(const ProjData& projdata,const ProjData &add_projdata, ProjData &est_projdata, std::vector &ratio_vector); }; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 2ab14de69e..669554a483 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -761,331 +761,5 @@ L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesia } -ProjDataInMemory -SingleScatterLikelihoodAndGradient:: -likelihood_and_gradient_scatter_from_est_data(const ProjData &projdata,const ProjData &est_data, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) -{ - - - gradient_image_LR.fill(0); - gradient_image_HR.fill(0); - - // est_LR.fill(*(this->output_proj_data_sptr)); - - ProjDataInMemory ratio_HR(projdata); - ProjDataInMemory est_projdata_HR(projdata); - ProjDataInMemory ratio_LR(est_data); - - if((this->output_proj_data_sptr->get_num_views()!=projdata.get_num_views())||(this->output_proj_data_sptr->get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_data,true); - else - est_projdata_HR.fill(est_data); - - Bin bin; - { - for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) - for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) - { - Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); - - for (bin.view_num()=sino.get_min_view_num(); - bin.view_num()<=sino.get_max_view_num(); - ++bin.view_num()) - { - for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; - ratio_HR.set_sinogram(ratio_sino); - } - - } - } - - if((this->output_proj_data_sptr->get_num_views()!=projdata.get_num_views())||(this->output_proj_data_sptr->get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::push_scatter_estimate(ratio_LR,est_data,ratio_HR,true); - else - ratio_LR.fill(ratio_HR); - - L_G_function_from_est_data(ratio_LR,gradient_image_LR,compute_gradient, isgradient_mu,1); - - this->HR_output_proj_data_sptr.reset(new ProjDataInMemory(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()->create_shared_clone())); - this->HR_output_proj_data_sptr->fill(est_projdata_HR); - - if((gradient_image_HR.get_x_size()!=gradient_image_LR.get_x_size())||(gradient_image_HR.get_y_size()!=gradient_image_LR.get_y_size())||(gradient_image_HR.get_z_size()!=gradient_image_LR.get_z_size())) - { - if(isgradient_mu==true) - transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_values); - else - transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_projections); - - } - - ProjDataInMemory est_data_HR = *(this->HR_output_proj_data_sptr); - return est_data_HR; - -} - -ProjDataInMemory -SingleScatterLikelihoodAndGradient:: -likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) -{ - gradient_image_LR.fill(0); - gradient_image_HR.fill(0); - int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only - std::vector > jacobian_array; - std::vector ratio; - jacobian_array.reserve(lenght); - ratio.reserve(lenght); - for (int i = 0 ; i <= lenght ; ++i) - { - jacobian_array.push_back(gradient_image_LR); - ratio.push_back(0); - } - - get_jacobian(jacobian_array, compute_gradient, isgradient_mu); - - get_ratio(projdata,add_projdata,*(this->output_proj_data_sptr),ratio); - - for (int i = 0 ; i <= lenght ; ++i) - { - gradient_image_LR += jacobian_array[i]*ratio[i]; - } - - if((gradient_image_HR.get_x_size()!=gradient_image_LR.get_x_size())||(gradient_image_HR.get_y_size()!=gradient_image_LR.get_y_size())||(gradient_image_HR.get_z_size()!=gradient_image_LR.get_z_size())) - { - if(isgradient_mu==true) - transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_values); - else - transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_projections); - - } - - ProjDataInMemory est_data_HR = *(this->HR_output_proj_data_sptr); - return est_data_HR; - -} - -void -SingleScatterLikelihoodAndGradient:: -get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) -{ - - this->output_proj_data_sptr->fill(0.f); - - this->remove_cache_for_integrals_over_activity(); - this->remove_cache_for_integrals_over_attenuation(); - this->sample_scatter_points(); - this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - - ViewSegmentNumbers vs_num; - - int bin_counter = 0; - int axial_bins = 0 ; - double sum = 0; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns - coordinate in a coordinate system where z=0 in the first ring of the scanner. - We want to shift this to a coordinate system where z=0 in the middle - of the scanner. - We can use get_m() as that uses the 'middle of the scanner' system. - (sorry) - */ -#ifndef NDEBUG - { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( - detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - assert(detector_coord_A.z() == 0); - assert(detector_coord_B.z() == 0); - // check that get_m refers to the middle of the scanner - const float m_first = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); - assert(fabs(m_last + m_first) < m_last * 10E-4); - } -#endif - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - - info("ScatterSimulator: Initialization finished ..."); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); - ++vs_num.view_num()) - { - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - - this->low_res_jacobian_for_view_segment_number(gradient_image_array,vs_num,compute_gradient,isgradient_mu); - - bin_counter += - this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - std::cout<< bin_counter << " / "<< total_bins < > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) -{ - - Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); - - low_res_jacobian_for_viewgram(v_est,gradient_image_array, compute_gradient,isgradient_mu); - output_proj_data_sptr->set_viewgram(v_est); - -} - -void -SingleScatterLikelihoodAndGradient:: -low_res_jacobian_for_viewgram(Viewgram& v_est,std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) -{ - - const ViewSegmentNumbers vs_num(v_est.get_view_num(),v_est.get_segment_num()); - - // First construct a vector of all bins that we'll process. - // The reason for making this list before the actual calculation is that we can then parallelise over all bins - // without having to think about double loops. - std::vector all_bins; - { - Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); - - for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); - bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - { - all_bins.push_back(bin); - } - } - } - // now compute scatter for all bins - - - VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); - - for (int i = 0; i < static_cast(all_bins.size()); ++i) - { - //creates a template image to fill - tmp_gradient_image.fill(0); - - const Bin bin = all_bins[i]; - - //forward model - const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); - - v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); - gradient_image_array[i] += tmp_gradient_image; - } - -} - -void -SingleScatterLikelihoodAndGradient:: -get_ratio(const ProjData& projdata,const ProjData &add_projdata, ProjData &est_projdata, std::vector &ratio_vector) -{ - - ProjDataInMemory ratio_HR(projdata); - ProjDataInMemory est_projdata_HR(projdata); - ProjDataInMemory ratio_LR(est_projdata); - - if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,true); - else - est_projdata_HR.fill(est_projdata); - - Bin bin; - { - for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) - for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) - { - Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); - - for (bin.view_num()=sino.get_min_view_num(); - bin.view_num()<=sino.get_max_view_num(); - ++bin.view_num()) - { - for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; - ratio_HR.set_sinogram(ratio_sino); - } - - } - } - - if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::push_scatter_estimate(ratio_LR,est_projdata,ratio_HR,true); - else - ratio_LR.fill(ratio_HR); - - ViewSegmentNumbers vs_num; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num();vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); ++vs_num.view_num()) - { - - Viewgram viewgram = ratio_LR.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - - const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); - std::vector all_bins; - { - Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); - for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - { - all_bins.push_back(bin); - } - } - } - - for (int i = 0; i < static_cast(all_bins.size()); ++i) - { - - const Bin bin = all_bins[i]; - - ratio_vector[i] = viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; - } - - } - } - - this->HR_output_proj_data_sptr.reset(new ProjDataInMemory(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()->create_shared_clone())); - this->HR_output_proj_data_sptr->fill(est_projdata_HR); - -} - - - END_NAMESPACE_STIR From ceafe3e8c9d114afbc80fe3d164dfeeada288e15 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 5 Aug 2019 16:32:01 +0100 Subject: [PATCH 153/274] maximum order scatter --- src/IO/InputStreamFromROOTFile.cxx | 5 ++++- src/IO/InputStreamFromROOTFileForCylindricalPET.cxx | 5 +++-- src/IO/InputStreamFromROOTFileForECATPET.cxx | 5 +++-- src/include/stir/IO/InputStreamFromROOTFile.h | 10 +++++++--- src/include/stir/IO/InputStreamFromROOTFile.inl | 11 +++++++++-- .../IO/InputStreamFromROOTFileForCylindricalPET.h | 2 +- .../stir/IO/InputStreamFromROOTFileForECATPET.h | 2 +- src/include/stir/listmode/CListRecordROOT.h | 4 ++-- src/listmode_buildblock/CListModeDataROOT.cxx | 13 +++++-------- src/listmode_buildblock/LmToProjData.cxx | 12 ++++++------ 10 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/IO/InputStreamFromROOTFile.cxx b/src/IO/InputStreamFromROOTFile.cxx index 660ee07208..24ee9f55da 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -36,11 +36,12 @@ InputStreamFromROOTFile:: InputStreamFromROOTFile(std::string filename, std::string chain_name, bool exclude_scattered, bool exclude_randoms, + int maximum_order_of_scatter, float low_energy_window_1, float up_energy_window_1, float low_energy_window_2, float up_energy_window_2, int offset_dets) : filename(filename), chain_name(chain_name), - exclude_scattered(exclude_scattered), exclude_randoms(exclude_randoms), + exclude_scattered(exclude_scattered), exclude_randoms(exclude_randoms), maximum_order_of_scatter(maximum_order_of_scatter), low_energy_window_1(low_energy_window_1), up_energy_window_1(up_energy_window_1),low_energy_window_2(low_energy_window_2), up_energy_window_2(up_energy_window_2), offset_dets(offset_dets) { set_defaults(); @@ -53,6 +54,7 @@ InputStreamFromROOTFile::set_defaults() starting_stream_position = 0; singles_readout_depth = -1; exclude_scattered = false; + maximum_order_of_scatter = 0; exclude_randoms = false; low_energy_window_1 = 0.f; up_energy_window_1 = 1000.f; @@ -68,6 +70,7 @@ InputStreamFromROOTFile::initialise_keymap() this->parser.add_key("Singles readout depth", &this->singles_readout_depth); this->parser.add_key("name of input TChain", &this->chain_name); this->parser.add_key("exclude scattered events", &this->exclude_scattered); + this->parser.add_key("maximum order of scatter", &this->maximum_order_of_scatter); this->parser.add_key("exclude random events", &this->exclude_randoms); this->parser.add_key("offset (num of detectors)", &this->offset_dets); this->parser.add_key("number of energy windows", &this->num_en_windows); diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 22bf34eee8..3b86067cb2 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -37,7 +37,7 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, int submodule_repeater_x, int submodule_repeater_y, int submodule_repeater_z, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, - bool _exclude_scattered, bool _exclude_randoms, + bool _exclude_scattered, bool _exclude_randoms, int _maximum_order_of_scatter, float _low_energy_window_1, float _up_energy_window_1, float _low_energy_window_2, float _up_energy_window_2, int _offset_dets): @@ -53,6 +53,7 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; + maximum_order_of_scatter = _maximum_order_of_scatter; low_energy_window_1 = _low_energy_window_1; up_energy_window_1 = _up_energy_window_1; low_energy_window_2 = _low_energy_window_2; @@ -80,7 +81,7 @@ get_next_record(CListRecordROOT& record) current_position ++ ; - if ( (this->comptonphantom1 > 0 || this->comptonphantom2 > 0) && this->exclude_scattered ) + if ( (this->comptonphantom1 > maximum_order_of_scatter || this->comptonphantom2 >this->maximum_order_of_scatter) && this->exclude_scattered ) continue; if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) continue; diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index f3065a1dd4..e2ca49ef7d 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -36,7 +36,7 @@ InputStreamFromROOTFileForECATPET(std::string _filename, std::string _chain_name, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int block_repeater, - bool _exclude_scattered, bool _exclude_randoms, + bool _exclude_scattered, bool _exclude_randoms, int _maximum_order_of_scatter, float _low_energy_window_1, float _up_energy_window_1, float _low_energy_window_2, float _up_energy_window_2, int _offset_dets): @@ -50,6 +50,7 @@ InputStreamFromROOTFileForECATPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; + maximum_order_of_scatter = _maximum_order_of_scatter; low_energy_window_1 = _low_energy_window_1; up_energy_window_1 = _up_energy_window_1; low_energy_window_2 = _low_energy_window_2; @@ -76,7 +77,7 @@ get_next_record(CListRecordROOT& record) current_position ++ ; - if ( (comptonphantom1 > 0 || comptonphantom2 > 0) && exclude_scattered ) + if ( (comptonphantom1 > maximum_order_of_scatter || comptonphantom2 > maximum_order_of_scatter) && exclude_scattered ) continue; if ( eventID1 != eventID2 && exclude_randoms ) continue; diff --git a/src/include/stir/IO/InputStreamFromROOTFile.h b/src/include/stir/IO/InputStreamFromROOTFile.h index 091b86f9d7..7123aa6f64 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.h +++ b/src/include/stir/IO/InputStreamFromROOTFile.h @@ -83,7 +83,7 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! constructor InputStreamFromROOTFile(std::string filename, std::string chain_name, - bool exclude_scattered, bool exclude_randoms, + bool exclude_scattered, bool exclude_randoms,int maximum_order_of_scatter, float low_energy_window_1, float up_energy_window_1, float low_energy_window_2, float up_energy_window_2, int offset_dets); @@ -134,9 +134,9 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile virtual int get_num_trans_crystals_per_singles_unit() const = 0; //! Lower energy threshold - inline std::vector get_low_energy_thres() const; + inline std::vector get_low_energy_thres_in_keV() const; //! Upper energy threshold - inline std::vector get_up_energy_thres() const; + inline std::vector get_up_energy_thres_in_keV() const; //! Upper number of energy windows inline int get_number_of_energy_windows() const; @@ -151,6 +151,8 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile inline void set_exclude_random_events(bool); + inline void set_maximum_order_of_scatter(int); + inline void set_detectors_offset(int); inline void set_low_energy_window(float); @@ -197,6 +199,8 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! Skip scattered events (comptonphantom1 > 0 && comptonphantom2 > 0) bool exclude_scattered; + //! Scatter order to skip; + bool maximum_order_of_scatter; //! Skip random events (eventID1 != eventID2) bool exclude_randoms; //! Lower energy threshold diff --git a/src/include/stir/IO/InputStreamFromROOTFile.inl b/src/include/stir/IO/InputStreamFromROOTFile.inl index 4db8fa894b..b63cdfc498 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.inl +++ b/src/include/stir/IO/InputStreamFromROOTFile.inl @@ -88,7 +88,7 @@ get_number_of_energy_windows() const std::vector InputStreamFromROOTFile:: -get_low_energy_thres() const +get_low_energy_thres_in_keV() const { std::vector low_energy_window; low_energy_window.resize(2); @@ -99,7 +99,7 @@ get_low_energy_thres() const std::vector InputStreamFromROOTFile:: -get_up_energy_thres() const +get_up_energy_thres_in_keV() const { std::vector up_energy_window; up_energy_window.resize(2); @@ -141,6 +141,13 @@ InputStreamFromROOTFile::set_exclude_scattered_events(bool val) exclude_scattered = val; } +void +InputStreamFromROOTFile::set_maximum_order_of_scatter(int val) +{ + maximum_order_of_scatter= val; +} + + void InputStreamFromROOTFile::set_exclude_random_events(bool val) { diff --git a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h index 1a9650f777..b559e0cefd 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h @@ -100,7 +100,7 @@ class InputStreamFromROOTFileForCylindricalPET : public int submodule_repeater_x, int submodule_repeater_y, int submodule_repeater_z, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, - bool exclude_scattered, bool exclude_randoms, + bool exclude_scattered, bool exclude_randoms, int maximum_order_of_scatter, float low_energy_window_1, float up_energy_window_1, float low_energy_window_2, float up_energy_window_2, int offset_dets); diff --git a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h index 270bcaa842..a40b84e473 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h @@ -93,7 +93,7 @@ class InputStreamFromROOTFileForECATPET : public std::string chain_name, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int blocks_repeater, - bool exclude_scattered, bool exclude_randoms, + bool exclude_scattered, bool exclude_randoms,int maximum_order_of_scatter, float low_energy_window_1, float up_energy_window_1, float low_energy_window_2, float up_energy_window_2, int offset_dets); diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index e0c3dfb592..b391344117 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -148,11 +148,11 @@ class CListEnergyROOT : public CListEnergy //! Get the detection energy of the first photon //! in keV inline double get_energyA_in_keV() const - { return energyA; } + { return 1e3*energyA; } //! Get the detection energy of the second photon //! in keV inline double get_energyB_in_keV() const - { return energyB; } + { return 1e3*energyB; } private: diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index ccda26d303..8dfa3c7e67 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -76,11 +76,8 @@ CListModeDataROOT(const std::string& hroot_filename) this->exam_info_sptr->originating_system = this->originating_system; this->exam_info_sptr->set_num_energy_windows(this->root_file_sptr->get_number_of_energy_windows()); -// /std::vector a; - // std::vector b; - - this->exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres()); - this->exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres()); + this->exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres_in_keV()); + this->exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres_in_keV()); for(int i =0; iexam_info_sptr->get_num_energy_windows(); ++i) if (this->exam_info_sptr->get_high_energy_thres(i)<=this->exam_info_sptr->get_low_energy_thres(i)) @@ -88,13 +85,13 @@ CListModeDataROOT(const std::string& hroot_filename) std::vector val; val.resize(2); - if(this->root_file_sptr->get_low_energy_thres()[0]>this->root_file_sptr->get_low_energy_thres()[1]) + if(this->root_file_sptr->get_low_energy_thres_in_keV()[0]>this->root_file_sptr->get_low_energy_thres_in_keV()[1]) {val[0]=1; val[1]=2;} - else if(this->root_file_sptr->get_low_energy_thres()[1]>this->root_file_sptr->get_low_energy_thres()[0]) + else if(this->root_file_sptr->get_low_energy_thres_in_keV()[1]>this->root_file_sptr->get_low_energy_thres_in_keV()[0]) {val[0]=2; val[1]=1;} - else if(this->root_file_sptr->get_low_energy_thres()[1]==this->root_file_sptr->get_low_energy_thres()[0]) + else if(this->root_file_sptr->get_low_energy_thres_in_keV()[1]==this->root_file_sptr->get_low_energy_thres_in_keV()[0]) {val[0]=1; val[1]=1;} this->exam_info_sptr->set_energy_window_pair(val,1); diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 95402dbdf9..a3b71f5d9e 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -672,15 +672,15 @@ process_data() { if(((record.is_energy())&&(record.event().is_swapped()==false) - &&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < 1e-3*up_en_thres[en_win_A]) - &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B])) + &&(record.energy().get_energyA_in_keV() > low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < up_en_thres[en_win_A]) + &&(record.energy().get_energyB_in_keV() > low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < up_en_thres[en_win_B])) ||((record.is_energy())&&(record.event().is_swapped()==true) - &&(record.energy().get_energyA_in_keV() > 1e-3*low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_B]) - &&(record.energy().get_energyB_in_keV() > 1e-3*low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < 1e-3*up_en_thres[en_win_A]))) + &&(record.energy().get_energyA_in_keV() > low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < up_en_thres[en_win_B]) + &&(record.energy().get_energyB_in_keV() > low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < up_en_thres[en_win_A]))) { - // std::cout<< "energy A: " << 1e3*record.energy().get_energyB_in_keV() << '\n'; - // std::cout<< "energy B: " << 1e3*record.energy().get_energyA_in_keV() << '\n'; + std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; + std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); assert(bin.view_num()<=proj_data_ptr->get_max_view_num()); From 8ff6f780d006d24b8b5940cacc69bbf48d32335f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 6 Aug 2019 17:05:15 +0100 Subject: [PATCH 154/274] detection efficiency --- src/include/stir/scatter/ScatterSimulation.h | 10 ++- .../scatter_detection_modelling.cxx | 83 ++++++++++++++++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 635f391964..ae5d627ce2 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,9 +211,13 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency(const float energy, int en_window = 0) const; - -Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); + float detection_efficiency(const float energy, const int en_window = 0) const; + float detection_efficiency_full_model(const float energy, const int en_window = 0) const; + float photoelectric(const float K, const float std_peak, const float energy, const float ref_energy) const; + float compton_plateau(const float K, const float std_peak, const float energy, const float ref_energy, const float scaling_std_compton,const float shift_compton) const; + float flat_continuum(const float K, const float std_peak, const float energy, const float ref_energy) const; + float exponential_tail(const float K, const float std_peak, const float energy, const float ref_energy, const float beta) const; + Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); protected: diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 36ac0a1ffe..7e187405e6 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -97,7 +97,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy,int en_window) const +detection_efficiency(const float energy,const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -113,6 +113,87 @@ detection_efficiency(const float energy,int en_window) const return efficiency; } +float +ScatterSimulation:: +detection_efficiency_full_model(const float energy,const int en_window) const +{ + const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); + const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); + const float ref_energy = HLD - (HLD - LLD)/2; //the reference energy is the center of the given energy window + + const int Z = 66; // atomic number of LSO + const float H_1 = pow(Z,5)/ref_energy; //high of the photopeak prop. to the photoelectric cross section + const float H_2 = 8.17*pow(10,25)*total_Compton_cross_section(ref_energy)*Z; + const float H_3 = 7; + const float H_4 = 235; + const float beta = -4.682; + const float global_scale = 0.0000296; + const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); //full width half maximum + const float std_peak = sqrt(energy*ref_energy)*fwhm/2.35482; + const float scaling_std_compton = 107; + const float shift_compton = 0.5916; + + const float f1 = photoelectric(H_1, std_peak, energy, ref_energy); + const float f2 = compton_plateau(H_2, std_peak, energy, ref_energy,scaling_std_compton,shift_compton); + const float f3 = flat_continuum(H_3,std_peak, energy, ref_energy); + const float f4 = exponential_tail(H_4,std_peak, energy, ref_energy,beta); + + return global_scale*(f1+f2+f3+f4); +} + +float +ScatterSimulation:: +photoelectric(const float K, const float std_peak, const float energy, const float ref_energy) const +{ + const double pi = boost::math::constants::pi(); + const float diff = energy - ref_energy; + const float pow_diff = pow(diff,2); + const float pow_std_peak = pow(std_peak,2); + return K/(std_peak*sqrt(2*pi))*exp(-pow_diff/(2*pow_std_peak)); +} + +float +ScatterSimulation:: +compton_plateau(const float K, const float std_peak, const float energy, const float ref_energy, const float scaling_std_compton,const float shift_compton) const +{ + const double pi = boost::math::constants::pi(); + const float m_0_c_2 = 511.F; + const float alpha = ref_energy/m_0_c_2; + const float theta = 2*pi; + const float E_1 = ref_energy/(1+alpha*(1-cos(theta))); + const float mean = ref_energy*shift_compton; + return ((ref_energy/E_1)+(E_1/ref_energy)-1+cos(theta))*(K*exp(-(pow((energy - mean),2))/(scaling_std_compton*std_peak))); +} +float +ScatterSimulation:: +flat_continuum(const float K, const float std_peak, const float energy, const float ref_energy) const +{ + const float den = sqrt(2)*std_peak; + float f = 0; + if (energy<=ref_energy) + f = K* erfc((energy-ref_energy)/den); + else + f = 0; + return f; +} + +float +ScatterSimulation:: +exponential_tail(const float K, const float std_peak, const float energy, const float ref_energy, const float beta) const +{ + const double pi = boost::math::constants::pi(); + const float den1 = sqrt(2)*pi*std_peak*beta; + const float den2 = sqrt(2)*std_peak; + const float den3 = 2*beta; + float f = 0; + + if (energy > 100) + f = K * exp((energy-ref_energy)/den1)*erfc((energy-ref_energy)/den2+1/den3); + else + f =0; + return f; +} + float ScatterSimulation:: max_cos_angle(const float low, const float approx, const float resolution_at_511keV) From e4d8f5388000670f5d760f1ca3bc857af8074364 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 7 Aug 2019 16:05:30 +0100 Subject: [PATCH 155/274] remove swapping --- .../InputStreamFromROOTFileForCylindricalPET.cxx | 14 +------------- src/IO/InputStreamFromROOTFileForECATPET.cxx | 14 +------------- src/include/stir/ProjDataInfoCylindrical.inl | 4 ++++ src/include/stir/listmode/CListRecordROOT.h | 5 ----- src/listmode_buildblock/CListRecordROOT.cxx | 13 ------------- src/listmode_buildblock/LmToProjData.cxx | 15 ++------------- 6 files changed, 8 insertions(+), 57 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 3b86067cb2..0cd188b750 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -85,23 +85,11 @@ get_next_record(CListRecordROOT& record) continue; if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) continue; - if((this->low_energy_window_1low_energy_window_2)) - { if (this->energy1 < this->low_energy_window_1 || - this->energy1 > this->up_energy_window_2 || - this->energy2 < this->low_energy_window_1|| - this->energy2 > this->up_energy_window_2) - continue; - } - else - { - if (this->energy1 < this->low_energy_window_2 || this->energy1 > this->up_energy_window_1 || this->energy2 < this->low_energy_window_2|| - this->energy2 > this->up_energy_window_1) + this->energy2 > this->up_energy_window_2) continue; - } - break; } diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index e2ca49ef7d..abc706ef9c 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -81,23 +81,11 @@ get_next_record(CListRecordROOT& record) continue; if ( eventID1 != eventID2 && exclude_randoms ) continue; - if((this->low_energy_window_1low_energy_window_2)) - { if (this->energy1 < this->low_energy_window_1 || - this->energy1 > this->up_energy_window_2 || - this->energy2 < this->low_energy_window_1|| - this->energy2 > this->up_energy_window_2) - continue; - } - else - { - if (this->energy1 < this->low_energy_window_2 || this->energy1 > this->up_energy_window_1 || this->energy2 < this->low_energy_window_2|| - this->energy2 > this->up_energy_window_1) + this->energy2 > this->up_energy_window_2) continue; - } - break; } diff --git a/src/include/stir/ProjDataInfoCylindrical.inl b/src/include/stir/ProjDataInfoCylindrical.inl index 3b4a0125b6..7c4ecddee3 100644 --- a/src/include/stir/ProjDataInfoCylindrical.inl +++ b/src/include/stir/ProjDataInfoCylindrical.inl @@ -244,7 +244,11 @@ get_segment_axial_pos_num_for_ring_pair(int& segment_num, const int ring2) const { assert(0<=ring1); + //std::cout << "RING1" << ring1 << std::endl; + //std::cout << "NUM RINGS" << get_scanner_ptr()->get_num_rings()<< std::endl; + assert(ring1get_num_rings()); + assert(0<=ring2); assert(ring2get_num_rings()); diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index b391344117..42e3aa26be 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -240,11 +240,6 @@ class CListRecordROOT : public CListRecord // currently no gating yet this->time_data.init_from_data( time1,time2); - - if(this->event_data.is_swapped()) - this->energy_data.init_energy_from_data( - energy2,energy1); - else this->energy_data.init_energy_from_data( energy1,energy2); diff --git a/src/listmode_buildblock/CListRecordROOT.cxx b/src/listmode_buildblock/CListRecordROOT.cxx index 158bf60be1..0da2703d59 100644 --- a/src/listmode_buildblock/CListRecordROOT.cxx +++ b/src/listmode_buildblock/CListRecordROOT.cxx @@ -88,22 +88,9 @@ void CListEventROOT::init_from_data(const int& _ring1, const int& _ring2, else if ( det2 >= scanner_sptr->get_num_detectors_per_ring()) det2 = det2 - scanner_sptr->get_num_detectors_per_ring(); - if (det1 > det2) - { - int tmp = det1; - det1 = det2; - det2 = tmp; - - ring1 = _ring2; - ring2 = _ring1; - swapped = true; - } - else - { ring1 = _ring1; ring2 = _ring2; swapped = false; - } } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index a3b71f5d9e..074675d070 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -671,16 +671,8 @@ process_data() ) { - if(((record.is_energy())&&(record.event().is_swapped()==false) - &&(record.energy().get_energyA_in_keV() > low_en_thres[en_win_A])&&(record.energy().get_energyA_in_keV() < up_en_thres[en_win_A]) - &&(record.energy().get_energyB_in_keV() > low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < up_en_thres[en_win_B])) - ||((record.is_energy())&&(record.event().is_swapped()==true) - &&(record.energy().get_energyA_in_keV() > low_en_thres[en_win_B])&&(record.energy().get_energyB_in_keV() < up_en_thres[en_win_B]) - &&(record.energy().get_energyB_in_keV() > low_en_thres[en_win_A])&&(record.energy().get_energyB_in_keV() < up_en_thres[en_win_A]))) - - { - std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; - std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; + std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; + std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); assert(bin.view_num()<=proj_data_ptr->get_max_view_num()); @@ -718,9 +710,6 @@ process_data() (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += bin.get_bin_value() * event_increment; - - - } } } From bb677a84e9c5d2b07de20a0c7b23d581df39431d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 7 Aug 2019 17:09:24 +0100 Subject: [PATCH 156/274] fixed bug in root ecat --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 32 ++++++++++++------- .../IO/InputStreamFromROOTFileForECATPET.h | 17 ++++++---- .../IO/InputStreamFromROOTFileForECATPET.inl | 18 +++++++---- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index abc706ef9c..c9d55c4434 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -35,14 +35,14 @@ InputStreamFromROOTFileForECATPET:: InputStreamFromROOTFileForECATPET(std::string _filename, std::string _chain_name, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, - int block_repeater, + int block_repeater_y, int block_repeater_z, bool _exclude_scattered, bool _exclude_randoms, int _maximum_order_of_scatter, float _low_energy_window_1, float _up_energy_window_1, float _low_energy_window_2, float _up_energy_window_2, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), - block_repeater(block_repeater) + block_repeater_y(block_repeater_y), block_repeater_z(block_repeater_z) { set_defaults(); @@ -90,15 +90,15 @@ get_next_record(CListRecordROOT& record) } int ring1 = static_cast(crystalID1/crystal_repeater_z) - + static_cast(blockID1/ block_repeater)*crystal_repeater_z; + + static_cast(blockID1/ block_repeater_y)*crystal_repeater_z; int ring2 = static_cast(crystalID2/crystal_repeater_z) - + static_cast(blockID2/block_repeater)*crystal_repeater_z; + + static_cast(blockID2/block_repeater_y)*crystal_repeater_z; - int crystal1 = (blockID1%block_repeater) * crystal_repeater_y + int crystal1 = (blockID1%block_repeater_y) * crystal_repeater_y + (crystalID1%crystal_repeater_z); - int crystal2 = (blockID2%block_repeater) * crystal_repeater_y + int crystal2 = (blockID2%block_repeater_y) * crystal_repeater_y + (crystalID2%crystal_repeater_z); // GATE counts crystal ID =0 the most negative. Therefore @@ -133,7 +133,8 @@ InputStreamFromROOTFileForECATPET::set_defaults() crystal_repeater_x = -1; crystal_repeater_y = -1; crystal_repeater_z = -1; - block_repeater = -1; + block_repeater_y = -1; + block_repeater_z = -1; } void @@ -142,7 +143,8 @@ InputStreamFromROOTFileForECATPET::initialise_keymap() base_type::initialise_keymap(); this->parser.add_start_key("GATE_ECAT_PET Parameters"); this->parser.add_stop_key("End GATE_ECAT_PET Parameters"); - this->parser.add_key("number of blocks", &this->block_repeater); + this->parser.add_key("number of blocks Y", &this->block_repeater_y); + this->parser.add_key("number of blocks Z", &this->block_repeater_z); this->parser.add_key("number of crystals X", &this->crystal_repeater_x); this->parser.add_key("number of crystals Y", &this->crystal_repeater_y); @@ -194,19 +196,25 @@ check_all_required_keywords_are_set(std::string& ret) const if (crystal_repeater_y == -1) { - stream << "crystal_repeater_x, "; + stream << "crystal_repeater_y, "; ok = false; } if (crystal_repeater_z == -1) { - stream << "crystal_repeater_x, "; + stream << "crystal_repeater_z, "; ok = false; } - if (block_repeater == -1) + if (block_repeater_y == -1) { - stream << "crystal_repeater_x, "; + stream << "block_repeater_y, "; + ok = false; + } + + if (block_repeater_z == -1) + { + stream << "block_repeater_z, "; ok = false; } diff --git a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h index a40b84e473..97c9b1146a 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h @@ -53,10 +53,11 @@ From ( Date: Thu, 8 Aug 2019 13:32:06 +0100 Subject: [PATCH 159/274] detection efficiency --- src/include/stir/scatter/ScatterSimulation.h | 12 +- .../scatter_detection_modelling.cxx | 117 +++++++++++------- 2 files changed, 82 insertions(+), 47 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index ae5d627ce2..861ff8568c 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -212,11 +212,13 @@ class ScatterSimulation : public RegisteredObject, //@} float detection_efficiency(const float energy, const int en_window = 0) const; - float detection_efficiency_full_model(const float energy, const int en_window = 0) const; - float photoelectric(const float K, const float std_peak, const float energy, const float ref_energy) const; - float compton_plateau(const float K, const float std_peak, const float energy, const float ref_energy, const float scaling_std_compton,const float shift_compton) const; - float flat_continuum(const float K, const float std_peak, const float energy, const float ref_energy) const; - float exponential_tail(const float K, const float std_peak, const float energy, const float ref_energy, const float beta) const; + float detection_efficiency_full_model(const float incoming_photon_energy, const int en_window = 0) const; + std::vector energy_spectrum(const float LLD, const float HLD, const float incoming_photon_energy) const; + float detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const; + float photoelectric(const float K, const float std_peak, const float x, const float energy) const; + float compton_plateau(const float K, const float std_peak, const float x, const float energy, const float theta, const float scaling_std_compton,const float shift_compton) const; + float flat_continuum(const float K, const float std_peak, const float x, const float energy) const; + float exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const; Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); protected: diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 7e187405e6..2df33fd759 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -97,7 +97,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy,const int en_window) const +detection_efficiency(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -113,65 +113,100 @@ detection_efficiency(const float energy,const int en_window) const return efficiency; } +float +ScatterSimulation::detection_efficiency_full_model(const float incoming_photon_energy, const int en_window) const +{ + float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); + float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); + float sum = 0; + std::vector out = energy_spectrum(LLD, HLD, incoming_photon_energy); + for(int i = 0 ; i< out.size(); ++i) + { + sum+=out[i]; + } + return sum; +} + +std::vector +ScatterSimulation::energy_spectrum(const float LLD, const float HLD, const float incoming_photon_energy) const +{ + int size = HLD - LLD; + std::vector energy_range(size); + std::vector out(size); + float increment_theta = (2*M_PI)/size; + std::vector theta(size); + for(int i = 0 ; i< size; ++i) + { + energy_range[i]+= LLD + i; + theta[i]+=i*increment_theta; + out[i]+=0; + } + + for(int j = 0; j < size; ++j) + { + out[j]= detection_model_with_fitted_parameters(energy_range[j], theta[j], incoming_photon_energy); + } + + return out; +} + float ScatterSimulation:: -detection_efficiency_full_model(const float energy,const int en_window) const +detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const { - const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); - const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); - const float ref_energy = HLD - (HLD - LLD)/2; //the reference energy is the center of the given energy window + //! Brief + //! All the parameters are obtained by fitting the model to the energy spectrum obtained with GATE. + //! The crystal used here is LSO, the one for the Siemens mMR (atomic number Z = 66). + //! We consider to have four terms: (i) gaussian model for the photopeak, (ii) compton plateau, (iii) flat continuum, (iv) exponential tale + //! The model has be trained with 511 keV and tested with 370 keV. const int Z = 66; // atomic number of LSO - const float H_1 = pow(Z,5)/ref_energy; //high of the photopeak prop. to the photoelectric cross section - const float H_2 = 8.17*pow(10,25)*total_Compton_cross_section(ref_energy)*Z; - const float H_3 = 7; - const float H_4 = 235; - const float beta = -4.682; - const float global_scale = 0.0000296; - const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); //full width half maximum - const float std_peak = sqrt(energy*ref_energy)*fwhm/2.35482; - const float scaling_std_compton = 107; - const float shift_compton = 0.5916; - - const float f1 = photoelectric(H_1, std_peak, energy, ref_energy); - const float f2 = compton_plateau(H_2, std_peak, energy, ref_energy,scaling_std_compton,shift_compton); - const float f3 = flat_continuum(H_3,std_peak, energy, ref_energy); - const float f4 = exponential_tail(H_4,std_peak, energy, ref_energy,beta); + const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section + const float H_2 = 9.27*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section + const float H_3 = 7; //fitting parameter + const float H_4 = 26.0; //fitting parameter + const float beta = -0.817; //fitting parameter + const float global_scale = 0.000233; //fitting parameter + const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); + const float std_peak = energy*fwhm/2.35482; + const float scaling_std_compton = 28.8; //fitting parameter + const float shift_compton = 0.6; //fitting parameter + const float f1 = photoelectric(H_1, std_peak, x, energy); + const float f2 = compton_plateau(H_2, std_peak, x, energy,theta, scaling_std_compton,shift_compton); + const float f3 = flat_continuum(H_3,std_peak, x, energy); + const float f4 = exponential_tail(H_4,std_peak, x, energy,beta); return global_scale*(f1+f2+f3+f4); } float ScatterSimulation:: -photoelectric(const float K, const float std_peak, const float energy, const float ref_energy) const +photoelectric(const float K, const float std_peak, const float x, const float energy) const { - const double pi = boost::math::constants::pi(); - const float diff = energy - ref_energy; + const float diff = x - energy; const float pow_diff = pow(diff,2); const float pow_std_peak = pow(std_peak,2); - return K/(std_peak*sqrt(2*pi))*exp(-pow_diff/(2*pow_std_peak)); + return K/(std_peak*sqrt(2*M_PI))*exp(-pow_diff/(2*pow_std_peak)); } float ScatterSimulation:: -compton_plateau(const float K, const float std_peak, const float energy, const float ref_energy, const float scaling_std_compton,const float shift_compton) const +compton_plateau(const float K, const float std_peak, const float x, const float energy, const float theta, const float scaling_std_compton,const float shift_compton) const { - const double pi = boost::math::constants::pi(); const float m_0_c_2 = 511.F; - const float alpha = ref_energy/m_0_c_2; - const float theta = 2*pi; - const float E_1 = ref_energy/(1+alpha*(1-cos(theta))); - const float mean = ref_energy*shift_compton; - return ((ref_energy/E_1)+(E_1/ref_energy)-1+cos(theta))*(K*exp(-(pow((energy - mean),2))/(scaling_std_compton*std_peak))); + const float alpha = energy/m_0_c_2; + const float E_1 = energy/(1+alpha*(1-cos(theta))); + const float mean = energy*shift_compton; + return ((energy/E_1)+(E_1/energy)-1+cos(theta))*(K*exp(-(pow((x - mean),2))/(4*scaling_std_compton*std_peak))); } float ScatterSimulation:: -flat_continuum(const float K, const float std_peak, const float energy, const float ref_energy) const +flat_continuum(const float K, const float std_peak, const float x, const float energy) const { const float den = sqrt(2)*std_peak; float f = 0; - if (energy<=ref_energy) - f = K* erfc((energy-ref_energy)/den); + if (x<=energy) + f = K* erfc((x-energy)/den); else f = 0; return f; @@ -179,18 +214,16 @@ flat_continuum(const float K, const float std_peak, const float energy, const fl float ScatterSimulation:: -exponential_tail(const float K, const float std_peak, const float energy, const float ref_energy, const float beta) const +exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const { - const double pi = boost::math::constants::pi(); - const float den1 = sqrt(2)*pi*std_peak*beta; + const float den1 = sqrt(2)*M_PI*std_peak*beta; const float den2 = sqrt(2)*std_peak; const float den3 = 2*beta; - float f = 0; - - if (energy > 100) - f = K * exp((energy-ref_energy)/den1)*erfc((energy-ref_energy)/den2+1/den3); + float f; + if (x > 100) + f = K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); else - f =0; + f = 0; return f; } From ddaa2a428b6be0a12146ef0930b3281ccd787ef8 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 8 Aug 2019 14:33:51 +0100 Subject: [PATCH 160/274] efficiency --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../SingleScatterLikelihoodAndGradient.cxx | 3 ++- src/scatter_buildblock/scatter_detection_modelling.cxx | 7 ++----- .../scatter_estimate_for_one_scatter_point.cxx | 2 ++ 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 861ff8568c..4cf6d88141 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -212,7 +212,7 @@ class ScatterSimulation : public RegisteredObject, //@} float detection_efficiency(const float energy, const int en_window = 0) const; - float detection_efficiency_full_model(const float incoming_photon_energy, const int en_window = 0) const; + float detection_efficiency_new(const float incoming_photon_energy, const int en_window = 0) const; std::vector energy_spectrum(const float LLD, const float HLD, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 669554a483..463ee1e9a2 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -405,7 +405,8 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; - + if ((detection_probability_XY==0)&&(detection_probability_YX==0)) + return 0; const float emiss_to_detA = cached_integral_over_activity_image_between_scattpoint_det diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 2df33fd759..a2c00a3538 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -114,7 +114,7 @@ detection_efficiency(const float energy, const int en_window) const } float -ScatterSimulation::detection_efficiency_full_model(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_new(const float incoming_photon_energy, const int en_window) const { float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); @@ -252,10 +252,7 @@ detection_efficiency_no_scatter(const unsigned det_num_A, { // TODO: slightly dangerous to use a static here // it would give wrong results when the energy_thresholds are changed... - static const float detector_efficiency_no_scatter = 1; - /*detection_efficiency(511.F, en_window) > 0 - ? detection_efficiency(511.F, en_window) - : (info("Zero detection efficiency for 511. Will normalise to 1"), 1.F);*/ + static const float detector_efficiency_no_scatter = 1; //here we remove this, it will be multiplied by the unscattered counts const CartesianCoordinate3D& detector_coord_A = detection_points_vector[det_num_A]; diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 7d65f082b6..f3aa69ac99 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -145,6 +145,8 @@ detection_efficiency_unscattered.push_back(0); float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; + if ((detection_probability_XY==0)&&(detection_probability_YX==0)) + return 0; const float emiss_to_detA = From 8892f82c6c0691939f66fbf8bc83d7aa911503fb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 9 Aug 2019 00:31:08 +0100 Subject: [PATCH 161/274] src --- src/include/stir/scatter/ScatterSimulation.h | 4 +- .../scatter_detection_modelling.cxx | 48 +++++++++++-------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 4cf6d88141..149d04b218 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -212,8 +212,8 @@ class ScatterSimulation : public RegisteredObject, //@} float detection_efficiency(const float energy, const int en_window = 0) const; - float detection_efficiency_new(const float incoming_photon_energy, const int en_window = 0) const; - std::vector energy_spectrum(const float LLD, const float HLD, const float incoming_photon_energy) const; + float detection_efficiency_full(const float incoming_photon_energy, const int en_window = 0) const; + std::vector detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; float compton_plateau(const float K, const float std_peak, const float x, const float energy, const float theta, const float scaling_std_compton,const float shift_compton) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index a2c00a3538..fce7efd89c 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -32,6 +32,7 @@ #include "stir/ProjDataInfoCylindricalNoArcCorr.h" #include "stir/numerics/erf.h" #include "stir/info.h" +#include "stir/CPUTimer.h" #include START_NAMESPACE_STIR @@ -110,46 +111,55 @@ detection_efficiency(const float energy, const int en_window) const 0.5f*( erf((this->template_exam_info_sptr->get_high_energy_thres(en_window)-energy)/sigma_times_sqrt2) - erf((this->template_exam_info_sptr->get_low_energy_thres(en_window)-energy)/sigma_times_sqrt2 )); /* Maximum efficiency is 1.*/ - return efficiency; -} -float -ScatterSimulation::detection_efficiency_new(const float incoming_photon_energy, const int en_window) const -{ - float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); - float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); - float sum = 0; - std::vector out = energy_spectrum(LLD, HLD, incoming_photon_energy); - for(int i = 0 ; i< out.size(); ++i) - { - sum+=out[i]; - } - return sum; + return efficiency; } std::vector -ScatterSimulation::energy_spectrum(const float LLD, const float HLD, const float incoming_photon_energy) const +ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const { - int size = HLD - LLD; + std::vector energy_range(size); std::vector out(size); + float increment_x = (HLD - LLD)/size; float increment_theta = (2*M_PI)/size; std::vector theta(size); for(int i = 0 ; i< size; ++i) { - energy_range[i]+= LLD + i; + energy_range[i]+= LLD+i*increment_x; theta[i]+=i*increment_theta; out[i]+=0; } for(int j = 0; j < size; ++j) { - out[j]= detection_model_with_fitted_parameters(energy_range[j], theta[j], incoming_photon_energy); + out[j]+= detection_model_with_fitted_parameters(energy_range[j], theta[j], incoming_photon_energy); } return out; } +float +ScatterSimulation::detection_efficiency_full(const float incoming_photon_energy, const int en_window) const +{ + + const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); + const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); + float sum = 0; + const int size = HLD-LLD; + const float increment_x = (HLD - LLD)/size; + const float increment_theta = (2*M_PI)/size; + for(int i = 0 ; i< size; ++i) + { + const float energy_range = LLD+i*increment_x; + const float theta=i*increment_theta; + sum+= detection_model_with_fitted_parameters(energy_range, theta, incoming_photon_energy); + } + + sum*=increment_x; + return sum; +} + float ScatterSimulation:: detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const @@ -166,7 +176,7 @@ detection_model_with_fitted_parameters(const float x, const float theta, const f const float H_3 = 7; //fitting parameter const float H_4 = 26.0; //fitting parameter const float beta = -0.817; //fitting parameter - const float global_scale = 0.000233; //fitting parameter + const float global_scale = 2.33*1e-07; //fitting parameter const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); const float std_peak = energy*fwhm/2.35482; const float scaling_std_compton = 28.8; //fitting parameter From ebf28b23548ca16180fc52a329c84e04848550f9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 9 Aug 2019 11:27:56 +0100 Subject: [PATCH 162/274] can read data --- .../SingleScatterLikelihoodAndGradient.h | 5 + .../SingleScatterLikelihoodAndGradient.cxx | 146 ++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index a5243b33c7..e0ea5ab4ae 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -65,6 +65,7 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); + ProjDataInMemory scatter_likelihood_and_gradient(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu); protected: void @@ -105,6 +106,10 @@ class SingleScatterLikelihoodAndGradient : public void L_G_for_viewgram_from_est_data(const Viewgram& viewgram,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); + void + scatter_likelihood_and_gradient_for_view_segment_number(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); + + void scatter_likelihood_and_gradient_for_viewgram(const Viewgram& viewgram, Viewgram& v_est, VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu); }; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 463ee1e9a2..15d6fcddbd 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -762,5 +762,151 @@ L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesia } + +ProjDataInMemory +SingleScatterLikelihoodAndGradient:: +scatter_likelihood_and_gradient(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu) +{ + + info("ScatterSimulator: Running Scatter Simulation ..."); + info("ScatterSimulator: Initialising ..."); + // The activiy image might have been changed, during the estimation process. + this->remove_cache_for_integrals_over_activity(); + this->remove_cache_for_integrals_over_attenuation(); + this->sample_scatter_points(); + this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); + this->initialise_cache_for_scattpoint_det_integrals_over_activity(); + + ViewSegmentNumbers vs_num; + + int bin_counter = 0; + int axial_bins = 0 ; + double sum = 0; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + + const int total_bins = + this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns + coordinate in a coordinate system where z=0 in the first ring of the scanner. + We want to shift this to a coordinate system where z=0 in the middle + of the scanner. + We can use get_m() as that uses the 'middle of the scanner' system. + (sorry) + */ +#ifndef NDEBUG + { + CartesianCoordinate3D detector_coord_A, detector_coord_B; + // check above statement + this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( + detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); + assert(detector_coord_A.z() == 0); + assert(detector_coord_B.z() == 0); + // check that get_m refers to the middle of the scanner + const float m_first = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); + const float m_last = + this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); + assert(fabs(m_last + m_first) < m_last * 10E-4); + } +#endif + this->shift_detector_coordinates_to_origin = + CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); + + info("ScatterSimulator: Initialization finished ..."); + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); + vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); + ++vs_num.view_num()) + { + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + + this->scatter_likelihood_and_gradient_for_view_segment_number(data,gradient_image,vs_num,compute_gradient,isgradient_mu); + + bin_counter += + this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * + this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); + //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); + + std::cout<< bin_counter << " / "<< total_bins <output_proj_data_sptr); +} + +void +SingleScatterLikelihoodAndGradient:: +scatter_likelihood_and_gradient_for_view_segment_number(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) +{ + + const Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + Viewgram v_est=data.get_empty_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + + scatter_likelihood_and_gradient_for_viewgram(viewgram,v_est,gradient_image, compute_gradient,isgradient_mu); + this->output_proj_data_sptr->set_viewgram(v_est); + +} + + +void +SingleScatterLikelihoodAndGradient:: +scatter_likelihood_and_gradient_for_viewgram(const Viewgram& viewgram, Viewgram& v_est, VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu) +{ + + const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); + + // First construct a vector of all bins that we'll process. + // The reason for making this list before the actual calculation is that we can then parallelise over all bins + // without having to think about double loops. + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); + bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); + ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); + bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); + ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } + // now compute scatter for all bins + + double sum = 0; + + + VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); + + + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { + //creates a template image to fill + tmp_gradient_image.fill(0); + const Bin bin = all_bins[i]; + + //forward model + const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); + gradient_image += tmp_gradient_image; + if (sum != sum) error('Nan Here'); + } +} + + END_NAMESPACE_STIR From d3a881866358b2aa8cfb9f6ae8446e698248fbde Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 9 Aug 2019 14:38:59 +0100 Subject: [PATCH 163/274] test --- src/include/stir/scatter/ScatterSimulation.h | 1 - .../SingleScatterLikelihoodAndGradient.h | 10 +- .../SingleScatterLikelihoodAndGradient.cxx | 156 ++++++++++++++++-- 3 files changed, 147 insertions(+), 20 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 149d04b218..0c87d07efc 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -376,7 +376,6 @@ class ScatterSimulation : public RegisteredObject, std::string output_proj_data_filename; //! Shared ptr to hold the simulated data. shared_ptr output_proj_data_sptr; - shared_ptr HR_output_proj_data_sptr; //! threshold below which a voxel in the attenuation image will not be considered as a candidate scatter point float attenuation_threshold; diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index e0ea5ab4ae..9833824844 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -65,7 +65,10 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); - ProjDataInMemory scatter_likelihood_and_gradient(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu); + ProjDataInMemory likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); + ProjDataInMemory get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); + ProjDataInMemory get_jacobian_test(VoxelsOnCartesianGrid&gradient_image_array,const bool compute_gradient, const bool isgradient_mu); + ProjDataInMemory get_ratio(std::vector &ratio_vector, const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata); protected: void @@ -106,10 +109,9 @@ class SingleScatterLikelihoodAndGradient : public void L_G_for_viewgram_from_est_data(const Viewgram& viewgram,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - void - scatter_likelihood_and_gradient_for_view_segment_number(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); + void get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); - void scatter_likelihood_and_gradient_for_viewgram(const Viewgram& viewgram, Viewgram& v_est, VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu); + void get_jacobian_for_viewgram(Viewgram& v_est, std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); }; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 15d6fcddbd..a8bebb54b0 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -761,11 +761,26 @@ L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesia } } +ProjDataInMemory +SingleScatterLikelihoodAndGradient:: +get_jacobian_test(VoxelsOnCartesianGrid &gradient_image,const bool compute_gradient, const bool isgradient_mu) +{ + int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only + std::cout << "LENGHT:" << lenght << std::endl; + std::vector > jacobian_array; + jacobian_array.reserve(lenght); + for (int i = 0 ; i < lenght ; ++i) + { + jacobian_array.push_back(gradient_image); + } + const ProjDataInMemory a = get_jacobian(jacobian_array,compute_gradient, isgradient_mu); + return a; +} ProjDataInMemory SingleScatterLikelihoodAndGradient:: -scatter_likelihood_and_gradient(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu) +get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) { info("ScatterSimulator: Running Scatter Simulation ..."); @@ -830,7 +845,7 @@ scatter_likelihood_and_gradient(const ProjData& data,VoxelsOnCartesianGridscatter_likelihood_and_gradient_for_view_segment_number(data,gradient_image,vs_num,compute_gradient,isgradient_mu); + this->get_jacobian_for_view_segment_number(gradient_image_array,vs_num,compute_gradient,isgradient_mu); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * @@ -847,13 +862,11 @@ scatter_likelihood_and_gradient(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) +get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) { - const Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - Viewgram v_est=data.get_empty_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - - scatter_likelihood_and_gradient_for_viewgram(viewgram,v_est,gradient_image, compute_gradient,isgradient_mu); + Viewgram v_est=this->output_proj_data_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + get_jacobian_for_viewgram(v_est,gradient_image_array, compute_gradient,isgradient_mu); this->output_proj_data_sptr->set_viewgram(v_est); } @@ -861,10 +874,10 @@ scatter_likelihood_and_gradient_for_view_segment_number(const ProjData&data,Voxe void SingleScatterLikelihoodAndGradient:: -scatter_likelihood_and_gradient_for_viewgram(const Viewgram& viewgram, Viewgram& v_est, VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu) +get_jacobian_for_viewgram(Viewgram& v_est, std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) { - const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); + const ViewSegmentNumbers vs_num(v_est.get_view_num(),v_est.get_segment_num()); // First construct a vector of all bins that we'll process. // The reason for making this list before the actual calculation is that we can then parallelise over all bins @@ -887,10 +900,7 @@ scatter_likelihood_and_gradient_for_viewgram(const Viewgram& viewgram, Vi } // now compute scatter for all bins - double sum = 0; - - - VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); + VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); for (int i = 0; i < static_cast(all_bins.size()); ++i) @@ -902,11 +912,127 @@ scatter_likelihood_and_gradient_for_viewgram(const Viewgram& viewgram, Vi //forward model const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); - gradient_image += tmp_gradient_image; - if (sum != sum) error('Nan Here'); + gradient_image_array[i] += tmp_gradient_image; } } +ProjDataInMemory +SingleScatterLikelihoodAndGradient:: +get_ratio(std::vector &ratio_vector, const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata) +{ + ProjDataInMemory est_projdata_HR(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()); + est_projdata_HR.fill(0); + ProjDataInMemory ratio_HR(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()); + ratio_HR.fill(0); + ProjDataInMemory ratio_LR(est_projdata.get_exam_info_sptr(),est_projdata.get_proj_data_info_sptr()); + ratio_LR.fill(0); + if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,true); + else + est_projdata_HR.fill(est_projdata); + + Bin bin; + { + for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) + for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); + + for (bin.view_num()=sino.get_min_view_num(); + bin.view_num()<=sino.get_max_view_num(); + ++bin.view_num()) + { + for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; + ratio_HR.set_sinogram(ratio_sino); + } + + } + } + + if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::pull_scatter_estimate(ratio_LR,est_projdata,ratio_HR,true); + else + ratio_LR.fill(ratio_HR); + + ViewSegmentNumbers vs_num; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num();vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); ++vs_num.view_num()) + { + + Viewgram viewgram = ratio_LR.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } + + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { + + const Bin bin = all_bins[i]; + + ratio_vector[i] = viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; + } + + } + } + + return est_projdata_HR; +} + +ProjDataInMemory +SingleScatterLikelihoodAndGradient:: +likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) +{ + gradient_image_LR.fill(0); + gradient_image_HR.fill(0); + int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only + std::cout << "LENGHT:" << lenght << std::endl; + std::vector > jacobian_array; + std::vector ratio; + jacobian_array.reserve(lenght); + ratio.reserve(lenght); + for (int i = 0 ; i < lenght ; ++i) + { + jacobian_array.push_back(gradient_image_LR); + ratio.push_back(0.F); + } + + const ProjDataInMemory est_projdata_LR = get_jacobian(jacobian_array, compute_gradient, isgradient_mu); + + + const ProjDataInMemory est_projdata_HR = get_ratio(ratio, projdata, add_projdata, est_projdata_LR); + + for (int i = 0 ; i < lenght ; ++i) + { + gradient_image_LR += jacobian_array[i]*ratio[i]; + } + + if((gradient_image_HR.get_x_size()!=gradient_image_LR.get_x_size())||(gradient_image_HR.get_y_size()!=gradient_image_LR.get_y_size())||(gradient_image_HR.get_z_size()!=gradient_image_LR.get_z_size())) + { + if(isgradient_mu==true) + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_values); + else + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_projections); + + } + + return est_projdata_HR; + +} END_NAMESPACE_STIR From a4dca12a374ffaf6c145383514f0e979b6fcc2e3 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 9 Aug 2019 15:07:51 +0100 Subject: [PATCH 164/274] array code --- src/include/stir/scatter/ScatterSimulation.h | 1 + .../SingleScatterLikelihoodAndGradient.h | 6 +- .../SingleScatterLikelihoodAndGradient.cxx | 229 +++++++++--------- 3 files changed, 112 insertions(+), 124 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 0c87d07efc..149d04b218 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -376,6 +376,7 @@ class ScatterSimulation : public RegisteredObject, std::string output_proj_data_filename; //! Shared ptr to hold the simulated data. shared_ptr output_proj_data_sptr; + shared_ptr HR_output_proj_data_sptr; //! threshold below which a voxel in the attenuation image will not be considered as a candidate scatter point float attenuation_threshold; diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 9833824844..739d417095 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -66,9 +66,9 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); ProjDataInMemory likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); - ProjDataInMemory get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); - ProjDataInMemory get_jacobian_test(VoxelsOnCartesianGrid&gradient_image_array,const bool compute_gradient, const bool isgradient_mu); - ProjDataInMemory get_ratio(std::vector &ratio_vector, const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata); + void get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); + //ProjDataInMemory get_jacobian_test(VoxelsOnCartesianGrid&gradient_image_array,const bool compute_gradient, const bool isgradient_mu); + void get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector); protected: void diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index a8bebb54b0..9668686928 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -761,31 +761,54 @@ L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesia } } + ProjDataInMemory SingleScatterLikelihoodAndGradient:: -get_jacobian_test(VoxelsOnCartesianGrid &gradient_image,const bool compute_gradient, const bool isgradient_mu) +likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) { + gradient_image_LR.fill(0); + gradient_image_HR.fill(0); + int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only + std::vector > jacobian_array; + std::vector ratio; + jacobian_array.reserve(lenght); + ratio.reserve(lenght); + for (int i = 0 ; i <= lenght ; ++i) + { + jacobian_array.push_back(gradient_image_LR); + ratio.push_back(0); + } + + get_jacobian(jacobian_array, compute_gradient, isgradient_mu); + const ProjDataInMemory est_data_LR = *(this->output_proj_data_sptr); + get_ratio(projdata,add_projdata,est_data_LR,ratio); + + for (int i = 0 ; i <= lenght ; ++i) + { + gradient_image_LR += jacobian_array[i]*ratio[i]; + } + + if((gradient_image_HR.get_x_size()!=gradient_image_LR.get_x_size())||(gradient_image_HR.get_y_size()!=gradient_image_LR.get_y_size())||(gradient_image_HR.get_z_size()!=gradient_image_LR.get_z_size())) + { + if(isgradient_mu==true) + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_values); + else + transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_projections); + + } + + ProjDataInMemory est_data_HR = *(this->HR_output_proj_data_sptr); + return est_data_HR; - int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only - std::cout << "LENGHT:" << lenght << std::endl; - std::vector > jacobian_array; - jacobian_array.reserve(lenght); - for (int i = 0 ; i < lenght ; ++i) - { - jacobian_array.push_back(gradient_image); - } - const ProjDataInMemory a = get_jacobian(jacobian_array,compute_gradient, isgradient_mu); - return a; } -ProjDataInMemory +void SingleScatterLikelihoodAndGradient:: get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) { - info("ScatterSimulator: Running Scatter Simulation ..."); - info("ScatterSimulator: Initialising ..."); - // The activiy image might have been changed, during the estimation process. + this->output_proj_data_sptr->fill(0.f); + this->remove_cache_for_integrals_over_activity(); this->remove_cache_for_integrals_over_attenuation(); this->sample_scatter_points(); @@ -857,24 +880,23 @@ get_jacobian(std::vector > &gradient_image_array,co } } - return *(this->output_proj_data_sptr); } void SingleScatterLikelihoodAndGradient:: -get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) +get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) { - Viewgram v_est=this->output_proj_data_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); + get_jacobian_for_viewgram(v_est,gradient_image_array, compute_gradient,isgradient_mu); - this->output_proj_data_sptr->set_viewgram(v_est); + output_proj_data_sptr->set_viewgram(v_est); } - void SingleScatterLikelihoodAndGradient:: -get_jacobian_for_viewgram(Viewgram& v_est, std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) +get_jacobian_for_viewgram(Viewgram& v_est,std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) { const ViewSegmentNumbers vs_num(v_est.get_view_num(),v_est.get_segment_num()); @@ -900,138 +922,103 @@ get_jacobian_for_viewgram(Viewgram& v_est, std::vector tmp_gradient_image(gradient_image_array[0]); + VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); for (int i = 0; i < static_cast(all_bins.size()); ++i) { //creates a template image to fill tmp_gradient_image.fill(0); + const Bin bin = all_bins[i]; //forward model const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); gradient_image_array[i] += tmp_gradient_image; } -} +} -ProjDataInMemory +void SingleScatterLikelihoodAndGradient:: -get_ratio(std::vector &ratio_vector, const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata) +get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector) { - ProjDataInMemory est_projdata_HR(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()); - est_projdata_HR.fill(0); - ProjDataInMemory ratio_HR(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()); - ratio_HR.fill(0); - ProjDataInMemory ratio_LR(est_projdata.get_exam_info_sptr(),est_projdata.get_proj_data_info_sptr()); - ratio_LR.fill(0); - if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,true); - else - est_projdata_HR.fill(est_projdata); - - Bin bin; - { - for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) - for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) - { - Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); - - for (bin.view_num()=sino.get_min_view_num(); - bin.view_num()<=sino.get_max_view_num(); - ++bin.view_num()) - { - for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; - ratio_HR.set_sinogram(ratio_sino); - } - - } - } - - if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::pull_scatter_estimate(ratio_LR,est_projdata,ratio_HR,true); - else - ratio_LR.fill(ratio_HR); - - ViewSegmentNumbers vs_num; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num();vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); ++vs_num.view_num()) - { - - Viewgram viewgram = ratio_LR.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); - std::vector all_bins; - { - Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); - for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - { - all_bins.push_back(bin); - } - } - } - for (int i = 0; i < static_cast(all_bins.size()); ++i) - { + this->HR_output_proj_data_sptr.reset(new ProjDataInMemory(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()->create_shared_clone())); + ProjDataInMemory ratio_HR(projdata); + ProjDataInMemory est_projdata_HR(projdata); + ProjDataInMemory ratio_LR(est_projdata); - const Bin bin = all_bins[i]; + if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,true); + else + est_projdata_HR.fill(est_projdata); - ratio_vector[i] = viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; - } + Bin bin; + { + for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) + for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); + this->HR_output_proj_data_sptr->set_sinogram(est_sino); + + for (bin.view_num()=sino.get_min_view_num(); + bin.view_num()<=sino.get_max_view_num(); + ++bin.view_num()) + { + for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; + ratio_HR.set_sinogram(ratio_sino); + } - } - } + } + } - return est_projdata_HR; -} + if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) + ScatterEstimation::push_scatter_estimate(ratio_LR,est_projdata,ratio_HR,true); + else + ratio_LR.fill(ratio_HR); -ProjDataInMemory -SingleScatterLikelihoodAndGradient:: -likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) -{ - gradient_image_LR.fill(0); - gradient_image_HR.fill(0); - int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only - std::cout << "LENGHT:" << lenght << std::endl; - std::vector > jacobian_array; - std::vector ratio; - jacobian_array.reserve(lenght); - ratio.reserve(lenght); - for (int i = 0 ; i < lenght ; ++i) + ViewSegmentNumbers vs_num; + + for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) + { + for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num();vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); ++vs_num.view_num()) { - jacobian_array.push_back(gradient_image_LR); - ratio.push_back(0.F); - } - const ProjDataInMemory est_projdata_LR = get_jacobian(jacobian_array, compute_gradient, isgradient_mu); + Viewgram viewgram = ratio_LR.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + //Viewgram v_add = add_sino.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + //Viewgram v_est = est_data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } - const ProjDataInMemory est_projdata_HR = get_ratio(ratio, projdata, add_projdata, est_projdata_LR); + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { - for (int i = 0 ; i < lenght ; ++i) - { - gradient_image_LR += jacobian_array[i]*ratio[i]; - } + const Bin bin = all_bins[i]; - if((gradient_image_HR.get_x_size()!=gradient_image_LR.get_x_size())||(gradient_image_HR.get_y_size()!=gradient_image_LR.get_y_size())||(gradient_image_HR.get_z_size()!=gradient_image_LR.get_z_size())) - { - if(isgradient_mu==true) - transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_values); - else - transpose_zoom_image(gradient_image_HR,gradient_image_LR,ZoomOptions::preserve_projections); + ratio_vector[i] = viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; + } + } } - return est_projdata_HR; } END_NAMESPACE_STIR From 77a95946ff65a19d8c3810c479d77c1b7b694976 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 9 Aug 2019 16:23:08 +0100 Subject: [PATCH 165/274] checked --- .../SingleScatterLikelihoodAndGradient.h | 7 +-- .../SingleScatterLikelihoodAndGradient.cxx | 55 +++++++++---------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 739d417095..9476d8f57a 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -66,9 +66,8 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); ProjDataInMemory likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); - void get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); - //ProjDataInMemory get_jacobian_test(VoxelsOnCartesianGrid&gradient_image_array,const bool compute_gradient, const bool isgradient_mu); - void get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector); + ProjDataInMemory get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); + ProjDataInMemory get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector); protected: void @@ -109,7 +108,7 @@ class SingleScatterLikelihoodAndGradient : public void L_G_for_viewgram_from_est_data(const Viewgram& viewgram,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - void get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); + void get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,ProjData &est_data,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); void get_jacobian_for_viewgram(Viewgram& v_est, std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 9668686928..3c9e5d4254 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -768,22 +768,21 @@ likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_pr { gradient_image_LR.fill(0); gradient_image_HR.fill(0); - int lenght = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only + int length = this->output_proj_data_sptr->get_num_views()*this->output_proj_data_sptr->get_num_axial_poss(0)*this->output_proj_data_sptr->get_num_tangential_poss(); //TODO: the code is for segment zero only std::vector > jacobian_array; std::vector ratio; - jacobian_array.reserve(lenght); - ratio.reserve(lenght); - for (int i = 0 ; i <= lenght ; ++i) + jacobian_array.reserve(length); + ratio.reserve(length); + for (int i = 0 ; i < length ; ++i) { jacobian_array.push_back(gradient_image_LR); ratio.push_back(0); } - get_jacobian(jacobian_array, compute_gradient, isgradient_mu); - const ProjDataInMemory est_data_LR = *(this->output_proj_data_sptr); - get_ratio(projdata,add_projdata,est_data_LR,ratio); + const ProjDataInMemory est_data_LR = get_jacobian(jacobian_array, compute_gradient, isgradient_mu); + const ProjDataInMemory est_data_HR = get_ratio(projdata,add_projdata,est_data_LR,ratio); - for (int i = 0 ; i <= lenght ; ++i) + for (int i = 0 ; i < length ; ++i) { gradient_image_LR += jacobian_array[i]*ratio[i]; } @@ -797,17 +796,17 @@ likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_pr } - ProjDataInMemory est_data_HR = *(this->HR_output_proj_data_sptr); return est_data_HR; } -void +ProjDataInMemory SingleScatterLikelihoodAndGradient:: get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu) { - this->output_proj_data_sptr->fill(0.f); + ProjDataInMemory est_data(this->get_output_proj_data_sptr()->get_exam_info_sptr(),this->get_output_proj_data_sptr()->get_proj_data_info_sptr()); + est_data.fill(0); this->remove_cache_for_integrals_over_activity(); this->remove_cache_for_integrals_over_attenuation(); @@ -868,7 +867,7 @@ get_jacobian(std::vector > &gradient_image_array,co //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - this->get_jacobian_for_view_segment_number(gradient_image_array,vs_num,compute_gradient,isgradient_mu); + this->get_jacobian_for_view_segment_number(gradient_image_array,est_data,vs_num,compute_gradient,isgradient_mu); bin_counter += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * @@ -879,18 +878,17 @@ get_jacobian(std::vector > &gradient_image_array,co } } - +return est_data; } void SingleScatterLikelihoodAndGradient:: -get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) +get_jacobian_for_view_segment_number(std::vector > &gradient_image_array, ProjData &est_data, const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu) { - Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); - + Viewgram v_est = est_data.get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); get_jacobian_for_viewgram(v_est,gradient_image_array, compute_gradient,isgradient_mu); - output_proj_data_sptr->set_viewgram(v_est); + est_data.set_viewgram(v_est); } @@ -921,7 +919,8 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector(all_bins.size())*this->output_proj_data_sptr->get_num_views()) + error("SIZE is %d , but it should be %d",gradient_image_array.size(),static_cast(all_bins.size())); VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); @@ -932,6 +931,7 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector& v_est,std::vector &ratio_vector) { - this->HR_output_proj_data_sptr.reset(new ProjDataInMemory(projdata.get_exam_info_sptr(),projdata.get_proj_data_info_sptr()->create_shared_clone())); - ProjDataInMemory ratio_HR(projdata); - ProjDataInMemory est_projdata_HR(projdata); - ProjDataInMemory ratio_LR(est_projdata); + ProjDataInMemory ratio_HR(projdata); ratio_HR.fill(0); + ProjDataInMemory est_projdata_HR(projdata); est_projdata_HR.fill(0); + ProjDataInMemory ratio_LR(est_projdata); ratio_LR.fill(0); if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,true); @@ -965,7 +964,6 @@ get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData Sinogram add_sino = add_projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); Sinogram est_sino = est_projdata_HR.get_sinogram(bin.axial_pos_num(),bin.segment_num()); Sinogram ratio_sino = ratio_HR.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); - this->HR_output_proj_data_sptr->set_sinogram(est_sino); for (bin.view_num()=sino.get_min_view_num(); bin.view_num()<=sino.get_max_view_num(); @@ -985,6 +983,7 @@ get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData ratio_LR.fill(ratio_HR); ViewSegmentNumbers vs_num; + int counter = 0; for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) { @@ -992,9 +991,6 @@ get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData { Viewgram viewgram = ratio_LR.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - //Viewgram v_add = add_sino.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - //Viewgram v_est = est_data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); std::vector all_bins; { @@ -1010,6 +1006,7 @@ get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData for (int i = 0; i < static_cast(all_bins.size()); ++i) { + ++ counter; const Bin bin = all_bins[i]; @@ -1019,7 +1016,9 @@ get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData } } - + if(ratio_vector.size()!=counter) + error("SIZE is %d , but it should be %d",ratio_vector.size(),counter); +return est_projdata_HR; } END_NAMESPACE_STIR From d6b07dee3019695d80d429176bee461428c2be35 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 10 Aug 2019 12:22:39 +0100 Subject: [PATCH 166/274] hardcoded for low thres --- src/listmode_buildblock/CListModeDataROOT.cxx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 8dfa3c7e67..f64c3d6b5b 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -93,7 +93,15 @@ CListModeDataROOT(const std::string& hroot_filename) val[1]=1;} else if(this->root_file_sptr->get_low_energy_thres_in_keV()[1]==this->root_file_sptr->get_low_energy_thres_in_keV()[0]) {val[0]=1; - val[1]=1;} + val[1]=1; + if(this->exam_info_sptr->get_num_energy_windows() > 1) + {std::vector low_t = this->root_file_sptr->get_low_energy_thres_in_keV(); + std::vector up_t = this->root_file_sptr->get_up_energy_thres_in_keV(); + low_t[1]=350; + up_t[1]=460; + this->exam_info_sptr->set_low_energy_thres_vect(low_t); + this->exam_info_sptr->set_high_energy_thres_vect(up_t);} + } this->exam_info_sptr->set_energy_window_pair(val,1); From 6c6f13fc40fc1b4b430610f7aa39144fbfece651 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 10 Aug 2019 13:46:26 +0100 Subject: [PATCH 167/274] energy --- src/include/stir/ExamInfo.h | 4 ++-- src/include/stir/ExamInfo.inl | 8 ++++---- src/listmode_buildblock/CListModeDataROOT.cxx | 8 +++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index a9057dc0a6..a14f81604b 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -115,8 +115,8 @@ public : //! Set the number of energy windows inline void set_num_energy_windows(int n_win); inline void set_energy_window_pair(std::vector val,int n_win); - inline void set_low_energy_thres_vect(std::vector new_val); - inline void set_high_energy_thres_vect(std::vector new_val); + inline void set_low_energy_thres_vect(std::vector new_val,bool switch_energy = false); + inline void set_high_energy_thres_vect(std::vector new_val,bool switch_energy = false); //@} //! Standard trick for a 'virtual copy-constructor' diff --git a/src/include/stir/ExamInfo.inl b/src/include/stir/ExamInfo.inl index 10092c35ce..e7af9642a5 100644 --- a/src/include/stir/ExamInfo.inl +++ b/src/include/stir/ExamInfo.inl @@ -53,13 +53,13 @@ ExamInfo::set_high_energy_thres(float new_val,int en_window) } void -ExamInfo::set_low_energy_thres_vect(std::vector new_val) +ExamInfo::set_low_energy_thres_vect(std::vector new_val, bool switch_energy) { low_energy_thres = new_val; //TODO extend to the case of more than two //Decrescent ordering - if (new_val[0] new_val) } void -ExamInfo::set_high_energy_thres_vect(std::vector new_val) +ExamInfo::set_high_energy_thres_vect(std::vector new_val, bool switch_energy) { up_energy_thres = new_val; //TODO extend to the case of more than two //Decrescent ordering - if (new_val[0]root_file_sptr->get_low_energy_thres_in_keV()[0]>this->root_file_sptr->get_low_energy_thres_in_keV()[1]) {val[0]=1; val[1]=2;} - else if(this->root_file_sptr->get_low_energy_thres_in_keV()[1]>this->root_file_sptr->get_low_energy_thres_in_keV()[0]) + else if(this->root_file_sptr->get_low_energy_thres_in_keV()[0]root_file_sptr->get_low_energy_thres_in_keV()[1]) {val[0]=2; - val[1]=1;} - else if(this->root_file_sptr->get_low_energy_thres_in_keV()[1]==this->root_file_sptr->get_low_energy_thres_in_keV()[0]) + val[1]=1; + this->exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres_in_keV(),true); + this->exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres_in_keV(),true);} + else if(this->root_file_sptr->get_low_energy_thres_in_keV()[0]==this->root_file_sptr->get_low_energy_thres_in_keV()[1]) {val[0]=1; val[1]=1; if(this->exam_info_sptr->get_num_energy_windows() > 1) From d42254230d6465f1598a15c1dd9fe6bb09d73a47 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 23 Aug 2019 12:21:31 +0100 Subject: [PATCH 168/274] scatter sim --- src/IO/interfile.cxx | 2 +- src/include/stir/ExamInfo.h | 8 +- src/include/stir/scatter/ScatterSimulation.h | 4 +- .../scatter_detection_modelling.cxx | 4 +- src/utilities/find_ML_normfactors.cxx | 80 ++++++++++++++----- 5 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/IO/interfile.cxx b/src/IO/interfile.cxx index 800f3aa0a5..d4f67748c2 100644 --- a/src/IO/interfile.cxx +++ b/src/IO/interfile.cxx @@ -479,7 +479,7 @@ static void write_interfile_energy_windows(std::ostream& output_header, const Ex else { // need to write this anyway to allow vectored keys below - output_header <<"number of energy windows := 1"; + //output_header <<"number of energy windows := 1"; } //Write energy window thresholds diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index a14f81604b..615ffd60ba 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -59,14 +59,12 @@ public : : start_time_in_secs_since_1970(0.) { - num_windows = 2; - low_energy_thres.resize(num_windows); - up_energy_thres.resize(num_windows); + num_windows = -1; + low_energy_thres.resize(1); + up_energy_thres.resize(1); en_win_pair.resize(2); low_energy_thres[0]=-1.F; up_energy_thres[0]=-1.F; - low_energy_thres[0]=1.F; - up_energy_thres[0]=1.F; en_win_pair[0]=-1.F; en_win_pair[1]=-1.F; diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 149d04b218..06f96968ee 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,8 +211,8 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency(const float energy, const int en_window = 0) const; - float detection_efficiency_full(const float incoming_photon_energy, const int en_window = 0) const; + float detection_efficiency_gaussian(const float energy, const int en_window = 0) const; + float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; std::vector detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index fce7efd89c..bb7acf8e57 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -98,7 +98,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy, const int en_window) const +detection_efficiency_gaussian(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -140,7 +140,7 @@ ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const } float -ScatterSimulation::detection_efficiency_full(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); diff --git a/src/utilities/find_ML_normfactors.cxx b/src/utilities/find_ML_normfactors.cxx index 66377506dc..f37948f98c 100644 --- a/src/utilities/find_ML_normfactors.cxx +++ b/src/utilities/find_ML_normfactors.cxx @@ -104,20 +104,57 @@ void check_geo_data() END_NAMESPACE_STIR +static void print_usage_and_exit(const std::string& program_name) +{ + std::cerr<<"Usage: " << program_name << " [--display | --print-KL | --include-block-timing-model] \\\n" + << " out_filename_prefix measured_data model num_iterations num_eff_iterations\n" + << " set num_iterations to 0 to do only efficiencies\n"; + exit(EXIT_FAILURE); +} + + USING_NAMESPACE_STIR int main(int argc, char **argv) -{ +{ + const char * const program_name = argv[0]; + // skip program name + --argc; + ++argv; + //check_geo_data(); + bool do_display = false; + bool do_KL = false; + bool do_block = false; + + // first process command line options + while (argc>0 && argv[0][0]=='-' && argc>=1) + { + if (strcmp(argv[0], "--display")==0) + { + do_display = true; + --argc; ++argv; + } + else if (strcmp(argv[0], "--print-KL")==0) + { + do_KL = true; + --argc; ++argv; + } + else if (strcmp(argv[0], "--include-block-timing-model")==0) + { + do_block = true; + --argc; ++argv; + } + else + print_usage_and_exit(program_name); + } + // go back to previous counts such that we don't have to change code below + ++argc; --argv; + if (argc!=6) { - std::cerr << "Usage: " << argv[0] - << " out_filename_prefix measured_data model num_iterations num_eff_iterations\n" - << " set num_iterations to 0 to do only efficiencies\n"; - return EXIT_FAILURE; + print_usage_and_exit(program_name); } - const bool do_display = ask("Display",false); - const bool do_KL = ask("Compute KL distances?",false); const int num_eff_iterations = atoi(argv[5]); const int num_iterations = atoi(argv[4]); shared_ptr model_data = ProjData::read_from_file(argv[3]); @@ -271,17 +308,20 @@ int main(int argc, char **argv) } // block norm { - det_pair_data = model_det_pair_data; - apply_efficiencies(det_pair_data, efficiencies); - apply_geo_norm(det_pair_data, norm_geo_data); - iterate_block_norm(norm_block_data, measured_block_data, det_pair_data); - { // check - for (int a=0; a Date: Fri, 23 Aug 2019 16:35:57 +0100 Subject: [PATCH 169/274] unit test ok with efficiency --- src/include/stir/scatter/ScatterSimulation.h | 4 ++-- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 06f96968ee..5f24ce9c8a 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,8 +211,8 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_gaussian(const float energy, const int en_window = 0) const; - float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; + float detection_efficiency(const float energy, const int en_window = 0) const; + float detection_efficiency2(const float incoming_photon_energy, const int en_window = 0) const; std::vector detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index bb7acf8e57..bd310b591c 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -98,7 +98,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency_gaussian(const float energy, const int en_window) const +detection_efficiency(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -140,7 +140,7 @@ ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const } float -ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency2(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); From 90d0f1f3dc80f44b78ca66c37a008d147cff7bdb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 24 Aug 2019 19:33:23 +0100 Subject: [PATCH 170/274] added normalisation --- src/include/stir/scatter/ScatterEstimation.h | 18 +++++ .../SingleScatterLikelihoodAndGradient.h | 4 +- .../SingleScatterLikelihoodAndGradient.cxx | 10 +-- .../upsample_and_fit_scatter_estimate.cxx | 77 +++++++++++++++++++ src/test/test_upsample.cxx | 13 +++- 5 files changed, 111 insertions(+), 11 deletions(-) diff --git a/src/include/stir/scatter/ScatterEstimation.h b/src/include/stir/scatter/ScatterEstimation.h index f07b6d7bf1..bd0bd47aa9 100644 --- a/src/include/stir/scatter/ScatterEstimation.h +++ b/src/include/stir/scatter/ScatterEstimation.h @@ -110,6 +110,24 @@ class ScatterEstimation: public ParsingObject const ProjData& emission_proj_data, const ProjData& scatter_proj_data, const bool remove_interleaving = true); + + static void + pull_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const ProjData& norm, + const bool remove_interleaving=true); + + static void + push_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const ProjData& norm, + const bool remove_interleaving=true); + + static void + apply_norm(ProjData& projdata,const ProjData& norm); + //! Default constructor (calls set_defaults()) ScatterEstimation(); diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index 9476d8f57a..e7bc198888 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -65,9 +65,9 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); - ProjDataInMemory likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); + ProjDataInMemory likelihood_and_gradient_scatter(const ProjData &projdata,const ProjData& norm, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); ProjDataInMemory get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); - ProjDataInMemory get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector); + ProjDataInMemory get_ratio(const ProjData& projdata,const ProjData& norm,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector); protected: void diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 3c9e5d4254..25411d905b 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -764,7 +764,7 @@ L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesia ProjDataInMemory SingleScatterLikelihoodAndGradient:: -likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) +likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData& norm , const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) { gradient_image_LR.fill(0); gradient_image_HR.fill(0); @@ -780,7 +780,7 @@ likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData &add_pr } const ProjDataInMemory est_data_LR = get_jacobian(jacobian_array, compute_gradient, isgradient_mu); - const ProjDataInMemory est_data_HR = get_ratio(projdata,add_projdata,est_data_LR,ratio); + const ProjDataInMemory est_data_HR = get_ratio(projdata,norm,add_projdata,est_data_LR,ratio); for (int i = 0 ; i < length ; ++i) { @@ -943,7 +943,7 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector &ratio_vector) +get_ratio(const ProjData& projdata,const ProjData& norm,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector) { ProjDataInMemory ratio_HR(projdata); ratio_HR.fill(0); @@ -951,7 +951,7 @@ get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData ProjDataInMemory ratio_LR(est_projdata); ratio_LR.fill(0); if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,true); + ScatterEstimation::pull_scatter_estimate(est_projdata_HR,projdata,est_projdata,norm,true); else est_projdata_HR.fill(est_projdata); @@ -978,7 +978,7 @@ get_ratio(const ProjData& projdata,const ProjData &add_projdata, const ProjData } if((est_projdata.get_num_views()!=projdata.get_num_views())||(est_projdata.get_num_tangential_poss()!=projdata.get_num_tangential_poss())) - ScatterEstimation::push_scatter_estimate(ratio_LR,est_projdata,ratio_HR,true); + ScatterEstimation::push_scatter_estimate(ratio_LR,est_projdata,ratio_HR,norm,true); else ratio_LR.fill(ratio_HR); diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 275e4ba2d5..2d8a1da057 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -193,4 +193,81 @@ push_scatter_estimate(ProjData& scaled_scatter_proj_data, } +void +ScatterEstimation:: +pull_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const ProjData& norm, + const bool remove_interleaving) +{ + + shared_ptr interpolated_direct_scatter_proj_data_info_sptr(emission_proj_data.get_proj_data_info_ptr()->clone()); + interpolated_direct_scatter_proj_data_info_sptr->reduce_segment_range(0,0); //create the output template + + + info("upsample_and_fit_scatter_estimate: Interpolating scatter estimate to size of emission data"); + ProjDataInMemory interpolated_direct_scatter(emission_proj_data.get_exam_info_sptr(), + interpolated_direct_scatter_proj_data_info_sptr); + + // interpolate projdata + interpolate_projdata_pull(interpolated_direct_scatter, scatter_proj_data, remove_interleaving); + + // Perform Inverse Single Slice Rebinning + inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); + + apply_norm(scaled_scatter_proj_data,norm); + +} + +void +ScatterEstimation:: +push_scatter_estimate(ProjData& scaled_scatter_proj_data, + const ProjData& emission_proj_data, + const ProjData& scatter_proj_data, + const ProjData& norm, + const bool remove_interleaving) +{ + + ProjDataInMemory scatter_proj_data_in_memory(scatter_proj_data); + apply_norm(scatter_proj_data_in_memory,norm); + + shared_ptr new_input_proj_data_info_sptr(scatter_proj_data_in_memory.get_proj_data_info_ptr()->clone()); + new_input_proj_data_info_sptr->reduce_segment_range(0,0); //create input template + + ProjDataInMemory new_input(scatter_proj_data_in_memory.get_exam_info_sptr(),new_input_proj_data_info_sptr); + + transpose_inverse_SSRB(new_input, scatter_proj_data_in_memory); + + + interpolate_projdata_push(scaled_scatter_proj_data, new_input, remove_interleaving); + + +} + +void +ScatterEstimation:: +apply_norm(ProjData& projdata,const ProjData& norm) +{ +Bin bin; +{ + for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) + for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) + { + Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + Sinogram norm_sino = norm.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + + for (bin.view_num()=sino.get_min_view_num(); + bin.view_num()<=sino.get_max_view_num(); + ++bin.view_num()) + { + for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + sino[bin.view_num()][bin.tangential_pos_num()] *= norm_sino[bin.axial_pos_num()][bin.tangential_pos_num()]; + projdata.set_sinogram(sino); + } + + } + } + +} END_NAMESPACE_STIR diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index 24dbca42b4..c650615eae 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -136,22 +136,27 @@ run_tests() // construct x ProjDataInMemory Aty(sss->get_ExamInfo_sptr(), sss->get_template_proj_data_info_sptr()); + ProjDataInMemory N(exam_info_sptr, proj_data_info_sptr); + fill_projdata_with_random(x); fill_projdata_with_random(y); Ax.fill(0); //initialise output Aty.fill(0); //initialise output + //N.fill(10); + fill_projdata_with_random(N); + bool remove_interleaving = false; std::cout << "========== REMOVE INTERLEAVING = FALSE =========== \n"; std::cout << "-------- Testing Pull --------\n"; - ScatterEstimation::pull_scatter_estimate(Ax,y,x,remove_interleaving); + ScatterEstimation::pull_scatter_estimate(Ax,y,x,N,remove_interleaving); std::cout << "-------- Testing Push --------\n"; - ScatterEstimation::push_scatter_estimate(Aty,x,y,remove_interleaving); + ScatterEstimation::push_scatter_estimate(Aty,x,y,N,remove_interleaving); std::cout << "-------- = --------\n"; @@ -207,11 +212,11 @@ run_tests() remove_interleaving = true; std::cout << "-------- Testing Pull --------\n"; - ScatterEstimation::pull_scatter_estimate(Ax,y,x,remove_interleaving); + ScatterEstimation::pull_scatter_estimate(Ax,y,x,N,remove_interleaving); std::cout << "-------- Testing Push --------\n"; - ScatterEstimation::push_scatter_estimate(Aty,x,y,remove_interleaving); + ScatterEstimation::push_scatter_estimate(Aty,x,y,N,remove_interleaving); std::cout << "-------- = --------\n"; From 37177f5853671baa1d278f62ea01ee04071b643c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 27 Aug 2019 12:00:39 +0100 Subject: [PATCH 171/274] fixed bug in norm --- .../upsample_and_fit_scatter_estimate.cxx | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 2d8a1da057..831cadd58d 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -27,6 +27,8 @@ #include "stir/ProjDataInfo.h" #include "stir/ExamInfo.h" #include "stir/ProjDataInMemory.h" +#include "stir/ViewSegmentNumbers.h" +#include "stir/Viewgram.h" #include "stir/inverse_SSRB.h" #include "stir/scale_sinograms.h" #include "stir/scatter/ScatterEstimation.h" @@ -216,7 +218,7 @@ pull_scatter_estimate(ProjData& scaled_scatter_proj_data, // Perform Inverse Single Slice Rebinning inverse_SSRB(scaled_scatter_proj_data, interpolated_direct_scatter); - apply_norm(scaled_scatter_proj_data,norm); + apply_norm(scaled_scatter_proj_data,norm); } @@ -249,25 +251,49 @@ void ScatterEstimation:: apply_norm(ProjData& projdata,const ProjData& norm) { -Bin bin; + +if((projdata.get_num_views()!=norm.get_num_views())||(projdata.get_num_tangential_poss()!=norm.get_num_tangential_poss())) + error("sinograms have to have the same dimensions"); +ProjDataInMemory projdata_out(projdata); +projdata_out.fill(0); + +ViewSegmentNumbers vs_num; + +for (vs_num.segment_num() = norm.get_min_segment_num(); vs_num.segment_num() <= norm.get_max_segment_num(); ++vs_num.segment_num()) { - for (bin.segment_num()=projdata.get_min_segment_num(); bin.segment_num()<=projdata.get_max_segment_num(); ++bin.segment_num()) - for (bin.axial_pos_num() = projdata.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num()<=projdata.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) - { - Sinogram sino = projdata.get_sinogram(bin.axial_pos_num(),bin.segment_num()); - Sinogram norm_sino = norm.get_sinogram(bin.axial_pos_num(),bin.segment_num()); + for (vs_num.view_num() = norm.get_min_view_num();vs_num.view_num() <= norm.get_max_view_num(); ++vs_num.view_num()) + { - for (bin.view_num()=sino.get_min_view_num(); - bin.view_num()<=sino.get_max_view_num(); - ++bin.view_num()) + Viewgram viewgram_n = norm.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + Viewgram viewgram_in = projdata.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + Viewgram viewgram_out = projdata_out.get_empty_viewgram(vs_num.view_num(), vs_num.segment_num(),false); + const ViewSegmentNumbers vs_num(viewgram_n.get_view_num(),viewgram_n.get_segment_num()); + std::vector all_bins; + { + Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); + for (bin.axial_pos_num() = norm.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num() <= norm.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) { - for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - sino[bin.view_num()][bin.tangential_pos_num()] *= norm_sino[bin.axial_pos_num()][bin.tangential_pos_num()]; - projdata.set_sinogram(sino); - } + for (bin.tangential_pos_num() = norm.get_min_tangential_pos_num(); bin.tangential_pos_num() <= norm.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) + { + all_bins.push_back(bin); + } + } + } + + for (int i = 0; i < static_cast(all_bins.size()); ++i) + { + + const Bin bin = all_bins[i]; + + viewgram_out[bin.axial_pos_num()][bin.tangential_pos_num()]=viewgram_in[bin.axial_pos_num()][bin.tangential_pos_num()]*viewgram_n[bin.axial_pos_num()][bin.tangential_pos_num()]; + } + + projdata_out.set_viewgram(viewgram_out); - } } +} + +projdata.fill(projdata_out); } END_NAMESPACE_STIR From 3faf7873a1ac2864ae9d26e4b73478a56cebe97c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 27 Aug 2019 21:19:22 +0100 Subject: [PATCH 172/274] mathematica --- src/include/stir/scatter/ScatterSimulation.h | 9 +- .../scatter_detection_modelling.cxx | 94 ++++++++++++++++--- 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 5f24ce9c8a..7d13661391 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -213,12 +213,17 @@ class ScatterSimulation : public RegisteredObject, float detection_efficiency(const float energy, const int en_window = 0) const; float detection_efficiency2(const float incoming_photon_energy, const int en_window = 0) const; + float detection_efficiency3(const float incoming_photon_energy, const int en_window = 0) const; std::vector detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; - float detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const; + float detection_model_with_fitted_parameters(const float x, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; - float compton_plateau(const float K, const float std_peak, const float x, const float energy, const float theta, const float scaling_std_compton,const float shift_compton) const; + float compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const; float flat_continuum(const float K, const float std_peak, const float x, const float energy) const; float exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const; + float integral_photoelectric(const float LT, const float HT, const float FWHM, const float energy) const; + float integral_compton_plateau(const float LT, const float HT, const float FWHM, const float energy) const; + float integral_flat_continuum(const float LT, const float HT, const float FWHM, const float energy) const; + float integral_exponential_tail(const float LT, const float HT, const float FWHM, const float energy) const; Succeeded downsample_scanner(int new_num_rings = -1, int new_num_dets = -1); protected: diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index bd310b591c..9fbf1dc7ad 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -122,18 +122,15 @@ ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const std::vector energy_range(size); std::vector out(size); float increment_x = (HLD - LLD)/size; - float increment_theta = (2*M_PI)/size; - std::vector theta(size); for(int i = 0 ; i< size; ++i) { energy_range[i]+= LLD+i*increment_x; - theta[i]+=i*increment_theta; out[i]+=0; } for(int j = 0; j < size; ++j) { - out[j]+= detection_model_with_fitted_parameters(energy_range[j], theta[j], incoming_photon_energy); + out[j]+= detection_model_with_fitted_parameters(energy_range[j], incoming_photon_energy); } return out; @@ -141,6 +138,20 @@ ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const float ScatterSimulation::detection_efficiency2(const float incoming_photon_energy, const int en_window) const +{ + + const float HT = this->template_exam_info_sptr->get_high_energy_thres(en_window); + const float LT = this->template_exam_info_sptr->get_low_energy_thres(en_window); + const float FWHM = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); + const float f1 = integral_photoelectric(LT,HT, FWHM, incoming_photon_energy) ; + const float f2 = integral_compton_plateau(LT,HT, FWHM, incoming_photon_energy) ; + const float f3 = integral_flat_continuum(LT,HT, FWHM, incoming_photon_energy) ; + const float f4 = integral_exponential_tail(LT,HT, FWHM, incoming_photon_energy) ; + return f1+f2+f3+f4; + } + +float +ScatterSimulation::detection_efficiency3(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); @@ -148,21 +159,20 @@ ScatterSimulation::detection_efficiency2(const float incoming_photon_energy, con float sum = 0; const int size = HLD-LLD; const float increment_x = (HLD - LLD)/size; - const float increment_theta = (2*M_PI)/size; for(int i = 0 ; i< size; ++i) { const float energy_range = LLD+i*increment_x; - const float theta=i*increment_theta; - sum+= detection_model_with_fitted_parameters(energy_range, theta, incoming_photon_energy); + sum+= detection_model_with_fitted_parameters(energy_range, incoming_photon_energy); } sum*=increment_x; return sum; } + float ScatterSimulation:: -detection_model_with_fitted_parameters(const float x, const float theta, const float energy) const +detection_model_with_fitted_parameters(const float x, const float energy) const { //! Brief //! All the parameters are obtained by fitting the model to the energy spectrum obtained with GATE. @@ -172,17 +182,17 @@ detection_model_with_fitted_parameters(const float x, const float theta, const f const int Z = 66; // atomic number of LSO const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section - const float H_2 = 9.27*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section + const float H_2 = 9.40*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section const float H_3 = 7; //fitting parameter const float H_4 = 26.0; //fitting parameter const float beta = -0.817; //fitting parameter const float global_scale = 2.33*1e-07; //fitting parameter const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); const float std_peak = energy*fwhm/2.35482; - const float scaling_std_compton = 28.8; //fitting parameter - const float shift_compton = 0.6; //fitting parameter + const float scaling_std_compton = 29.6; //fitting parameter + const float shift_compton = 0.598; //fitting parameter const float f1 = photoelectric(H_1, std_peak, x, energy); - const float f2 = compton_plateau(H_2, std_peak, x, energy,theta, scaling_std_compton,shift_compton); + const float f2 = compton_plateau(H_2, std_peak, x, energy, scaling_std_compton,shift_compton); const float f3 = flat_continuum(H_3,std_peak, x, energy); const float f4 = exponential_tail(H_4,std_peak, x, energy,beta); @@ -201,13 +211,13 @@ photoelectric(const float K, const float std_peak, const float x, const float en float ScatterSimulation:: -compton_plateau(const float K, const float std_peak, const float x, const float energy, const float theta, const float scaling_std_compton,const float shift_compton) const +compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const { const float m_0_c_2 = 511.F; const float alpha = energy/m_0_c_2; - const float E_1 = energy/(1+alpha*(1-cos(theta))); + const float E_1 = energy/(1+alpha*(1-cos(M_PI))); const float mean = energy*shift_compton; - return ((energy/E_1)+(E_1/energy)-1+cos(theta))*(K*exp(-(pow((x - mean),2))/(4*scaling_std_compton*std_peak))); + return ((energy/E_1)+(E_1/energy)-1+cos(M_PI))*(K*exp(-(pow((x - mean),2))/(4*scaling_std_compton*std_peak))); } float ScatterSimulation:: @@ -237,6 +247,60 @@ exponential_tail(const float K, const float std_peak, const float x, const float return f; } +float +ScatterSimulation:: +integral_photoelectric(const float LT, const float HT, const float FWHM, const float energy) const +{ +const float den = energy; +const float num = -145.897*erf((1.66511*(energy -HT))/(energy*FWHM))+145.897*erf((1.66511*abs((energy -LT)))/(energy*FWHM)); + return num/den; +} + +float +ScatterSimulation:: +integral_compton_plateau(const float LT, const float HT, const float FWHM, const float energy) const +{ +const float a = pow((255.5+energy),3); +const float b = sqrt(energy*FWHM); +const float fact1 = 1/(a*b)*FWHM; +const float fact2a = 8.88178*1e-16*erf(0.0832061*sqrt(energy/FWHM)); +const float fact2b = -6.28408*erf((0.0832061*energy-0.141027*HT)/sqrt(energy*FWHM)); +const float fact2c = ((0.522874*energy-0.886227*LT)*erf((0.0832061*abs(energy-1.69492*LT))/(sqrt(energy*FWHM))))/(abs(0.0832061*energy-0.141027*LT)); +const float fact2 = fact2a+fact2b+fact2c; +const float fact3 = (energy*(96199.6+energy*(753.03+(1.65785+0.00036048*energy)*energy)) + + (-2.4579*1e07+energy*(-240499+energy*(-705.966+(-0.36841+0.000720959*energy)*energy)))*log(1+0.00391389*energy)); + +return fact1*fact2*fact3; +} + +float +ScatterSimulation:: +integral_flat_continuum(const float LT, const float HT, const float FWHM, const float energy) const +{ + const float num1 = pow((energy-LT),2); + const float den1 = pow((energy*FWHM),2); + const float fact1 = -5.52632*1e-07+5.52632*1e-07*exp(-(2.77259*num1)/(den1))*energy*FWHM; + const float fact2 = 1.631*1e-06*energy-1.631*1e-06*LT; + const float fact3 = erfc((1.66511*(-energy*LT))/(energy*FWHM)); + return fact1 + fact2*fact3; +} + +float +ScatterSimulation:: +integral_exponential_tail(const float LT, const float HT, const float FWHM, const float energy) const +{ +const float fact1 = 6.058*1e-06*exp(0.64874/FWHM)*energy*FWHM; +const float fact2 = -1.26141*exp(-0.64874/FWHM)*erf(0.417191+(1.66511-(1.66511*LT)/(energy))/FWHM); +const float fact3 = 1.26141*exp(-0.64874/FWHM)*erf(0.417191+(1.66511-(1.66511*HT)/(energy))/FWHM); +const float fact4 = 1.54145*exp(-0.64874*LT/(energy*FWHM))*erfc(-0.611995+(-1.66511+(1.66511*LT)/(energy))/FWHM); +const float fact5 = -1.54145*exp(-0.64874*HT/(energy*FWHM))*erfc(-0.611995+(-1.66511+(1.66511*HT)/(energy))/FWHM); +if (energy<100) + return 0; +else + return fact1*(fact2+fact3+fact4+fact5); +} + + float ScatterSimulation:: max_cos_angle(const float low, const float approx, const float resolution_at_511keV) From 107335c400cb7b1055f9ed7ae500e65d74da9b10 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 27 Aug 2019 22:08:11 +0100 Subject: [PATCH 173/274] efficiency mathematica --- src/include/stir/scatter/ScatterSimulation.h | 4 ++-- src/scatter_buildblock/ScatterSimulation.cxx | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 7d13661391..89b913cd2b 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,8 +211,8 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency(const float energy, const int en_window = 0) const; - float detection_efficiency2(const float incoming_photon_energy, const int en_window = 0) const; + float detection_efficiency2(const float energy, const int en_window = 0) const; + float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency3(const float incoming_photon_energy, const int en_window = 0) const; std::vector detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float energy) const; diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 972805fcc8..f69f170aa0 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -35,6 +35,7 @@ #include "stir/error.h" #include #include +#include #include "stir/zoom.h" #include "stir/SSRB.h" @@ -59,6 +60,9 @@ Succeeded ScatterSimulation:: process_data() { + + time_t tstart, tend; + tstart = time(0); // this is usefull in the scatter estimation process. this->output_proj_data_sptr->fill(0.f); //show energy window information @@ -169,6 +173,8 @@ process_data() std::cout << "TOTAL SCATTER:= " << total_scatter << '\n'; + tend = time(0); + cout << "ELAPSED TIME: "<< difftime(1000*tend, 1000*tstart) <<" [ms]."<< endl; return Succeeded::yes; } From 5043f17d3069d7f08217d4517505b5b3ce2ee822 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 28 Aug 2019 19:07:47 +0100 Subject: [PATCH 174/274] ssrb --- src/buildblock/inverse_SSRB.cxx | 19 ++++++++++++++----- src/test/test_SSRB.cxx | 11 ++++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 176694d3be..27e5f3e543 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -133,12 +133,15 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, // keep sinograms out of the loop to avoid reallocations. initialise to something because there's no default constructor Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); + Sinogram sino_3D2 = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); + Sinogram sino_3D3 = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) { sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); + sino_3D3 = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); @@ -152,25 +155,31 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); const float in_m = proj_data_4D_info_ptr->get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); - const float in_m_prev = in_ax_pos_num == proj_data_4D.get_max_axial_pos_num(in_segment_num) ? - -1000000.F : proj_data_4D_info_ptr->get_m(Bin(-in_segment_num, 0, out_ax_pos_num+in_segment_num, 0)); if (fabs(out_m - in_m) < 1E-2) { sino_3D += sino_4D; } + if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { - sino_4D *= .5F; - sino_3D += sino_4D; + for (int out_reaching = out_ax_pos_num; out_reaching <= proj_data_3D.get_max_axial_pos_num(0); ++out_reaching ) + { + sino_3D2 = proj_data_3D.get_empty_sinogram(out_reaching, 0); + sino_4D *= .5F; + sino_3D += sino_4D; + sino_3D2 += sino_4D; } } } - proj_data_3D.set_sinogram(sino_3D); + } + + sino_3D3 += sino_3D+sino_3D2; + proj_data_3D.set_sinogram(sino_3D3); } diff --git a/src/test/test_SSRB.cxx b/src/test/test_SSRB.cxx index 63e5394929..1c65e8e838 100644 --- a/src/test/test_SSRB.cxx +++ b/src/test/test_SSRB.cxx @@ -42,6 +42,7 @@ #include "stir/IO/write_to_file.h" +#include START_NAMESPACE_STIR @@ -58,6 +59,10 @@ void SSRBTests:: fill_projdata_with_random(ProjData & projdata) { + + std::random_device random_device; + std::mt19937 random_number_generator(random_device()); + std::uniform_real_distribution number_distribution(0,10); Bin bin; { for (bin.segment_num()=projdata.get_min_segment_num(); @@ -80,7 +85,7 @@ fill_projdata_with_random(ProjData & projdata) bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - sino[bin.view_num()][bin.tangential_pos_num()]= rand()%10;//((double) rand() / (1)) + 1; + sino[bin.view_num()][bin.tangential_pos_num()]= number_distribution(random_number_generator); projdata.set_sinogram(sino); @@ -101,7 +106,7 @@ run_tests() shared_ptr scanner_sptr(new Scanner(Scanner::Siemens_mMR)); //creating proj data info - shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); + shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 2,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr exam_info_sptr_4D(new ExamInfo); ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); @@ -168,7 +173,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.02); + set_tolerance(0.04); check_if_equal(cdot1, cdot2, "test adjoint"); From 872dcc445839dd04e6446a45cffdcff17c7f296a Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 28 Aug 2019 22:21:43 +0100 Subject: [PATCH 175/274] set sino --- src/buildblock/inverse_SSRB.cxx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 27e5f3e543..b53a184115 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -134,16 +134,12 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, // keep sinograms out of the loop to avoid reallocations. initialise to something because there's no default constructor Sinogram sino_3D = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); Sinogram sino_3D2 = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); - Sinogram sino_3D3 = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) { sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); - sino_3D3 = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); - - const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); @@ -164,11 +160,13 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { - for (int out_reaching = out_ax_pos_num; out_reaching <= proj_data_3D.get_max_axial_pos_num(0); ++out_reaching ) + + int out_reaching = out_ax_pos_num +1; + for (out_reaching; out_reaching <= proj_data_3D.get_max_axial_pos_num(0); ++out_reaching ) { - sino_3D2 = proj_data_3D.get_empty_sinogram(out_reaching, 0); sino_4D *= .5F; sino_3D += sino_4D; + sino_3D2 = proj_data_3D.get_empty_sinogram(out_reaching, 0); sino_3D2 += sino_4D; } @@ -178,8 +176,8 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, } - sino_3D3 += sino_3D+sino_3D2; - proj_data_3D.set_sinogram(sino_3D3); + proj_data_3D.set_sinogram(sino_3D); + proj_data_3D.set_sinogram(sino_3D2); } From 97fa9dcb73641b82b0c93917be5af723b49fe0d6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 29 Aug 2019 12:36:51 +0100 Subject: [PATCH 176/274] ssrb2 --- src/buildblock/inverse_SSRB.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index b53a184115..71e0bc6c9c 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -161,12 +161,12 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) { - int out_reaching = out_ax_pos_num +1; - for (out_reaching; out_reaching <= proj_data_3D.get_max_axial_pos_num(0); ++out_reaching ) + // int out_reaching = out_ax_pos_num +1; + for (int i = out_ax_pos_num + 1; i < proj_data_3D.get_max_axial_pos_num(0); ++i) { sino_4D *= .5F; sino_3D += sino_4D; - sino_3D2 = proj_data_3D.get_empty_sinogram(out_reaching, 0); + sino_3D2 = proj_data_3D.get_empty_sinogram(i, 0); sino_3D2 += sino_4D; } From 3f53570e5a54cede6c4199075631b3e868312ec8 Mon Sep 17 00:00:00 2001 From: Ludovica BRUSAFERRI Date: Thu, 29 Aug 2019 22:09:45 +0100 Subject: [PATCH 177/274] fixed bug root ECAT --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index c9d55c4434..602c4b794b 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -89,17 +89,17 @@ get_next_record(CListRecordROOT& record) break; } - int ring1 = static_cast(crystalID1/crystal_repeater_z) + int ring1 = static_cast(crystalID1/crystal_repeater_y) + static_cast(blockID1/ block_repeater_y)*crystal_repeater_z; - int ring2 = static_cast(crystalID2/crystal_repeater_z) + int ring2 = static_cast(crystalID2/crystal_repeater_y) + static_cast(blockID2/block_repeater_y)*crystal_repeater_z; int crystal1 = (blockID1%block_repeater_y) * crystal_repeater_y - + (crystalID1%crystal_repeater_z); + + (crystalID1%crystal_repeater_y); int crystal2 = (blockID2%block_repeater_y) * crystal_repeater_y - + (crystalID2%crystal_repeater_z); + + (crystalID2%crystal_repeater_y); // GATE counts crystal ID =0 the most negative. Therefore // ID = 0 should be negative, in Rsector 0 and the mid crystal ID be 0 . From f84802c5e27fb4ea68123be9c11c9143478200ec Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 9 Sep 2019 20:00:02 +0100 Subject: [PATCH 178/274] set --- src/include/stir/numerics/sampling_functions.inl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 9effabd4c3..93945c20a1 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -172,6 +172,8 @@ void transpose_extend_tangential_position(Array<3,elemT>& array) { const int old_min = array[z][y].get_min_index(); const int old_max = array[z][y].get_max_index(); + array[z][y][old_min+1] += array[z][y][old_min]; + array[z][y][old_max-1] += array[z][y][old_max]; array[z][y].grow(old_min+1, old_max-1); //resize } } @@ -221,6 +223,17 @@ void transpose_extend_axial_position(Array<3,elemT>& array) max[2]=array[0].get_max_index();; min[3]=array[0][0].get_min_index(); max[3]=array[0][0].get_max_index(); - array.grow(IndexRange<3>(min, max)); + + + for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) + { + for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) + { + array[min[1]][i][j]+=array[min[1]-1][i][j]; + array[max[1]][i][j]+=array[max[1]+1][i][j]; + } + } + + array.grow(IndexRange<3>(min, max)); } END_NAMESPACE_STIR From 3c2bdbfa6224f123fa527e2d5970322a726174bb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 9 Sep 2019 20:24:06 +0100 Subject: [PATCH 179/274] extend axial --- .../stir/numerics/sampling_functions.inl | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 93945c20a1..a2454b8f4a 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -186,24 +186,18 @@ void extend_axial_position(Array<3,elemT>& array) { BasicCoordinate<3,int> min, max; - min[1]=array.get_min_index()-1; max[1]=array.get_max_index()+1; - min[2]=array[0].get_min_index();; - max[2]=array[0].get_max_index();; - min[3]=array[0][0].get_min_index(); - max[3]=array[0][0].get_max_index(); - - array.grow(IndexRange<3>(min, max)); for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) { for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { - const int min = array.get_min_index(); - const int max = array.get_max_index(); - array[min][i][j]=array[min+1][i][j]; - array[max][i][j]=array[max-1][i][j]; + const int old_min = array.get_min_index(); + const int old_max = array.get_max_index(); + array.grow(IndexRange<3>(min, max)); + array[min][i][j]=array[old_min][i][j]; + array[max][i][j]=array[old_max][i][j]; } } @@ -216,24 +210,22 @@ template void transpose_extend_axial_position(Array<3,elemT>& array) { BasicCoordinate<3,int> min, max; - min[1]=array.get_min_index()+1; max[1]=array.get_max_index()-1; - min[2]=array[0].get_min_index();; - max[2]=array[0].get_max_index();; - min[3]=array[0][0].get_min_index(); - max[3]=array[0][0].get_max_index(); for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) { for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { - array[min[1]][i][j]+=array[min[1]-1][i][j]; - array[max[1]][i][j]+=array[max[1]+1][i][j]; + const int old_min = array.get_min_index(); + const int old_max = array.get_max_index(); + array[min][i][j]+=array[old_min][i][j]; + array[max][i][j]+=array[old_max][i][j]; + array.grow(IndexRange<3>(min, max)); } } - array.grow(IndexRange<3>(min, max)); + } END_NAMESPACE_STIR From 9fdc7431f46d1e67b2e4f116553973bbbe926713 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 9 Sep 2019 20:32:15 +0100 Subject: [PATCH 180/274] fixed --- .../stir/numerics/sampling_functions.inl | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index a2454b8f4a..93945c20a1 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -186,18 +186,24 @@ void extend_axial_position(Array<3,elemT>& array) { BasicCoordinate<3,int> min, max; + min[1]=array.get_min_index()-1; max[1]=array.get_max_index()+1; + min[2]=array[0].get_min_index();; + max[2]=array[0].get_max_index();; + min[3]=array[0][0].get_min_index(); + max[3]=array[0][0].get_max_index(); + + array.grow(IndexRange<3>(min, max)); for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) { for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { - const int old_min = array.get_min_index(); - const int old_max = array.get_max_index(); - array.grow(IndexRange<3>(min, max)); - array[min][i][j]=array[old_min][i][j]; - array[max][i][j]=array[old_max][i][j]; + const int min = array.get_min_index(); + const int max = array.get_max_index(); + array[min][i][j]=array[min+1][i][j]; + array[max][i][j]=array[max-1][i][j]; } } @@ -210,22 +216,24 @@ template void transpose_extend_axial_position(Array<3,elemT>& array) { BasicCoordinate<3,int> min, max; + min[1]=array.get_min_index()+1; max[1]=array.get_max_index()-1; + min[2]=array[0].get_min_index();; + max[2]=array[0].get_max_index();; + min[3]=array[0][0].get_min_index(); + max[3]=array[0][0].get_max_index(); for (int i=array[0].get_min_index(); i<= array[0].get_max_index(); ++i) { for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { - const int old_min = array.get_min_index(); - const int old_max = array.get_max_index(); - array[min][i][j]+=array[old_min][i][j]; - array[max][i][j]+=array[old_max][i][j]; - array.grow(IndexRange<3>(min, max)); + array[min[1]][i][j]+=array[min[1]-1][i][j]; + array[max[1]][i][j]+=array[max[1]+1][i][j]; } } - + array.grow(IndexRange<3>(min, max)); } END_NAMESPACE_STIR From 1cc552887cc07f55e0f784fcfe3baa979dff9e2b Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 9 Sep 2019 22:49:55 +0100 Subject: [PATCH 181/274] fixed boundaries --- src/buildblock/interpolate_projdata.cxx | 8 ++++++-- src/include/stir/numerics/sampling_functions.inl | 2 ++ .../stir_experimental/numerics/more_interpolators.inl | 6 +++--- src/test/test_upsample.cxx | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 9fa272b15b..fd79361a30 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -551,6 +551,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(non_interleaved_segment, 2, 2); //here we are doubling the number of views extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) + extend_axial_position(extended); sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) @@ -560,6 +561,7 @@ interpolate_projdata_pull(ProjData& proj_data_out, { Array<3,float> extended = extend_segment_in_views(proj_data_in.get_segment_by_sinogram(0), 2, 2); //here we are extending the number of views extend_tangential_position(extended); // here we are adding one tangential position before and after max and min index (for the interpolation) + extend_axial_position(extended); sample_function_on_regular_grid_pull(sino_3D_out,extended, offset, step); //pull interpolation proj_data_out.set_segment(sino_3D_out); //fill the output if (proj_data_out.set_segment(sino_3D_out) == Succeeded::no) @@ -653,7 +655,7 @@ interpolate_projdata_push(ProjData& proj_data_out, const SegmentBySinogram non_interleaved_segment = make_non_interleaved_segment(*non_interleaved_proj_data_info_sptr, proj_data_out.get_segment_by_sinogram(0)); Array<3,float> extended = extend_segment_in_views(non_interleaved_segment,2,2); //extend the views extend_tangential_position(extended); //extend the tangential positions - + extend_axial_position(extended); // ===========================PUSH ================================== SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); //TODO: check if we need a for loop over segments @@ -661,6 +663,7 @@ interpolate_projdata_push(ProjData& proj_data_out, // =================== TRANSPOSE EXTENDED =========================== + transpose_extend_axial_position(extended); transpose_extend_tangential_position(extended); //reduce tangential positions SegmentBySinogram extended_segment_sino(extended, non_interleaved_proj_data_info_sptr, 0); //create SegmentBySinogram with extended Array<3,float> out = transpose_extend_segment_in_views(extended_segment_sino,2,2); // here we do the tranpose : extended -> sino_out @@ -683,13 +686,14 @@ interpolate_projdata_push(ProjData& proj_data_out, Array<3,float> extended = extend_segment_in_views(proj_data_out.get_segment_by_sinogram(0), 2, 2); //extend the views extend_tangential_position(extended); //extend the tangential positions - + extend_axial_position(extended); // ===========================PUSH ================================== SegmentBySinogram sino_3D_in = proj_data_in.get_segment_by_sinogram(0); sample_function_on_regular_grid_push(extended,sino_3D_in, offset, step); //here the output of the push is 'extended' // =================== TRANSPOSE EXTENDED =========================== + transpose_extend_axial_position(extended); transpose_extend_tangential_position(extended); shared_ptr extended_proj_data_info_sptr(proj_data_out_info.clone()); //create extended projdata inf SegmentBySinogram extended_segment_sino(extended, extended_proj_data_info_sptr, 0); //create SegmentBySinogram with extended diff --git a/src/include/stir/numerics/sampling_functions.inl b/src/include/stir/numerics/sampling_functions.inl index 93945c20a1..f63b4c90f5 100644 --- a/src/include/stir/numerics/sampling_functions.inl +++ b/src/include/stir/numerics/sampling_functions.inl @@ -229,7 +229,9 @@ void transpose_extend_axial_position(Array<3,elemT>& array) { for (int j=array[0][0].get_min_index(); j<= array[0][0].get_max_index(); ++j) { + array[min[1]][i][j]+=array[min[1]-1][i][j]; + array[min[1]][i][j]+=array[min[1]+1][i][j]-array[min[1]][i][j]; array[max[1]][i][j]+=array[max[1]+1][i][j]; } } diff --git a/src/include/stir_experimental/numerics/more_interpolators.inl b/src/include/stir_experimental/numerics/more_interpolators.inl index d26d20f96d..d4e74ac811 100644 --- a/src/include/stir_experimental/numerics/more_interpolators.inl +++ b/src/include/stir_experimental/numerics/more_interpolators.inl @@ -132,10 +132,10 @@ push_transpose_linear_interpolate(Array<3, elemT>& out, // TODO handle boundary conditions if (left_neighbour[1] < out.get_max_index() && - left_neighbour[1] >= out.get_min_index() && + left_neighbour[1] >= out.get_min_index() && left_neighbour[2] < out[left_neighbour[1]].get_max_index() && - left_neighbour[2] >= out[left_neighbour[1]].get_min_index() && - left_neighbour[3] < out[left_neighbour[1]][left_neighbour[2]].get_max_index() && + left_neighbour[2] >= out[left_neighbour[1]].get_min_index() && + left_neighbour[3] < out[left_neighbour[1]][left_neighbour[2]].get_max_index() && left_neighbour[3] >= out[left_neighbour[1]][left_neighbour[2]].get_min_index()) { const int x1=left_neighbour[3]; diff --git a/src/test/test_upsample.cxx b/src/test/test_upsample.cxx index c650615eae..6f1f052117 100644 --- a/src/test/test_upsample.cxx +++ b/src/test/test_upsample.cxx @@ -200,7 +200,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.004); + set_tolerance(0.006); check_if_equal(cdot1, cdot2, "test adjoint"); @@ -260,7 +260,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.004); + set_tolerance(0.006); check_if_equal(cdot1, cdot2, "test adjoint"); From d7ce3a26b3e262cf0a904dcbbf28e4f9444c4ad8 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 17 Sep 2019 15:50:17 +0100 Subject: [PATCH 182/274] detection --- src/include/stir/scatter/ScatterSimulation.h | 7 +- .../scatter_detection_modelling.cxx | 39 ++++-- src/swig/stir.i | 126 +++++++++--------- 3 files changed, 93 insertions(+), 79 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 89b913cd2b..e1fb60530a 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,10 +211,11 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency2(const float energy, const int en_window = 0) const; + float detection_efficiency_integral(const float energy, const int en_window = 0) const; + float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; - float detection_efficiency3(const float incoming_photon_energy, const int en_window = 0) const; - std::vector detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; + float detection_efficiency_numerical(const float incoming_photon_energy, const int en_window = 0) const; + std::vector detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; float compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 9fbf1dc7ad..a0a7c54713 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -116,7 +116,7 @@ detection_efficiency(const float energy, const int en_window) const } std::vector -ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const +ScatterSimulation::detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const { std::vector energy_range(size); @@ -124,7 +124,7 @@ ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const float increment_x = (HLD - LLD)/size; for(int i = 0 ; i< size; ++i) { - energy_range[i]+= LLD+i*increment_x; + energy_range[i]+= LLD+increment_x +i*increment_x; out[i]+=0; } @@ -137,7 +137,7 @@ ScatterSimulation::detection_efficiency(const float LLD, const float HLD, const } float -ScatterSimulation::detection_efficiency2(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_integral(const float incoming_photon_energy, const int en_window) const { const float HT = this->template_exam_info_sptr->get_high_energy_thres(en_window); @@ -151,7 +151,21 @@ ScatterSimulation::detection_efficiency2(const float incoming_photon_energy, con } float -ScatterSimulation::detection_efficiency3(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const +{ + + //const float HT = this->template_exam_info_sptr->get_high_energy_thres(en_window); + //const float LT = this->template_exam_info_sptr->get_low_energy_thres(en_window); + //const float FWHM = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); + const float f1 = integral_photoelectric(LT,HT, FWHM, incoming_photon_energy) ; + const float f2 = integral_compton_plateau(LT,HT, FWHM, incoming_photon_energy) ; + const float f3 = integral_flat_continuum(LT,HT, FWHM, incoming_photon_energy) ; + const float f4 = integral_exponential_tail(LT,HT, FWHM, incoming_photon_energy) ; + return f1+f2+f3+f4; + } + +float +ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); @@ -161,7 +175,7 @@ ScatterSimulation::detection_efficiency3(const float incoming_photon_energy, con const float increment_x = (HLD - LLD)/size; for(int i = 0 ; i< size; ++i) { - const float energy_range = LLD+i*increment_x; + const float energy_range = LLD+increment_x +i*increment_x; sum+= detection_model_with_fitted_parameters(energy_range, incoming_photon_energy); } @@ -182,15 +196,16 @@ detection_model_with_fitted_parameters(const float x, const float energy) const const int Z = 66; // atomic number of LSO const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section - const float H_2 = 9.40*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section + const float H_2 = 9.33*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section const float H_3 = 7; //fitting parameter - const float H_4 = 26.0; //fitting parameter - const float beta = -0.817; //fitting parameter - const float global_scale = 2.33*1e-07; //fitting parameter - const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); + const float H_4 = 29.4; //fitting parameter + const float beta = -0.8401; //fitting parameter + const float global_scale = 0.29246*0.8*1e-06;//2.33*1e-07; //fitting parameter + //const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); + const float fwhm = 0.14; const float std_peak = energy*fwhm/2.35482; - const float scaling_std_compton = 29.6; //fitting parameter - const float shift_compton = 0.598; //fitting parameter + const float scaling_std_compton = 28.3; //fitting parameter + const float shift_compton = 0.597; //fitting parameter const float f1 = photoelectric(H_1, std_peak, x, energy); const float f2 = compton_plateau(H_2, std_peak, x, energy, scaling_std_compton,shift_compton); const float f3 = flat_continuum(H_3,std_peak, x, energy); diff --git a/src/swig/stir.i b/src/swig/stir.i index 96dfd06107..da61b04e72 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -16,10 +16,10 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \brief Interface file for SWIG - \author Kris Thielemans + \author Kris Thielemans */ @@ -58,7 +58,7 @@ #include "stir/ProjData.h" #include "stir/ProjDataInMemory.h" #include "stir/ProjDataInterfile.h" - + #include "stir/CartesianCoordinate2D.h" #include "stir/CartesianCoordinate3D.h" @@ -71,7 +71,7 @@ #include "stir/VoxelsOnCartesianGrid.h" #include "stir/GeneralisedPoissonNoiseGenerator.h" - + #include "stir/IO/read_from_file.h" #include "stir/IO/InterfileOutputFileFormat.h" #ifdef HAVE_LLN_MATRIX @@ -82,7 +82,7 @@ #include "stir/SeparableCartesianMetzImageFilter.h" #include "stir/SeparableGaussianImageFilter.h" #include "stir/PostFiltering.h" -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" +#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" #include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" #include "stir/OSSPS/OSSPSReconstruction.h" #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" @@ -95,14 +95,14 @@ #include #include #include - + #include "stir/IO/write_to_file.h" - + #include "stir/scatter/ScatterSimulation.h" #include "stir/scatter/SingleScatterSimulation.h" #include "stir/scatter/ScatterEstimation.h" #include "stir/scatter/SingleScatterLikelihoodAndGradient.h" - + // TODO need this (bug in swig) // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace // as opposed to "%template(name) stir::someclass" outside the namespace @@ -116,7 +116,7 @@ SWIG_AsVal_double (PyObject * obj, double *val); #endif - // local helper functions for conversions etc. These are not "exposed" to the target language + // local helper functions for conversions etc. These are not "exposed" to the target language // (but only enter in the wrapper) namespace swigstir { #if defined(SWIGPYTHON) @@ -173,15 +173,15 @@ { PyObject *iterator = PyObject_GetIter(arg); - + PyObject *item; typename stir::Array::full_iterator array_iter = array_ptr->begin_all(); - while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) + while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) { double val; // TODO currently hard-wired as double which might imply extra conversions int ecode = SWIG_AsVal_double(item, &val); - if (SWIG_IsOK(ecode)) + if (SWIG_IsOK(ecode)) { *array_iter++ = static_cast(val); } @@ -203,7 +203,7 @@ } Py_DECREF(iterator); - if (PyErr_Occurred()) + if (PyErr_Occurred()) { throw std::runtime_error("Error during fill()"); } @@ -212,7 +212,7 @@ } #if 0 - + // TODO does not work yet. // it doesn't compile as includes are in init section, which follows after this in the wrapper // Even if it did compile, it might not work anyway as I haven't tested it. @@ -321,7 +321,7 @@ float const* data_ptr = (float *)mxGetData(pm); a.fill(static_cast(*data_ptr)); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for filling a stir array"); } } @@ -344,8 +344,8 @@ } if (matlab_num_dims > static_cast(num_dimensions)) { - throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % - num_dimensions)); + throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % + num_dimensions)); } if (do_resize) { @@ -356,7 +356,7 @@ a.resize(sizes); } else - { + { // check sizes BasicCoordinate minind,maxind; a.get_regular_range(minind,maxind); @@ -372,7 +372,7 @@ throw std::runtime_error("sizes of first dimensions of the stir array have to be 1 if initialising from a lower dimensional matlab array"); } } - } + } if (mxIsDouble(pm)) { double * data_ptr = mxGetPr(pm); @@ -382,10 +382,10 @@ float * data_ptr = (float *)mxGetData(pm); std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); } - } + } //////////// same for Coordinate @@ -414,7 +414,7 @@ float const* data_ptr = (float *)mxGetData(pm); a.fill(static_cast(*data_ptr)); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for filling a stir coordinate"); } } @@ -437,8 +437,8 @@ } if (matlab_num_dims != static_cast(1)) { - throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % - matlab_num_dims % num_dimensions)); + throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % + matlab_num_dims % num_dimensions)); } if (m_sizes[0]!=static_cast(num_dimensions)) { @@ -453,10 +453,10 @@ float * data_ptr = (float *)mxGetData(pm); std::copy(data_ptr, data_ptr+a.size(), a.begin()); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); } - } + } #endif } // end namespace swigstir %} @@ -497,7 +497,7 @@ } catch (const std::string& e) { SWIG_exception(SWIG_RuntimeError, e.c_str()); } -} +} // declare some functions that return a new pointer such that SWIG can release memory properly %newobject *::clone; @@ -508,7 +508,7 @@ %ignore *::create_shared_clone; #if defined(SWIGPYTHON) -%rename(__assign__) *::operator=; +%rename(__assign__) *::operator=; #endif // include standard swig support for some bits of the STL (i.e. standard C++ lib) @@ -553,7 +553,7 @@ namespace std { %template(StringList) list; } -// section for helper classes for creating new iterators. +// section for helper classes for creating new iterators. // The code here is nearly a copy of what's in PyIterators.swg, // except that the decr() function isn't defined. This is because we need it for some STIR iterators // which are forward_iterators. @@ -564,7 +564,7 @@ namespace std { %{ namespace swigstir { #ifdef SWIGPYTHON - template::value_type, typename FromOper = swig::from_oper > class SwigPyForwardIteratorClosed_T : public swig::SwigPyIterator_T @@ -573,14 +573,14 @@ namespace std { FromOper from; typedef OutIterator out_iterator; typedef ValueType value_type; - typedef swig::SwigPyIterator_T base; + typedef swig::SwigPyIterator_T base; typedef SwigPyForwardIteratorClosed_T self_type; - + SwigPyForwardIteratorClosed_T(out_iterator curr, out_iterator first, out_iterator last, PyObject *seq) : swig::SwigPyIterator_T(curr, seq), begin(first), end(last) { } - + PyObject *value() const { if (base::current == end) { throw swig::stop_iteration(); @@ -588,7 +588,7 @@ namespace std { return swig::from(static_cast(*(base::current))); } } - + swig::SwigPyIterator *copy() const { return new self_type(*this); @@ -692,14 +692,14 @@ namespace std { // } proj_data.fill_from(array_iter); } - - + + } // end of namespace %} // end of initial code specification for inclusino in the SWIG wrapper // doesn't work (yet?) because of bug in int template arguments -// %rename(__getitem__) *::at; +// %rename(__getitem__) *::at; // MACROS to define index access (Work-in-progress) %define %ADD_indexaccess(INDEXTYPE,RETTYPE,TYPE...) @@ -872,7 +872,7 @@ T * operator-> () const; // use simpler version for SWIG to make the hierarchy a bit easier namespace stir { template - class RegisteredObject + class RegisteredObject { public: //! List all possible registered names to the stream @@ -993,14 +993,14 @@ T * operator-> () const; static stir::VoxelsOnCartesianGrid * read_from_file(const std::string& filename) { using namespace stir; - unique_ptr > + unique_ptr > ret(read_from_file >(filename)); return dynamic_cast *>(ret.release()); } } //%ADD_indexaccess(int,stir::BasicCoordinate::value_type,stir::BasicCoordinate); -namespace stir { +namespace stir { #ifdef SWIGPYTHON // add extra features to the coordinates to make them a bit more Python friendly %extend BasicCoordinate { @@ -1017,7 +1017,7 @@ namespace stir { // print as (1,2,3) as opposed to non-informative default provided by SWIG std::string __str__() - { + { std::ostringstream s; s<<'('; for (int d=1; d<=num_dimensions-1; ++d) @@ -1028,7 +1028,7 @@ namespace stir { // print as classname((1,2,3)) as opposed to non-informative default provided by SWIG std::string __repr__() - { + { #if SWIG_VERSION < 0x020009 // don't know how to get the Python typename std::string repr = "stir.Coordinate"; @@ -1059,8 +1059,8 @@ namespace stir { return $self->size(); } #if defined(SWIGPYTHON_BUILTIN) - %feature("python:slot", "tp_str", functype="reprfunc") __str__; - %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; + %feature("python:slot", "tp_str", functype="reprfunc") __str__; + %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; %feature("python:slot", "sq_length", functype="lenfunc") __len__; #endif // SWIGPYTHON_BUILTIN @@ -1070,14 +1070,14 @@ namespace stir { %extend BasicCoordinate { // print as [1;2;3] as opposed to non-informative default provided by SWIG void disp() - { + { std::ostringstream s; s<<'['; for (int d=1; d<=num_dimensions-1; ++d) s << (*$self)[d] << "; "; s << (*$self)[num_dimensions] << "]\n"; mexPrintf(s.str().c_str()); - + } //%feature("autodoc", "construct from vector, e.g. [2;3;4] for a 3d coordinate") BasicCoordinate(const mxArray *pm) @@ -1103,7 +1103,7 @@ namespace stir { %template(Float3Coordinate) Coordinate3D< float >; %template(FloatCartesianCoordinate3D) CartesianCoordinate3D; %template(IntCartesianCoordinate3D) CartesianCoordinate3D; - + %template(Int2BasicCoordinate) BasicCoordinate<2,int>; %template(Size2BasicCoordinate) BasicCoordinate<2,std::size_t>; %template(Float2BasicCoordinate) BasicCoordinate<2,float>; @@ -1183,7 +1183,7 @@ namespace stir { snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", arg->ob_type->tp_name); throw std::invalid_argument(str); - } + } } } #endif @@ -1229,7 +1229,7 @@ namespace stir { { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } } #endif - // TODO next line doesn't give anything useful as SWIG doesn't recognise that + // TODO next line doesn't give anything useful as SWIG doesn't recognise that // the return value is an array. So, we get a wrapped object that we cannot handle //%ADD_indexaccess(int,Array::value_type, Array); @@ -1296,8 +1296,6 @@ namespace stir { #endif #endif -%template(write_image_to_file) stir::write_to_file >; - %include "stir/IO/OutputFileFormat.h" #define DataT stir::DiscretisedDensity<3,float> @@ -1337,9 +1335,9 @@ namespace stir { %include "stir/ProjDataInfo.h" %newobject *::construct_proj_data_info; -%extend stir::ProjDataInfo +%extend stir::ProjDataInfo { - // work around the current SWIG limitation that it doesn't wrap unique_ptr. + // work around the current SWIG limitation that it doesn't wrap unique_ptr. // we do this with the crazy (and ugly) way to let SWIG create a new function // which is the same as the original, but returns a bare pointer. // (This will be wrapped as a shared_ptr in the end). @@ -1351,7 +1349,7 @@ namespace stir { const int num_views, const int num_tangential_poss, const bool arc_corrected = true) { - return + return construct_proj_data_info(scanner_sptr, span, max_delta, num_views, num_tangential_poss, arc_corrected).get(); @@ -1371,13 +1369,13 @@ namespace stir { %include "stir/ProjData.h" namespace stir { -%extend ProjData +%extend ProjData { #ifdef SWIGPYTHON %feature("autodoc", "create a stir 3D Array from the projection data (internal)") to_array; %newobject to_array; Array<3,float> to_array() - { + { Array<3,float> array = swigstir::projdata_to_3D(*$self); return array; } @@ -1389,7 +1387,7 @@ namespace stir { { Array<3,float> array = swigstir::create_array_for_proj_data(*$self); swigstir::fill_Array_from_Python_iterator(&array, arg); - swigstir::fill_proj_data_from_3D(*$self, array); + swigstir::fill_proj_data_from_3D(*$self, array); } else { @@ -1397,19 +1395,19 @@ namespace stir { snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", arg->ob_type->tp_name); throw std::invalid_argument(str); - } + } } #elif defined(SWIGMATLAB) %newobject to_matlab; mxArray * to_matlab() - { + { Array<3,float> array = swigstir::projdata_to_3D(*$self); - return swigstir::Array_to_matlab(array); + return swigstir::Array_to_matlab(array); } void fill(const mxArray *pm) - { + { Array<3,float> array; swigstir::fill_Array_from_matlab(array, pm, true); swigstir::fill_proj_data_from_3D(*$self, array); @@ -1422,7 +1420,7 @@ namespace stir { %include "stir/ProjDataInterfile.h" %include "stir/ProjDataInMemory.h" -namespace stir { +namespace stir { %template(FloatViewgram) Viewgram; %template(FloatSinogram) Sinogram; // TODO don't want to give a name @@ -1640,7 +1638,7 @@ extend stir::DataProcessor { %shared_ptr( stir::AddParser); %template (internalAddParserForwardProjectorByBin) stir::AddParser; -%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) +%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) stir::RegisteredParsingObject; %include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" @@ -1648,7 +1646,7 @@ extend stir::DataProcessor { %shared_ptr( stir::AddParser); %template (internalAddParserBackProjectorByBin) stir::AddParser; -%template (internalRPBackProjectorByBinUsingProjMatrixByBin) +%template (internalRPBackProjectorByBinUsingProjMatrixByBin) stir::RegisteredParsingObject; %include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" From 9ac6357dfc1dce273fdc41c8b5b1fdd5e5a4c827 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Sep 2019 10:50:28 +0100 Subject: [PATCH 183/274] efficiency --- src/buildblock/inverse_SSRB.cxx | 43 +++++++++++++------ src/include/stir/scatter/ScatterSimulation.h | 4 +- .../scatter_detection_modelling.cxx | 6 +-- src/test/test_SSRB.cxx | 15 +++++-- 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/buildblock/inverse_SSRB.cxx b/src/buildblock/inverse_SSRB.cxx index 71e0bc6c9c..d505de716b 100644 --- a/src/buildblock/inverse_SSRB.cxx +++ b/src/buildblock/inverse_SSRB.cxx @@ -66,10 +66,11 @@ inverse_SSRB(ProjData& proj_data_4D, Sinogram sino_4D = proj_data_4D. get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); + sino_4D.fill(0); Sinogram sino_3D = proj_data_3D. get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); - + sino_3D.fill(0); for (int out_segment_num = proj_data_4D.get_min_segment_num(); out_segment_num <= proj_data_4D.get_max_segment_num(); ++out_segment_num) @@ -78,6 +79,10 @@ inverse_SSRB(ProjData& proj_data_4D, out_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(out_segment_num); ++out_ax_pos_num ) { + + // if((out_segment_num+out_ax_pos_num )>proj_data_4D.get_max_axial_pos_num(out_segment_num)||(out_segment_num+out_ax_pos_num) @@ -119,6 +124,10 @@ inverse_SSRB(ProjData& proj_data_4D, out_segment_num, out_ax_pos_num); } } + // Sinogram test = proj_data_4D.get_sinogram(1,0); + //std::cout << "expeted:1\n" << proj_data_4D.get_sinogram(1,0)[0][0]; + //std::cout << "expected: ?\n" << proj_data_4D.get_sinogram(1,-2)[0][0]; + // std::cout << "expected: /=1\n" << proj_data_4D.get_sinogram(1,2)[0][0]; return Succeeded::yes; } @@ -136,48 +145,54 @@ transpose_inverse_SSRB(ProjData& proj_data_3D, Sinogram sino_3D2 = proj_data_3D.get_empty_sinogram(proj_data_3D.get_min_axial_pos_num(0) , 0); Sinogram sino_4D = proj_data_4D.get_empty_sinogram(proj_data_4D.get_min_axial_pos_num(0) , 0); - + sino_3D.fill(0); + sino_3D2.fill(0); + sino_4D.fill(0); for (int out_ax_pos_num = proj_data_3D.get_min_axial_pos_num(0); out_ax_pos_num <= proj_data_3D.get_max_axial_pos_num(0); ++out_ax_pos_num ) { sino_3D = proj_data_3D.get_empty_sinogram(out_ax_pos_num, 0); const float out_m = proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num, 0)); const float out_m_next = out_ax_pos_num == proj_data_3D.get_max_axial_pos_num(0) ? -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num+1, 0)); + const float out_m_prev = out_ax_pos_num == proj_data_3D.get_min_axial_pos_num(0) ? + -1000000.F : proj_data_3D_info_ptr->get_m(Bin(0, 0, out_ax_pos_num-1, 0)); for (int in_segment_num = proj_data_4D.get_min_segment_num(); in_segment_num <= proj_data_4D.get_max_segment_num(); ++in_segment_num) { for (int in_ax_pos_num = proj_data_4D.get_min_axial_pos_num(in_segment_num);in_ax_pos_num <= proj_data_4D.get_max_axial_pos_num(in_segment_num); ++in_ax_pos_num ) { - sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); + //if((in_segment_num+out_ax_pos_num )>proj_data_4D.get_max_axial_pos_num(in_segment_num)||(in_segment_num+out_ax_pos_num)get_m(Bin(in_segment_num, 0, in_ax_pos_num, 0)); if (fabs(out_m - in_m) < 1E-2) { + sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); sino_3D += sino_4D; } - if (fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) + if ((fabs(in_m - .5F*(out_m + out_m_next)) < 1E-2) || (fabs(in_m - .5F*(out_m + out_m_prev)) < 1E-2)) { + // for (int i = out_ax_pos_num + 1; i <= proj_data_3D.get_max_axial_pos_num(0); ++i) + //{ + // sino_4D *= .5F; + sino_4D = proj_data_4D.get_sinogram(in_ax_pos_num,in_segment_num); + sino_3D += sino_4D/2; + // sino_3D2 = proj_data_3D.get_empty_sinogram(i, 0); + // sino_3D2 += sino_4D; - // int out_reaching = out_ax_pos_num +1; - for (int i = out_ax_pos_num + 1; i < proj_data_3D.get_max_axial_pos_num(0); ++i) - { - sino_4D *= .5F; - sino_3D += sino_4D; - sino_3D2 = proj_data_3D.get_empty_sinogram(i, 0); - sino_3D2 += sino_4D; + } - } - } } } proj_data_3D.set_sinogram(sino_3D); - proj_data_3D.set_sinogram(sino_3D2); + //proj_data_3D.set_sinogram(sino_3D2); } diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index e1fb60530a..8520abe3ef 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,10 +211,10 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_integral(const float energy, const int en_window = 0) const; + float detection_efficiency_gauss(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; + float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; - float detection_efficiency_numerical(const float incoming_photon_energy, const int en_window = 0) const; std::vector detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index a0a7c54713..8a77565784 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -98,7 +98,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy, const int en_window) const +detection_efficiency_gauss(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -165,13 +165,13 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = HLD-LLD; + const int size = 30; const float increment_x = (HLD - LLD)/size; for(int i = 0 ; i< size; ++i) { diff --git a/src/test/test_SSRB.cxx b/src/test/test_SSRB.cxx index 1c65e8e838..c8a5cfb6a5 100644 --- a/src/test/test_SSRB.cxx +++ b/src/test/test_SSRB.cxx @@ -60,9 +60,10 @@ SSRBTests:: fill_projdata_with_random(ProjData & projdata) { + projdata.fill(0); std::random_device random_device; std::mt19937 random_number_generator(random_device()); - std::uniform_real_distribution number_distribution(0,10); + std::uniform_real_distribution number_distribution(0,1); Bin bin; { for (bin.segment_num()=projdata.get_min_segment_num(); @@ -74,6 +75,9 @@ fill_projdata_with_random(ProjData & projdata) ++bin.axial_pos_num()) { + if((bin.segment_num()+bin.axial_pos_num())>projdata.get_max_axial_pos_num(bin.segment_num())||(bin.segment_num()+bin.axial_pos_num()) sino = projdata.get_empty_sinogram(bin.axial_pos_num(),bin.segment_num()); for (bin.view_num()=sino.get_min_view_num(); @@ -109,6 +113,7 @@ run_tests() shared_ptr proj_data_info_sptr_4D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 2,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr exam_info_sptr_4D(new ExamInfo); ProjDataInMemory projdata_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); + //shared_ptr proj_data_info_sptr_3D(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,/*span*/1, 0,/*views*/ 252, /*tang_pos*/344, /*arc_corrected*/ false)); shared_ptr proj_data_info_sptr_3D(projdata_4D.get_proj_data_info_ptr()->clone()); proj_data_info_sptr_3D->reduce_segment_range(0,0); //create input template @@ -116,10 +121,14 @@ run_tests() ProjDataInMemory projdata_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); ProjDataInMemory A_4D(exam_info_sptr_4D, proj_data_info_sptr_4D); - ProjDataInMemory A_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D); + ProjDataInMemory A_3D(projdata_3D.get_exam_info_sptr(),proj_data_info_sptr_3D); + // ProjDataInterfile A_4D(exam_info_sptr_4D, proj_data_info_sptr_4D, "4D.hs",std::ios::out|std::ios::in|std::ios::app); + //ProjDataInterfile A_3D(projdata_4D.get_exam_info_sptr(),proj_data_info_sptr_3D, "3D.hs",std::ios::out|std::ios::in|std::ios::app); fill_projdata_with_random(projdata_4D); + //projdata_4D.fill(1); fill_projdata_with_random(projdata_3D); + //projdata_3D.fill(1); A_4D.fill(0); //initialise output A_3D.fill(0); //initialise output @@ -173,7 +182,7 @@ run_tests() } std::cout << cdot1 << "=" << cdot2 << '\n'; - set_tolerance(0.04); + set_tolerance(0.008); check_if_equal(cdot1, cdot2, "test adjoint"); From b187ddde3b23d6f40c093bedc02c8d2a700c550e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Sep 2019 10:51:20 +0100 Subject: [PATCH 184/274] comment --- src/scatter_buildblock/scatter_detection_modelling.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 8a77565784..43fd8ec307 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -255,7 +255,7 @@ exponential_tail(const float K, const float std_peak, const float x, const float const float den2 = sqrt(2)*std_peak; const float den3 = 2*beta; float f; - if (x > 100) + if (x > 100) //i am not sure of the behaviour of the function at too low energies f = K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); else f = 0; From 065c7e24812278aece382bb240557289f67ad9ff Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Sep 2019 15:34:05 +0100 Subject: [PATCH 185/274] test omp --- src/scatter_buildblock/scatter_detection_modelling.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 43fd8ec307..d242562a7c 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -34,6 +34,7 @@ #include "stir/info.h" #include "stir/CPUTimer.h" #include +#include START_NAMESPACE_STIR unsigned @@ -173,6 +174,7 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons float sum = 0; const int size = 30; const float increment_x = (HLD - LLD)/size; + #pragma omp parallel for reduction(+:sum) for(int i = 0 ; i< size; ++i) { const float energy_range = LLD+increment_x +i*increment_x; @@ -255,7 +257,7 @@ exponential_tail(const float K, const float std_peak, const float x, const float const float den2 = sqrt(2)*std_peak; const float den3 = 2*beta; float f; - if (x > 100) //i am not sure of the behaviour of the function at too low energies + if (x > 150) //i am not sure of the behaviour of the function at too low energies f = K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); else f = 0; @@ -309,7 +311,7 @@ const float fact2 = -1.26141*exp(-0.64874/FWHM)*erf(0.417191+(1.66511-(1.66511*L const float fact3 = 1.26141*exp(-0.64874/FWHM)*erf(0.417191+(1.66511-(1.66511*HT)/(energy))/FWHM); const float fact4 = 1.54145*exp(-0.64874*LT/(energy*FWHM))*erfc(-0.611995+(-1.66511+(1.66511*LT)/(energy))/FWHM); const float fact5 = -1.54145*exp(-0.64874*HT/(energy*FWHM))*erfc(-0.611995+(-1.66511+(1.66511*HT)/(energy))/FWHM); -if (energy<100) +if (energy<150) return 0; else return fact1*(fact2+fact3+fact4+fact5); From 37f43dd9cea107eb60b614a399d33ad79806cf05 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Sep 2019 16:53:33 +0100 Subject: [PATCH 186/274] efficiency --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../scatter_detection_modelling.cxx | 62 ++++++++++--------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 8520abe3ef..7d19f52f11 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_gauss(const float energy, const int en_window = 0) const; + float detection_efficiency_numeric(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index d242562a7c..663e372dc7 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -34,7 +34,9 @@ #include "stir/info.h" #include "stir/CPUTimer.h" #include +#ifdef STIR_OPENMP #include +#endif START_NAMESPACE_STIR unsigned @@ -99,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency_gauss(const float energy, const int en_window) const +detection_efficiency(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -166,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_numeric(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); @@ -174,7 +176,9 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons float sum = 0; const int size = 30; const float increment_x = (HLD - LLD)/size; + #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:sum) + #endif for(int i = 0 ; i< size; ++i) { const float energy_range = LLD+increment_x +i*increment_x; @@ -196,24 +200,25 @@ detection_model_with_fitted_parameters(const float x, const float energy) const //! We consider to have four terms: (i) gaussian model for the photopeak, (ii) compton plateau, (iii) flat continuum, (iv) exponential tale //! The model has be trained with 511 keV and tested with 370 keV. - const int Z = 66; // atomic number of LSO - const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section - const float H_2 = 9.33*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section - const float H_3 = 7; //fitting parameter - const float H_4 = 29.4; //fitting parameter - const float beta = -0.8401; //fitting parameter - const float global_scale = 0.29246*0.8*1e-06;//2.33*1e-07; //fitting parameter + //const int Z = 66; // atomic number of LSO + //const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section + //const float H_2 = 9.33*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section + //const float H_3 = 7; //fitting parameter + //const float H_4 = 29.4; //fitting parameter + //const float beta = -0.8401; //fitting parameter + //const float global_scale = 0.29246*0.8*1e-06;//2.33*1e-07; //fitting parameter //const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); - const float fwhm = 0.14; - const float std_peak = energy*fwhm/2.35482; - const float scaling_std_compton = 28.3; //fitting parameter - const float shift_compton = 0.597; //fitting parameter - const float f1 = photoelectric(H_1, std_peak, x, energy); - const float f2 = compton_plateau(H_2, std_peak, x, energy, scaling_std_compton,shift_compton); - const float f3 = flat_continuum(H_3,std_peak, x, energy); - const float f4 = exponential_tail(H_4,std_peak, x, energy,beta); - - return global_scale*(f1+f2+f3+f4); + //const float fwhm = 0.14; + //const float std_peak = energy*fwhm/2.35482; + //const float scaling_std_compton = 28.3; //fitting parameter + //const float shift_compton = 0.597; //fitting parameter + const float f1 = photoelectric((66*66*66*66*66)/energy, (energy*0.14f)/2.35482f, x, energy); + const float f2 = compton_plateau(9.33f*pow(10,25)*total_Compton_cross_section(energy)*66, + (energy*0.14f)/2.35482f, x , energy, 28.3f, 0.597f); + const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); + const float f4 = exponential_tail(29.4f,(energy*0.14)/2.35482f, x, energy,-0.8401f); + + return 0.29246*0.8*1e-06*(f1+f2+f3+f4); } float @@ -221,8 +226,8 @@ ScatterSimulation:: photoelectric(const float K, const float std_peak, const float x, const float energy) const { const float diff = x - energy; - const float pow_diff = pow(diff,2); - const float pow_std_peak = pow(std_peak,2); + const float pow_diff = diff*diff; + const float pow_std_peak = std_peak*std_peak; return K/(std_peak*sqrt(2*M_PI))*exp(-pow_diff/(2*pow_std_peak)); } @@ -234,19 +239,18 @@ compton_plateau(const float K, const float std_peak, const float x, const float const float alpha = energy/m_0_c_2; const float E_1 = energy/(1+alpha*(1-cos(M_PI))); const float mean = energy*shift_compton; - return ((energy/E_1)+(E_1/energy)-1+cos(M_PI))*(K*exp(-(pow((x - mean),2))/(4*scaling_std_compton*std_peak))); + const float x_minus_mean = x - mean; + return ((energy/E_1)+(E_1/energy)-1+cos(M_PI))*(K*exp(-(x_minus_mean*x_minus_mean)/(4*scaling_std_compton*std_peak))); } float ScatterSimulation:: flat_continuum(const float K, const float std_peak, const float x, const float energy) const { const float den = sqrt(2)*std_peak; - float f = 0; if (x<=energy) - f = K* erfc((x-energy)/den); + return K* erfc((x-energy)/den); else - f = 0; - return f; + return 0; } float @@ -256,12 +260,10 @@ exponential_tail(const float K, const float std_peak, const float x, const float const float den1 = sqrt(2)*M_PI*std_peak*beta; const float den2 = sqrt(2)*std_peak; const float den3 = 2*beta; - float f; if (x > 150) //i am not sure of the behaviour of the function at too low energies - f = K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); + return K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); else - f = 0; - return f; + return 0; } float From bc44e830e2887b84dc7f20588a194f05165bcb41 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Sep 2019 17:27:03 +0100 Subject: [PATCH 187/274] efficiency --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../scatter_detection_modelling.cxx | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 7d19f52f11..8520abe3ef 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_numeric(const float energy, const int en_window = 0) const; + float detection_efficiency_gauss(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 663e372dc7..d7118bc1a3 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy, const int en_window) const +detection_efficiency_gauss(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency_numeric(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); @@ -213,7 +213,7 @@ detection_model_with_fitted_parameters(const float x, const float energy) const //const float scaling_std_compton = 28.3; //fitting parameter //const float shift_compton = 0.597; //fitting parameter const float f1 = photoelectric((66*66*66*66*66)/energy, (energy*0.14f)/2.35482f, x, energy); - const float f2 = compton_plateau(9.33f*pow(10,25)*total_Compton_cross_section(energy)*66, + const float f2 = compton_plateau(9.33f*10000000000000*10000000000000*total_Compton_cross_section(energy)*66, (energy*0.14f)/2.35482f, x , energy, 28.3f, 0.597f); const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); const float f4 = exponential_tail(29.4f,(energy*0.14)/2.35482f, x, energy,-0.8401f); @@ -228,25 +228,25 @@ photoelectric(const float K, const float std_peak, const float x, const float en const float diff = x - energy; const float pow_diff = diff*diff; const float pow_std_peak = std_peak*std_peak; - return K/(std_peak*sqrt(2*M_PI))*exp(-pow_diff/(2*pow_std_peak)); + return K/(std_peak*2.5066f)*exp(-pow_diff/(2*pow_std_peak)); } float ScatterSimulation:: compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const { - const float m_0_c_2 = 511.F; + const float m_0_c_2 = 511.0f; const float alpha = energy/m_0_c_2; - const float E_1 = energy/(1+alpha*(1-cos(M_PI))); + const float E_1 = energy/(1+alpha*(2)); const float mean = energy*shift_compton; const float x_minus_mean = x - mean; - return ((energy/E_1)+(E_1/energy)-1+cos(M_PI))*(K*exp(-(x_minus_mean*x_minus_mean)/(4*scaling_std_compton*std_peak))); + return ((energy/E_1)+(E_1/energy)-2)*(K*exp(-(x_minus_mean*x_minus_mean)/(4*scaling_std_compton*std_peak))); } float ScatterSimulation:: flat_continuum(const float K, const float std_peak, const float x, const float energy) const { - const float den = sqrt(2)*std_peak; + const float den = 1.4142f*std_peak; if (x<=energy) return K* erfc((x-energy)/den); else @@ -257,8 +257,8 @@ float ScatterSimulation:: exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const { - const float den1 = sqrt(2)*M_PI*std_peak*beta; - const float den2 = sqrt(2)*std_peak; + const float den1 = 4.4429f*std_peak*beta; + const float den2 = 1.4142f*std_peak; const float den3 = 2*beta; if (x > 150) //i am not sure of the behaviour of the function at too low energies return K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); From a40d5ae65216b1d5c811c0574bf3239e23bf7d09 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 18 Sep 2019 18:12:33 +0100 Subject: [PATCH 188/274] text threds --- .../scatter_detection_modelling.cxx | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index d7118bc1a3..885923cce3 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -200,25 +200,24 @@ detection_model_with_fitted_parameters(const float x, const float energy) const //! We consider to have four terms: (i) gaussian model for the photopeak, (ii) compton plateau, (iii) flat continuum, (iv) exponential tale //! The model has be trained with 511 keV and tested with 370 keV. - //const int Z = 66; // atomic number of LSO - //const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section - //const float H_2 = 9.33*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section - //const float H_3 = 7; //fitting parameter - //const float H_4 = 29.4; //fitting parameter - //const float beta = -0.8401; //fitting parameter - //const float global_scale = 0.29246*0.8*1e-06;//2.33*1e-07; //fitting parameter + const int Z = 66; // atomic number of LSO + const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section + const float H_2 = 9.33*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section + const float H_3 = 7; //fitting parameter + const float H_4 = 29.4; //fitting parameter + const float beta = -0.8401; //fitting parameter + const float global_scale = 0.29246*0.8*1e-06;//2.33*1e-07; //fitting parameter //const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); - //const float fwhm = 0.14; - //const float std_peak = energy*fwhm/2.35482; - //const float scaling_std_compton = 28.3; //fitting parameter - //const float shift_compton = 0.597; //fitting parameter - const float f1 = photoelectric((66*66*66*66*66)/energy, (energy*0.14f)/2.35482f, x, energy); - const float f2 = compton_plateau(9.33f*10000000000000*10000000000000*total_Compton_cross_section(energy)*66, - (energy*0.14f)/2.35482f, x , energy, 28.3f, 0.597f); - const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); - const float f4 = exponential_tail(29.4f,(energy*0.14)/2.35482f, x, energy,-0.8401f); - - return 0.29246*0.8*1e-06*(f1+f2+f3+f4); + const float fwhm = 0.14; + const float std_peak = energy*fwhm/2.35482; + const float scaling_std_compton = 28.3; //fitting parameter + const float shift_compton = 0.597; //fitting parameter + const float f1 = photoelectric(H_1, std_peak, x, energy); + const float f2 = compton_plateau(H_2, std_peak, x, energy, scaling_std_compton,shift_compton); + const float f3 = flat_continuum(H_3,std_peak, x, energy); + const float f4 = exponential_tail(H_4,std_peak, x, energy,beta); + + return global_scale*(f1+f2+f3+f4); } float @@ -226,44 +225,47 @@ ScatterSimulation:: photoelectric(const float K, const float std_peak, const float x, const float energy) const { const float diff = x - energy; - const float pow_diff = diff*diff; - const float pow_std_peak = std_peak*std_peak; - return K/(std_peak*2.5066f)*exp(-pow_diff/(2*pow_std_peak)); + const float pow_diff = pow(diff,2); + const float pow_std_peak = pow(std_peak,2); + return K/(std_peak*sqrt(2*M_PI))*exp(-pow_diff/(2*pow_std_peak)); } float ScatterSimulation:: compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const { - const float m_0_c_2 = 511.0f; + const float m_0_c_2 = 511.F; const float alpha = energy/m_0_c_2; - const float E_1 = energy/(1+alpha*(2)); + const float E_1 = energy/(1+alpha*(1-cos(M_PI))); const float mean = energy*shift_compton; - const float x_minus_mean = x - mean; - return ((energy/E_1)+(E_1/energy)-2)*(K*exp(-(x_minus_mean*x_minus_mean)/(4*scaling_std_compton*std_peak))); + return ((energy/E_1)+(E_1/energy)-1+cos(M_PI))*(K*exp(-(pow((x - mean),2))/(4*scaling_std_compton*std_peak))); } float ScatterSimulation:: flat_continuum(const float K, const float std_peak, const float x, const float energy) const { - const float den = 1.4142f*std_peak; + const float den = sqrt(2)*std_peak; + float f = 0; if (x<=energy) - return K* erfc((x-energy)/den); + f = K* erfc((x-energy)/den); else - return 0; + f = 0; + return f; } float ScatterSimulation:: exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const { - const float den1 = 4.4429f*std_peak*beta; - const float den2 = 1.4142f*std_peak; + const float den1 = sqrt(2)*M_PI*std_peak*beta; + const float den2 = sqrt(2)*std_peak; const float den3 = 2*beta; - if (x > 150) //i am not sure of the behaviour of the function at too low energies - return K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); + float f; + if (x > 100) //i am not sure of the behaviour of the function at too low energies + f = K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); else - return 0; + f = 0; + return f; } float From acd075d97cce63545f22b445f4cf3d1b1be6970a Mon Sep 17 00:00:00 2001 From: Ludovica BRUSAFERRI Date: Thu, 19 Sep 2019 12:24:50 +0100 Subject: [PATCH 189/274] changed function detection efficiency so that is faster --- .../scatter_detection_modelling.cxx | 67 +++++++++---------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 885923cce3..5f3f0568ce 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -174,7 +174,7 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 30; + const int size = 28; const float increment_x = (HLD - LLD)/size; #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:sum) @@ -200,24 +200,24 @@ detection_model_with_fitted_parameters(const float x, const float energy) const //! We consider to have four terms: (i) gaussian model for the photopeak, (ii) compton plateau, (iii) flat continuum, (iv) exponential tale //! The model has be trained with 511 keV and tested with 370 keV. - const int Z = 66; // atomic number of LSO - const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section - const float H_2 = 9.33*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section - const float H_3 = 7; //fitting parameter - const float H_4 = 29.4; //fitting parameter - const float beta = -0.8401; //fitting parameter - const float global_scale = 0.29246*0.8*1e-06;//2.33*1e-07; //fitting parameter + //const int Z = 66; // atomic number of LSO + //const float H_1 = pow(Z,5)/energy; //the height of the photopeak is prop. to the photoelectric cross section + //const float H_2 = 9.33*pow(10,25)*total_Compton_cross_section(energy)*Z; // the eight of the compton plateau is proportional to the compton cross section + //const float H_3 = 7; //fitting parameter + //const float H_4 = 29.4; //fitting parameter + //const float beta = -0.8401; //fitting parameter + //const float global_scale = 0.29246*0.8*1e-06;//2.33*1e-07; //fitting parameter //const float fwhm = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); - const float fwhm = 0.14; - const float std_peak = energy*fwhm/2.35482; - const float scaling_std_compton = 28.3; //fitting parameter - const float shift_compton = 0.597; //fitting parameter - const float f1 = photoelectric(H_1, std_peak, x, energy); - const float f2 = compton_plateau(H_2, std_peak, x, energy, scaling_std_compton,shift_compton); - const float f3 = flat_continuum(H_3,std_peak, x, energy); - const float f4 = exponential_tail(H_4,std_peak, x, energy,beta); - - return global_scale*(f1+f2+f3+f4); + //const float fwhm = 0.14; + //const float std_peak = energy*fwhm/2.35482; + //const float scaling_std_compton = 28.3; //fitting parameter + //const float shift_compton = 0.597; //fitting parameter + const float f1 = photoelectric((66*66*66*66*66)/energy, (energy*0.14f)/2.35482f, x, energy); + const float f2 = compton_plateau(9.33f*1000000000000*10000000000000*total_Compton_cross_section(energy)*66, (energy*0.14f)/2.35482f, x, energy, 28.3f,0.597f); + const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); + const float f4 = exponential_tail(29.4f,(energy*0.14f)/2.35482f, x, energy,-0.8401f); + + return 0.29246f*0.8f*1e-06*(f1+f2+f3+f4); } float @@ -225,47 +225,44 @@ ScatterSimulation:: photoelectric(const float K, const float std_peak, const float x, const float energy) const { const float diff = x - energy; - const float pow_diff = pow(diff,2); - const float pow_std_peak = pow(std_peak,2); - return K/(std_peak*sqrt(2*M_PI))*exp(-pow_diff/(2*pow_std_peak)); + const float pow_diff = diff*diff; + const float pow_std_peak = std_peak*std_peak; + return K/(std_peak*2.5066f)*exp(-pow_diff/(2*pow_std_peak)); } float ScatterSimulation:: compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const { - const float m_0_c_2 = 511.F; + const float m_0_c_2 = 511.0f; const float alpha = energy/m_0_c_2; - const float E_1 = energy/(1+alpha*(1-cos(M_PI))); + const float E_1 = energy/(1+alpha*(2)); const float mean = energy*shift_compton; - return ((energy/E_1)+(E_1/energy)-1+cos(M_PI))*(K*exp(-(pow((x - mean),2))/(4*scaling_std_compton*std_peak))); + const float x_minus_mean = x - mean; + return ((energy/E_1)+(E_1/energy)-2)*(K*exp(-(x_minus_mean*x_minus_mean)/(4*scaling_std_compton*std_peak))); } float ScatterSimulation:: flat_continuum(const float K, const float std_peak, const float x, const float energy) const { - const float den = sqrt(2)*std_peak; - float f = 0; + const float den = 1.4142f*std_peak; if (x<=energy) - f = K* erfc((x-energy)/den); + return K* erfc((x-energy)/den); else - f = 0; - return f; + return 0; } float ScatterSimulation:: exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const { - const float den1 = sqrt(2)*M_PI*std_peak*beta; - const float den2 = sqrt(2)*std_peak; + const float den1 = 1.4142f*M_PI*std_peak*beta; + const float den2 = 1.4142f*std_peak; const float den3 = 2*beta; - float f; if (x > 100) //i am not sure of the behaviour of the function at too low energies - f = K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); + return K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); else - f = 0; - return f; + return 0; } float From 8ac5ba8aa4d9adc5ac87a0f41321fc12bcf73503 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 20 Sep 2019 14:48:13 +0100 Subject: [PATCH 190/274] gauss --- src/include/stir/scatter/ScatterSimulation.h | 2 +- src/scatter_buildblock/scatter_detection_modelling.cxx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 8520abe3ef..7f21900d97 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_gauss(const float energy, const int en_window = 0) const; + float detection_efficiency_numerical(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 5f3f0568ce..89d3cda901 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency_gauss(const float energy, const int en_window) const +detection_efficiency(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); @@ -249,7 +249,7 @@ flat_continuum(const float K, const float std_peak, const float x, const float e if (x<=energy) return K* erfc((x-energy)/den); else - return 0; + return 0; } float From 08115115267308b2a32f26860615d118cddf340c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Sep 2019 21:21:10 +0100 Subject: [PATCH 191/274] thread --- .../SingleScatterLikelihoodAndGradient.cxx | 7 +++---- src/scatter_buildblock/scatter_detection_modelling.cxx | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 25411d905b..3eff6253d0 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -924,15 +924,14 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector tmp_gradient_image(gradient_image_array[0]); + #ifdef STIR_OPENMP + #pragma omp parallel schedule(dynamic) + #endif for (int i = 0; i < static_cast(all_bins.size()); ++i) { - //creates a template image to fill tmp_gradient_image.fill(0); const Bin bin = all_bins[i]; - - - //forward model const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 89d3cda901..ed65bbb7e2 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -177,7 +177,7 @@ ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_en const int size = 28; const float increment_x = (HLD - LLD)/size; #ifdef STIR_OPENMP - #pragma omp parallel for reduction(+:sum) + #pragma omp parallel for reduction(+:sum) schedule(dynamic) #endif for(int i = 0 ; i< size; ++i) { From ea48428ed4ac810969024e5c9a99dcd63a90bf28 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Sep 2019 21:25:51 +0100 Subject: [PATCH 192/274] for --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 3eff6253d0..947720953f 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -925,7 +925,7 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector tmp_gradient_image(gradient_image_array[0]); #ifdef STIR_OPENMP - #pragma omp parallel schedule(dynamic) + #pragma omp parallel for schedule(dynamic) #endif for (int i = 0; i < static_cast(all_bins.size()); ++i) { From d092901b892caecae066d7eb166634cc340e7459 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Sep 2019 21:34:53 +0100 Subject: [PATCH 193/274] test --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../SingleScatterLikelihoodAndGradient.cxx | 6 +++--- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 7f21900d97..8520abe3ef 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_numerical(const float energy, const int en_window = 0) const; + float detection_efficiency_gauss(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 947720953f..278cb66036 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -924,9 +924,9 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector tmp_gradient_image(gradient_image_array[0]); - #ifdef STIR_OPENMP - #pragma omp parallel for schedule(dynamic) - #endif + // #ifdef STIR_OPENMP + // #pragma omp parallel for schedule(dynamic) + // #endif for (int i = 0; i < static_cast(all_bins.size()); ++i) { tmp_gradient_image.fill(0); diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index ed65bbb7e2..407a93274c 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy, const int en_window) const +detection_efficiency_gauss(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); From 2f9504b662a931e2d255da0174b5858ff1a0859e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Sep 2019 22:03:40 +0100 Subject: [PATCH 194/274] test --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../SingleScatterLikelihoodAndGradient.cxx | 8 ++++---- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 8520abe3ef..7f21900d97 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_gauss(const float energy, const int en_window = 0) const; + float detection_efficiency_numerical(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 278cb66036..268541ad23 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -922,13 +922,13 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector(all_bins.size())*this->output_proj_data_sptr->get_num_views()) error("SIZE is %d , but it should be %d",gradient_image_array.size(),static_cast(all_bins.size())); - VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); - // #ifdef STIR_OPENMP - // #pragma omp parallel for schedule(dynamic) - // #endif + #ifdef STIR_OPENMP + #pragma omp parallel for schedule(dynamic) + #endif for (int i = 0; i < static_cast(all_bins.size()); ++i) { + VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); tmp_gradient_image.fill(0); const Bin bin = all_bins[i]; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 407a93274c..ed65bbb7e2 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency_gauss(const float energy, const int en_window) const +detection_efficiency(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); From 5bef60ced2af8b152304495ae81a3dc3b793fd1d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Sep 2019 22:15:57 +0100 Subject: [PATCH 195/274] sss --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 268541ad23..015175d82c 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -927,7 +927,7 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector(all_bins.size()); ++i) - { + { //test VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); tmp_gradient_image.fill(0); From 00daf9aba841b42e021fc78332b8a4a893833408 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 24 Sep 2019 22:35:01 +0100 Subject: [PATCH 196/274] new model --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../SingleScatterLikelihoodAndGradient.cxx | 6 +++--- src/scatter_buildblock/scatter_detection_modelling.cxx | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 7f21900d97..8520abe3ef 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_numerical(const float energy, const int en_window = 0) const; + float detection_efficiency_gauss(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 015175d82c..4597cdb071 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -923,18 +923,18 @@ get_jacobian_for_viewgram(Viewgram& v_est,std::vector(all_bins.size())); - #ifdef STIR_OPENMP + #ifdef STIR_OPENMP #pragma omp parallel for schedule(dynamic) #endif for (int i = 0; i < static_cast(all_bins.size()); ++i) - { //test + { // this needs to be defined inside here to be thread-safe VoxelsOnCartesianGrid tmp_gradient_image(gradient_image_array[0]); tmp_gradient_image.fill(0); const Bin bin = all_bins[i]; const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); - v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); + v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(y); //this is passed as reference and filled in the loop gradient_image_array[i] += tmp_gradient_image; } diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index ed65bbb7e2..b8050611e4 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy, const int en_window) const +detection_efficiency_gauss(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,13 +168,13 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 28; + const int size = 30; const float increment_x = (HLD - LLD)/size; #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:sum) schedule(dynamic) From 7c8b7ebb5700cb3ac703f2aaf78a384bd09a2c51 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 12:44:01 +0100 Subject: [PATCH 197/274] shift --- src/scatter_buildblock/scatter_detection_modelling.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index b8050611e4..712925194f 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -127,7 +127,7 @@ ScatterSimulation::detection_spectrum(const float LLD, const float HLD, const fl float increment_x = (HLD - LLD)/size; for(int i = 0 ; i< size; ++i) { - energy_range[i]+= LLD+increment_x +i*increment_x; + energy_range[i]+= LLD +i*increment_x; out[i]+=0; } @@ -174,14 +174,14 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 30; + const int size = 20; const float increment_x = (HLD - LLD)/size; #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:sum) schedule(dynamic) #endif for(int i = 0 ; i< size; ++i) { - const float energy_range = LLD+increment_x +i*increment_x; + const float energy_range = LLD+i*increment_x; sum+= detection_model_with_fitted_parameters(energy_range, incoming_photon_energy); } From 6541912d9cdb8559c69b976a57c2ddf14324e6ea Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:33:05 +0100 Subject: [PATCH 198/274] global factor --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../SingleScatterLikelihoodAndGradient.cxx | 54 +++++-------------- .../scatter_detection_modelling.cxx | 4 +- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 8520abe3ef..7f21900d97 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_gauss(const float energy, const int en_window = 0) const; + float detection_efficiency_numerical(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 4597cdb071..61b65819f4 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -504,17 +504,18 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, // Single ScatterForward Model + const float line_integral1 = detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1); + const float line_integral2 = detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1); + const float line_integral1_times_activityA = line_integral1*emiss_to_detA; + const float line_integral2_times_activityB = line_integral2*emiss_to_detB; + const float global_factor = atten_to_detB*atten_to_detA*cos_incident_angle_AS*cos_incident_angle_BS*dif_Compton_cross_section_value*common_factor; + const float global_factor_times_mu = global_factor*scatter_point_mu; + float scatter_ratio=0; scatter_ratio= (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + *global_factor_times_mu; @@ -524,35 +525,18 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, float contribution_AS_mu = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* total_Compton_cross_section_relative_to_511keV(new_energy)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + *global_factor_times_mu; float contribution_BS_mu = (detection_probability_XY*emiss_to_detA* (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* (total_Compton_cross_section_relative_to_511keV(new_energy)) +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + *global_factor_times_mu; float contribution_S = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + *global_factor; /*Single Scatter Forward model Jacobian w.r.t. activity: @@ -561,22 +545,10 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, float contribution_AS_act = (detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + *global_factor_times_mu; float contribution_BS_act = (detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; + *global_factor_times_mu; //Fill gradient image along [A,S], [B,S] and in [S] diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 712925194f..49aace3324 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency_gauss(const float energy, const int en_window) const +detection_efficiency(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); From ff18bd9375e51ff73ec57c0cfeceb5bee5bb2be1 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:35:18 +0100 Subject: [PATCH 199/274] parentesis --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 61b65819f4..bd94d35758 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -528,8 +528,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, *global_factor_times_mu; float contribution_BS_mu = (detection_probability_XY*emiss_to_detA* - (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - (total_Compton_cross_section_relative_to_511keV(new_energy)) + (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)*total_Compton_cross_section_relative_to_511keV(new_energy) +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) *global_factor_times_mu; From 62b9747a76e6d44060e627a5cffbae760cd2e4c8 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:49:34 +0100 Subject: [PATCH 200/274] cleaned --- .../SingleScatterLikelihoodAndGradient.cxx | 91 +++++-------------- ...scatter_estimate_for_one_scatter_point.cxx | 17 +--- 2 files changed, 26 insertions(+), 82 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index bd94d35758..52af2c7f04 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -478,24 +478,11 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, #endif - //normalisation - - - // we will divide by the effiency of the detector pair for unscattered photons + //normalisation + // we will divide by the solid angle factors for unscattered photons // (computed with the same detection model as used in the scatter code) - // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. - - // there is a scatter_volume factor for every scatter point, as the sum over scatter points - // is an approximation for the integral over the scatter point. - - // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code - - - // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window - //find the window that contains 511 keV - + // the energy dependency is left out - //normalisation factor between trues and scattered counts const double common_factor = 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * @@ -504,93 +491,61 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, // Single ScatterForward Model - const float line_integral1 = detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1); - const float line_integral2 = detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1); - const float line_integral1_times_activityA = line_integral1*emiss_to_detA; - const float line_integral2_times_activityB = line_integral2*emiss_to_detB; - const float global_factor = atten_to_detB*atten_to_detA*cos_incident_angle_AS*cos_incident_angle_BS*dif_Compton_cross_section_value*common_factor; - const float global_factor_times_mu = global_factor*scatter_point_mu; + const double line_integral1 = detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1); + const double line_integral2 = detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1); + const double line_integral1_times_activityA = line_integral1*emiss_to_detA; + const double line_integral2_times_activityB = line_integral2*emiss_to_detB; + const double global_factor = atten_to_detB*atten_to_detA*cos_incident_angle_AS*cos_incident_angle_BS*dif_Compton_cross_section_value*common_factor; + const double global_factor_times_mu = global_factor*scatter_point_mu; float scatter_ratio=0; - scatter_ratio= (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *global_factor_times_mu; - + scatter_ratio = (line_integral1_times_activityA+line_integral2_times_activityB)*global_factor_times_mu; /*Single Scatter Forward model Jacobian w.r.t. attenuation: * The derivative is given by three terms, respectively in [A,S], [B,S] and [S] */ - float contribution_AS_mu = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - total_Compton_cross_section_relative_to_511keV(new_energy)) - *global_factor_times_mu; + float contribution_AS_mu = (line_integral1_times_activityA+line_integral2_times_activityB*total_Compton_cross_section_relative_to_511keV(new_energy)) + *global_factor_times_mu; - float contribution_BS_mu = (detection_probability_XY*emiss_to_detA* - (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)*total_Compton_cross_section_relative_to_511keV(new_energy) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* - pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *global_factor_times_mu; + float contribution_BS_mu = (line_integral1_times_activityA*total_Compton_cross_section_relative_to_511keV(new_energy)+line_integral2_times_activityB*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) + *global_factor_times_mu; - float contribution_S = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *global_factor; + float contribution_S = (line_integral1_times_activityA+line_integral2_times_activityB) + *global_factor; /*Single Scatter Forward model Jacobian w.r.t. activity: - * * The derivative is given by two terms, respectively in [A,S] and [B,S] */ - float contribution_AS_act = (detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *global_factor_times_mu; - - float contribution_BS_act = (detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *global_factor_times_mu; - + float contribution_AS_act = line_integral1*global_factor_times_mu; + float contribution_BS_act = line_integral2*global_factor_times_mu; //Fill gradient image along [A,S], [B,S] and in [S] - if(compute_gradient) { if (isgradient_mu) { - line_contribution(gradient,rescale,scatter_point, - detector_coord_B,contribution_BS_mu); - - line_contribution(gradient,rescale,scatter_point, - detector_coord_A,contribution_AS_mu); - - s_contribution(gradient,scatter_point, - contribution_S); - + line_contribution(gradient,rescale,scatter_point,detector_coord_B,contribution_BS_mu); + line_contribution(gradient,rescale,scatter_point, detector_coord_A,contribution_AS_mu); + s_contribution(gradient,scatter_point,contribution_S); } - else { - - line_contribution_act(gradient,scatter_point, - detector_coord_B,contribution_BS_act); - - line_contribution_act(gradient,scatter_point, - detector_coord_A,contribution_AS_act); + line_contribution_act(gradient,scatter_point,detector_coord_B,contribution_BS_act); + line_contribution_act(gradient,scatter_point, detector_coord_A,contribution_AS_act); } } - - - return scatter_ratio; - } - - void SingleScatterLikelihoodAndGradient:: L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index f3aa69ac99..b64ea74f5f 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -207,21 +207,10 @@ detection_efficiency_unscattered.push_back(0); #endif - // we will divide by the effiency of the detector pair for unscattered photons + //normalisation + // we will divide by the solid angle factors for unscattered photons // (computed with the same detection model as used in the scatter code) - // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. - - // there is a scatter_volume factor for every scatter point, as the sum over scatter points - // is an approximation for the integral over the scatter point. - - // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code - - - // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window - //find the window that contains 511 keV - - - //normalisation factor between trues and scattered counts + // the energy dependency is left out const double common_factor = 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * From 444e957ecd6a8c8690a983544d70bbe7afd7745e Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:51:06 +0100 Subject: [PATCH 201/274] efficiency --- src/include/stir/scatter/ScatterSimulation.h | 2 +- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 7f21900d97..8520abe3ef 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_numerical(const float energy, const int en_window = 0) const; + float detection_efficiency_gauss(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 49aace3324..712925194f 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency(const float energy, const int en_window) const +detection_efficiency_gauss(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency_numerical(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); From fd690485f8320149ac1c1cde3272febee8a07992 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:53:59 +0100 Subject: [PATCH 202/274] test omp --- .../SingleScatterLikelihoodAndGradient.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 52af2c7f04..ba02a10791 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -746,10 +746,15 @@ get_jacobian(std::vector > &gradient_image_array,co int axial_bins = 0 ; double sum = 0; + #ifdef STIR_OPENMP + #pragma omp parallel for reduction(+:axial_bins) schedule(dynamic) + #endif for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + { + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); + } const int total_bins = this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * From 2e8a6e9a8341f7b1e519f57234636c064c31ef55 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:56:34 +0100 Subject: [PATCH 203/274] segm --- .../SingleScatterLikelihoodAndGradient.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index ba02a10791..5cd08a6a89 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -741,7 +741,7 @@ get_jacobian(std::vector > &gradient_image_array,co this->initialise_cache_for_scattpoint_det_integrals_over_activity(); ViewSegmentNumbers vs_num; - + int segm_num = vs_num.segment_num(); int bin_counter = 0; int axial_bins = 0 ; double sum = 0; @@ -749,9 +749,9 @@ get_jacobian(std::vector > &gradient_image_array,co #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:axial_bins) schedule(dynamic) #endif - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) + for (segm_num = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + segm_num <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++segm_num { axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); } From 9ce951536aff9295b1dabda3d7c554477ebfa463 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:56:57 +0100 Subject: [PATCH 204/274] fix --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 5cd08a6a89..437e4e4b8a 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -751,7 +751,7 @@ get_jacobian(std::vector > &gradient_image_array,co #endif for (segm_num = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); segm_num <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++segm_num + ++segm_num) { axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); } From b4ef92ba4f235d680355ae80a5c21b6d0313c881 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 14:58:11 +0100 Subject: [PATCH 205/274] test --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 437e4e4b8a..9c73b8b00f 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -752,9 +752,7 @@ get_jacobian(std::vector > &gradient_image_array,co for (segm_num = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); segm_num <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); ++segm_num) - { axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - } const int total_bins = this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * From c4f7fef1b2725c1277bbd56f988c28078aa49ab7 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 15:10:47 +0100 Subject: [PATCH 206/274] test --- .../SingleScatterLikelihoodAndGradient.cxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 9c73b8b00f..f6ec82ccc3 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -740,8 +740,6 @@ get_jacobian(std::vector > &gradient_image_array,co this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - ViewSegmentNumbers vs_num; - int segm_num = vs_num.segment_num(); int bin_counter = 0; int axial_bins = 0 ; double sum = 0; @@ -749,9 +747,12 @@ get_jacobian(std::vector > &gradient_image_array,co #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:axial_bins) schedule(dynamic) #endif - for (segm_num = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - segm_num <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++segm_num) + + ViewSegmentNumbers vs_num; + for (vs_num.segment_num()= this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); + vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); + ++vs_num.segment_num()) + axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); const int total_bins = From 0833218bb514c5f6a8b4528b0cbbc6d76db1db02 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 15:12:22 +0100 Subject: [PATCH 207/274] remove for --- .../SingleScatterLikelihoodAndGradient.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index f6ec82ccc3..77b7714bf8 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -744,9 +744,9 @@ get_jacobian(std::vector > &gradient_image_array,co int axial_bins = 0 ; double sum = 0; - #ifdef STIR_OPENMP - #pragma omp parallel for reduction(+:axial_bins) schedule(dynamic) - #endif +// #ifdef STIR_OPENMP +// #pragma omp parallel for reduction(+:axial_bins) schedule(dynamic) +// #endif ViewSegmentNumbers vs_num; for (vs_num.segment_num()= this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); From 4b0778af0eab99c5f5be304f8e77e86aec946881 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 15:13:30 +0100 Subject: [PATCH 208/274] remove for2 --- src/scatter_buildblock/scatter_detection_modelling.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 712925194f..84c781092b 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -213,7 +213,7 @@ detection_model_with_fitted_parameters(const float x, const float energy) const //const float scaling_std_compton = 28.3; //fitting parameter //const float shift_compton = 0.597; //fitting parameter const float f1 = photoelectric((66*66*66*66*66)/energy, (energy*0.14f)/2.35482f, x, energy); - const float f2 = compton_plateau(9.33f*1000000000000*10000000000000*total_Compton_cross_section(energy)*66, (energy*0.14f)/2.35482f, x, energy, 28.3f,0.597f); + const float f2 = compton_plateau(9.33f*10E25*total_Compton_cross_section(energy)*66, (energy*0.14f)/2.35482f, x, energy, 28.3f,0.597f); const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); const float f4 = exponential_tail(29.4f,(energy*0.14f)/2.35482f, x, energy,-0.8401f); From 3dc006f621bc0ecf2ff85e35856fff10d6ef3a2f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 15:21:41 +0100 Subject: [PATCH 209/274] test 210 --- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 84c781092b..03e6af3c2b 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -213,7 +213,7 @@ detection_model_with_fitted_parameters(const float x, const float energy) const //const float scaling_std_compton = 28.3; //fitting parameter //const float shift_compton = 0.597; //fitting parameter const float f1 = photoelectric((66*66*66*66*66)/energy, (energy*0.14f)/2.35482f, x, energy); - const float f2 = compton_plateau(9.33f*10E25*total_Compton_cross_section(energy)*66, (energy*0.14f)/2.35482f, x, energy, 28.3f,0.597f); + const float f2 = compton_plateau(9.33f*1e+25*total_Compton_cross_section(energy)*66, (energy*0.14f)/2.35482f, x, energy, 28.3f,0.597f); const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); const float f4 = exponential_tail(29.4f,(energy*0.14f)/2.35482f, x, energy,-0.8401f); @@ -259,7 +259,7 @@ exponential_tail(const float K, const float std_peak, const float x, const float const float den1 = 1.4142f*M_PI*std_peak*beta; const float den2 = 1.4142f*std_peak; const float den3 = 2*beta; - if (x > 100) //i am not sure of the behaviour of the function at too low energies + if (x > 210) //i am not sure of the behaviour of the function at too low energies return K * exp((x-energy)/den1)*erfc((x-energy)/den2+1/den3); else return 0; From 5fa6eab1984230d2f4ed161ccf41a4cb1c316613 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 16:15:27 +0100 Subject: [PATCH 210/274] code fixed --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../scatter_detection_modelling.cxx | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 8520abe3ef..fa0ce2d072 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -215,7 +215,7 @@ class ScatterSimulation : public RegisteredObject, float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; - std::vector detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; + std::vector detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; float compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 03e6af3c2b..d24cc5052d 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -118,25 +118,25 @@ detection_efficiency_gauss(const float energy, const int en_window) const return efficiency; } -std::vector +std::vector ScatterSimulation::detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const { - std::vector energy_range(size); - std::vector out(size); - float increment_x = (HLD - LLD)/size; - for(int i = 0 ; i< size; ++i) + std::vector output(size); + double increment_x = (HLD - LLD) / (size - 1); + + for(int i = 0; i < size; ++i) { - energy_range[i]+= LLD +i*increment_x; - out[i]+=0; + output[i] = LLD + (i * increment_x); + std::cout << output[i] << std::endl; } - for(int j = 0; j < size; ++j) + for(int i = 0; i < size; ++i) { - out[j]+= detection_model_with_fitted_parameters(energy_range[j], incoming_photon_energy); + output[i] = detection_model_with_fitted_parameters(output[i], incoming_photon_energy); } - return out; + return output; } float @@ -174,8 +174,8 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 20; - const float increment_x = (HLD - LLD)/size; + const int size = 30; + double increment_x = (HLD - LLD) / (size - 1); #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:sum) schedule(dynamic) #endif From d32404fa0879323b0607a47ad061144af4418f6f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 16:40:25 +0100 Subject: [PATCH 211/274] sr --- src/scatter_buildblock/scatter_detection_modelling.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index d24cc5052d..091260c6b1 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -174,8 +174,9 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 30; + const int size = 10; double increment_x = (HLD - LLD) / (size - 1); + #ifdef STIR_OPENMP #pragma omp parallel for reduction(+:sum) schedule(dynamic) #endif @@ -183,9 +184,9 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons { const float energy_range = LLD+i*increment_x; sum+= detection_model_with_fitted_parameters(energy_range, incoming_photon_energy); + sum*=increment_x; } - sum*=increment_x; return sum; } From aa7400a7bd1b0653182787e02d75f4e836e4e6c6 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 16:54:24 +0100 Subject: [PATCH 212/274] three terms --- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 091260c6b1..bbb32f4031 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -174,7 +174,7 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 10; + const int size = 30; double increment_x = (HLD - LLD) / (size - 1); #ifdef STIR_OPENMP @@ -218,7 +218,7 @@ detection_model_with_fitted_parameters(const float x, const float energy) const const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); const float f4 = exponential_tail(29.4f,(energy*0.14f)/2.35482f, x, energy,-0.8401f); - return 0.29246f*0.8f*1e-06*(f1+f2+f3+f4); + return 0.29246f*0.8f*1e-06*(f1+f2+f3); } float From 046867bdbcd292f771ab19ef68c7f09fd31d649f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 16:54:35 +0100 Subject: [PATCH 213/274] three terms2 --- src/scatter_buildblock/scatter_detection_modelling.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index bbb32f4031..1f0d262567 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -184,9 +184,8 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons { const float energy_range = LLD+i*increment_x; sum+= detection_model_with_fitted_parameters(energy_range, incoming_photon_energy); - sum*=increment_x; } - + sum*=increment_x; return sum; } From cd73be47bc64adfbe4951ebfd3430f8529b4f367 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 17:06:18 +0100 Subject: [PATCH 214/274] test --- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 1f0d262567..06ac102dd2 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -174,7 +174,7 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 30; + const int size = 10; double increment_x = (HLD - LLD) / (size - 1); #ifdef STIR_OPENMP @@ -217,7 +217,7 @@ detection_model_with_fitted_parameters(const float x, const float energy) const const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); const float f4 = exponential_tail(29.4f,(energy*0.14f)/2.35482f, x, energy,-0.8401f); - return 0.29246f*0.8f*1e-06*(f1+f2+f3); + return 0.29246f*0.8f*1e-06*(f1+f2); } float From 6fd4bb692b35cc4f7582e1476c3082223db0bebe Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 17:11:26 +0100 Subject: [PATCH 215/274] test3 --- src/scatter_buildblock/scatter_detection_modelling.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 06ac102dd2..48380ad9b1 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -174,7 +174,7 @@ ScatterSimulation::detection_efficiency(const float incoming_photon_energy, cons const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); const float LLD = this->template_exam_info_sptr->get_low_energy_thres(en_window); float sum = 0; - const int size = 10; + const int size = 30; double increment_x = (HLD - LLD) / (size - 1); #ifdef STIR_OPENMP From c821ecb22a64d1bf14dc757d0123fc8d165d9117 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 25 Sep 2019 17:44:31 +0100 Subject: [PATCH 216/274] test --- src/scatter_buildblock/scatter_detection_modelling.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 48380ad9b1..5bdc68b052 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -217,7 +217,7 @@ detection_model_with_fitted_parameters(const float x, const float energy) const const float f3 = flat_continuum(7,(energy*0.14f)/2.35482f, x, energy); const float f4 = exponential_tail(29.4f,(energy*0.14f)/2.35482f, x, energy,-0.8401f); - return 0.29246f*0.8f*1e-06*(f1+f2); + return 0.29246f*0.8f*1e-06*(f1+f2+f3+f4); } float From 860e1f6344a1289330ecaa376cb5701ad01ab937 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 27 Sep 2019 16:12:05 +0100 Subject: [PATCH 217/274] test ecat --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 602c4b794b..9311ef5d70 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -107,8 +107,8 @@ get_next_record(CListRecordROOT& record) crystal2 -= half_block; // Add offset - crystal1 += offset_dets; - crystal2 += offset_dets; + crystal1 -= offset_dets; + crystal2 -= offset_dets; return record.init_from_data(ring1, ring2, From c081302b6a43f760766cd08ce6218ff82e739aa4 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 27 Sep 2019 16:40:25 +0100 Subject: [PATCH 218/274] positive crystal --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 9311ef5d70..602c4b794b 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -107,8 +107,8 @@ get_next_record(CListRecordROOT& record) crystal2 -= half_block; // Add offset - crystal1 -= offset_dets; - crystal2 -= offset_dets; + crystal1 += offset_dets; + crystal2 += offset_dets; return record.init_from_data(ring1, ring2, From ae7fbe5a93bffb2222ee385885e0c809455696df Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 27 Sep 2019 16:48:09 +0100 Subject: [PATCH 219/274] negative --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 602c4b794b..9311ef5d70 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -107,8 +107,8 @@ get_next_record(CListRecordROOT& record) crystal2 -= half_block; // Add offset - crystal1 += offset_dets; - crystal2 += offset_dets; + crystal1 -= offset_dets; + crystal2 -= offset_dets; return record.init_from_data(ring1, ring2, From c8d633bffe504a4a03c2c30c898006b07bd27636 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 27 Sep 2019 16:49:56 +0100 Subject: [PATCH 220/274] negative --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 9311ef5d70..602c4b794b 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -107,8 +107,8 @@ get_next_record(CListRecordROOT& record) crystal2 -= half_block; // Add offset - crystal1 -= offset_dets; - crystal2 -= offset_dets; + crystal1 += offset_dets; + crystal2 += offset_dets; return record.init_from_data(ring1, ring2, From 1ca3f19aa6b9bb67bcb3167a08e96eb6470e392f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 27 Sep 2019 16:54:21 +0100 Subject: [PATCH 221/274] negative --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 602c4b794b..9311ef5d70 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -107,8 +107,8 @@ get_next_record(CListRecordROOT& record) crystal2 -= half_block; // Add offset - crystal1 += offset_dets; - crystal2 += offset_dets; + crystal1 -= offset_dets; + crystal2 -= offset_dets; return record.init_from_data(ring1, ring2, From c5c000446cfd933fbaf93b4377166e909ce715b4 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 2 Oct 2019 16:53:22 +0100 Subject: [PATCH 222/274] fixed bug in default --- src/include/stir/ExamInfo.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index 615ffd60ba..1a66e013ab 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -59,14 +59,14 @@ public : : start_time_in_secs_since_1970(0.) { - num_windows = -1; + num_windows = 1; low_energy_thres.resize(1); up_energy_thres.resize(1); en_win_pair.resize(2); - low_energy_thres[0]=-1.F; - up_energy_thres[0]=-1.F; - en_win_pair[0]=-1.F; - en_win_pair[1]=-1.F; + low_energy_thres[0]=1.F; + up_energy_thres[0]=1.F; + en_win_pair[0]=1.F; + en_win_pair[1]=1.F; } From bdb0c40346d03d8b51cb8a345cdc7f56cab8219c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 8 Oct 2019 17:09:58 +0100 Subject: [PATCH 223/274] norm --- .../upsample_and_fit_scatter_estimate.cxx | 30 +++---------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx index 831cadd58d..7a3f9a3406 100644 --- a/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx +++ b/src/scatter_buildblock/upsample_and_fit_scatter_estimate.cxx @@ -264,32 +264,10 @@ for (vs_num.segment_num() = norm.get_min_segment_num(); vs_num.segment_num() <= for (vs_num.view_num() = norm.get_min_view_num();vs_num.view_num() <= norm.get_max_view_num(); ++vs_num.view_num()) { - Viewgram viewgram_n = norm.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - Viewgram viewgram_in = projdata.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - Viewgram viewgram_out = projdata_out.get_empty_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - const ViewSegmentNumbers vs_num(viewgram_n.get_view_num(),viewgram_n.get_segment_num()); - std::vector all_bins; - { - Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); - for (bin.axial_pos_num() = norm.get_min_axial_pos_num(bin.segment_num()); bin.axial_pos_num() <= norm.get_max_axial_pos_num(bin.segment_num()); ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = norm.get_min_tangential_pos_num(); bin.tangential_pos_num() <= norm.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - { - all_bins.push_back(bin); - } - } - } - - for (int i = 0; i < static_cast(all_bins.size()); ++i) - { - - const Bin bin = all_bins[i]; - - viewgram_out[bin.axial_pos_num()][bin.tangential_pos_num()]=viewgram_in[bin.axial_pos_num()][bin.tangential_pos_num()]*viewgram_n[bin.axial_pos_num()][bin.tangential_pos_num()]; - } - - projdata_out.set_viewgram(viewgram_out); - + Viewgram viewgram_n = norm.get_viewgram(vs_num.view_num(), vs_num.segment_num()); + Viewgram viewgram_in = projdata.get_viewgram(vs_num.view_num(), vs_num.segment_num()); + viewgram_in *= viewgram_n; + projdata_out.set_viewgram(viewgram_in); } } From 0bcb3f3fa780d1cea6f8ce42332f35c95c7d3469 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 17 Oct 2019 12:41:06 +0100 Subject: [PATCH 224/274] energy threshold from listmode to projdata --- src/include/stir/ExamInfo.h | 4 -- src/include/stir/ExamInfo.inl | 18 ------- src/include/stir/listmode/LmToProjData.h | 1 + src/listmode_buildblock/CListModeDataROOT.cxx | 34 +------------- src/listmode_buildblock/LmToProjData.cxx | 47 ++++++++++++++----- 5 files changed, 38 insertions(+), 66 deletions(-) diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index 1a66e013ab..e6c7da13cb 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -94,10 +94,6 @@ public : //! Get the high energy boundary inline float get_high_energy_thres(int en_window = 0) const; - inline std::vector get_low_energy_thres_vect() const; - //! Get the high energy boundary - inline std::vector get_high_energy_thres_vect() const; - //! Get the number of energy windows inline int get_num_energy_windows() const; inline std::pair get_energy_window_pair() const; diff --git a/src/include/stir/ExamInfo.inl b/src/include/stir/ExamInfo.inl index e7af9642a5..2283ce53e4 100644 --- a/src/include/stir/ExamInfo.inl +++ b/src/include/stir/ExamInfo.inl @@ -122,24 +122,6 @@ ExamInfo::get_high_energy_thres(int en_window) const } -std::vector -ExamInfo::get_low_energy_thres_vect() const -{ - return low_energy_thres; - -} - -//Get the high energy boundary for all the energy windows. en_window is set to 0 by default -//So that it will work also in the case of 1 energy window - -std::vector -ExamInfo::get_high_energy_thres_vect() const -{ - - return up_energy_thres; - -} - //Get the number of energy windows int ExamInfo::get_num_energy_windows() const diff --git a/src/include/stir/listmode/LmToProjData.h b/src/include/stir/listmode/LmToProjData.h index 7a81eda471..9665c32133 100644 --- a/src/include/stir/listmode/LmToProjData.h +++ b/src/include/stir/listmode/LmToProjData.h @@ -233,6 +233,7 @@ class LmToProjData : public ParsingObject bool interactive; shared_ptr template_proj_data_info_ptr; + shared_ptr template_proj_data_ptr; //! This will be used for pre-normalisation shared_ptr normalisation_ptr; //! This will be used for post-normalisation diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 4e882003a5..41c2d0cf3c 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -71,41 +71,9 @@ CListModeDataROOT(const std::string& hroot_filename) // ExamInfo initialisation this->exam_info_sptr.reset(new ExamInfo); - // Only PET scanners supported + // Only PET scanners supported this->exam_info_sptr->imaging_modality = ImagingModality::PT; this->exam_info_sptr->originating_system = this->originating_system; - this->exam_info_sptr->set_num_energy_windows(this->root_file_sptr->get_number_of_energy_windows()); - - this->exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres_in_keV()); - this->exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres_in_keV()); - - for(int i =0; iexam_info_sptr->get_num_energy_windows(); ++i) - if (this->exam_info_sptr->get_high_energy_thres(i)<=this->exam_info_sptr->get_low_energy_thres(i)) - error("the upper energy threshold needs to be higher than the lower energy threshold"); - - std::vector val; - val.resize(2); - if(this->root_file_sptr->get_low_energy_thres_in_keV()[0]>this->root_file_sptr->get_low_energy_thres_in_keV()[1]) - {val[0]=1; - val[1]=2;} - else if(this->root_file_sptr->get_low_energy_thres_in_keV()[0]root_file_sptr->get_low_energy_thres_in_keV()[1]) - {val[0]=2; - val[1]=1; - this->exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres_in_keV(),true); - this->exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres_in_keV(),true);} - else if(this->root_file_sptr->get_low_energy_thres_in_keV()[0]==this->root_file_sptr->get_low_energy_thres_in_keV()[1]) - {val[0]=1; - val[1]=1; - if(this->exam_info_sptr->get_num_energy_windows() > 1) - {std::vector low_t = this->root_file_sptr->get_low_energy_thres_in_keV(); - std::vector up_t = this->root_file_sptr->get_up_energy_thres_in_keV(); - low_t[1]=350; - up_t[1]=460; - this->exam_info_sptr->set_low_energy_thres_vect(low_t); - this->exam_info_sptr->set_high_energy_thres_vect(up_t);} - } - this->exam_info_sptr->set_energy_window_pair(val,1); - shared_ptr this_scanner_sptr; diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index ae602a8051..b85cbc42e8 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -213,7 +213,7 @@ post_processing() warning("You have to specify template_projdata\n"); return true; } - shared_ptr template_proj_data_ptr = + template_proj_data_ptr = ProjData::read_from_file(template_proj_data_name); template_proj_data_info_ptr.reset(template_proj_data_ptr->get_proj_data_info_ptr()->clone()); @@ -528,8 +528,27 @@ process_data() // few coincidence events (as happens with ECAT scanners) current_time = 0; + float low_thres_A = template_proj_data_ptr->get_exam_info().get_low_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1); + float high_thres_A = template_proj_data_ptr->get_exam_info().get_high_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1); + float low_thres_B = template_proj_data_ptr->get_exam_info().get_low_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1); + float high_thres_B = template_proj_data_ptr->get_exam_info().get_high_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1); + int num_en_windows = template_proj_data_ptr->get_exam_info().get_num_energy_windows(); + std::vector high_en_thres(num_en_windows); + std::vector low_en_thres(num_en_windows); + std::vector energy_window_pair(2); + energy_window_pair[0]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().first; + energy_window_pair[1]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().second; + + for (int i = 0; i< num_en_windows; ++i) + { + low_en_thres[i] = template_proj_data_ptr->get_exam_info().get_low_energy_thres(i); + high_en_thres[i] = template_proj_data_ptr->get_exam_info().get_high_energy_thres(i); + } + + double time_of_last_stored_event = 0; long num_stored_events = 0; + VectorWithOffset segments (template_proj_data_info_ptr->get_min_segment_num(), template_proj_data_info_ptr->get_max_segment_num()); @@ -538,7 +557,6 @@ process_data() frame_start_positions(1, static_cast(frame_defs.get_num_frames())); shared_ptr record_sptr = lm_data_ptr->get_empty_record_sptr(); CListRecord& record = *record_sptr; - if (!record.event().is_valid_template(*template_proj_data_info_ptr)) error("The scanner template is not valid for LmToProjData. This might be because of unsupported arc correction."); @@ -565,14 +583,18 @@ process_data() char rest[50]; sprintf(rest, "_f%dg1d0b0", current_frame_num); const string output_filename = output_filename_prefix + rest; - + this_frame_exam_info.set_num_energy_windows(num_en_windows); + this_frame_exam_info.set_high_energy_thres_vect(high_en_thres); + this_frame_exam_info.set_low_energy_thres_vect(low_en_thres); + this_frame_exam_info.set_energy_window_pair(energy_window_pair,num_en_windows); + proj_data_ptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); + } long num_prompts_in_frame = 0; long num_delayeds_in_frame = 0; - const double start_time = frame_defs.get_start_time(current_frame_num); const double end_time = frame_defs.get_end_time(current_frame_num); @@ -647,7 +669,7 @@ process_data() // note: could do "else if" here if we would be sure that // a record can never be both timing and coincidence event // and there might be a scanner around that has them both combined. - if (record.is_event()) + if (record.is_event()) { assert(start_time <= current_time); @@ -661,14 +683,16 @@ process_data() if (bin.get_bin_value()>0 && bin.tangential_pos_num()>= proj_data_ptr->get_min_tangential_pos_num() && bin.tangential_pos_num()<= proj_data_ptr->get_max_tangential_pos_num() - && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) - && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) - ) + && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) + && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) + && record.energy().get_energyA_in_keV() >= low_thres_A + && record.energy().get_energyA_in_keV() <= high_thres_A + && record.energy().get_energyB_in_keV() >= low_thres_B + && record.energy().get_energyB_in_keV() <= high_thres_B) { - std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; - std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; - + std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; + std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); assert(bin.view_num()<=proj_data_ptr->get_max_view_num()); @@ -686,6 +710,7 @@ process_data() // now check if we have its segment in memory if (bin.segment_num() >= start_segment_index && bin.segment_num()<=end_segment_index) + { do_post_normalisation(bin); From e5933840c225a1c38c23fe167cfbec5e2f7ea63f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 21 Oct 2019 10:56:01 +0100 Subject: [PATCH 225/274] remove scatter --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 4 +--- .../scatter_estimate_for_one_scatter_point.cxx | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 77b7714bf8..f5728a19e6 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -484,9 +484,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, // the energy dependency is left out - const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * - scatter_volume/total_Compton_cross_section_511keV; + const double common_factor = scatter_volume/total_Compton_cross_section_511keV; // Single ScatterForward Model diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index b64ea74f5f..970b3b0e84 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -212,9 +212,7 @@ detection_efficiency_unscattered.push_back(0); // (computed with the same detection model as used in the scatter code) // the energy dependency is left out - const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * - scatter_volume/total_Compton_cross_section_511keV; + const double common_factor = scatter_volume/total_Compton_cross_section_511keV; float scatter_ratio=0 ; From 0fdc6e4b014aa037fbb4765d143428a078183513 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 22 Oct 2019 17:08:10 +0100 Subject: [PATCH 226/274] added swapping in time and energy --- src/IO/InputStreamFromROOTFileForECATPET.cxx | 4 ++-- src/include/stir/listmode/CListRecordROOT.h | 16 ++++++++++++---- src/listmode_buildblock/CListRecordROOT.cxx | 20 +++++++++++++++++--- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 9311ef5d70..602c4b794b 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -107,8 +107,8 @@ get_next_record(CListRecordROOT& record) crystal2 -= half_block; // Add offset - crystal1 -= offset_dets; - crystal2 -= offset_dets; + crystal1 += offset_dets; + crystal2 += offset_dets; return record.init_from_data(ring1, ring2, diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index 42e3aa26be..11fc3ecf6c 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -236,12 +236,20 @@ class CListRecordROOT : public CListRecord // currently no gating yet this->event_data.init_from_data(ring1, ring2, crystal1, crystal2); + if(this->event().is_swapped()) + { + this->time_data.init_from_data(time2,time1); - this->time_data.init_from_data( - time1,time2); + this->energy_data.init_energy_from_data(energy2,energy1); + } - this->energy_data.init_energy_from_data( - energy1,energy2); + + else + { + this->time_data.init_from_data(time1,time2); + + this->energy_data.init_energy_from_data(energy1,energy2); + } // We can make a singature raw based on the two events IDs. // It is pretty unique. diff --git a/src/listmode_buildblock/CListRecordROOT.cxx b/src/listmode_buildblock/CListRecordROOT.cxx index 0da2703d59..d3242f142d 100644 --- a/src/listmode_buildblock/CListRecordROOT.cxx +++ b/src/listmode_buildblock/CListRecordROOT.cxx @@ -88,9 +88,23 @@ void CListEventROOT::init_from_data(const int& _ring1, const int& _ring2, else if ( det2 >= scanner_sptr->get_num_detectors_per_ring()) det2 = det2 - scanner_sptr->get_num_detectors_per_ring(); - ring1 = _ring1; - ring2 = _ring2; - swapped = false; + if (((det1 + det2 < 3*scanner_sptr->get_num_detectors_per_ring()/4) && (det1-det2 > 0)) + ||((det1 + det2 > 3*scanner_sptr->get_num_detectors_per_ring()/4)&&(det1-det2 < 0))) + { + int tmp = det1; + det1 = det2; + det2 = tmp; + + ring1 = _ring2; + ring2 = _ring1; + swapped = true; + } + else + { + ring1 = _ring1; + ring2 = _ring2; + swapped = false; + } } END_NAMESPACE_STIR From 2e133f7a63414ed1c5423e5d03ad2ab952459292 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 22 Oct 2019 18:04:36 +0100 Subject: [PATCH 227/274] scatter max angle --- .../SingleScatterLikelihoodAndGradient.cxx | 8 ++++---- .../scatter_estimate_for_one_scatter_point.cxx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index f5728a19e6..c77f042028 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -319,7 +319,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. - int low = 0; + /* int low = 0; if (this->template_exam_info_sptr->get_num_energy_windows()>1) @@ -345,7 +345,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), 2.f, this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); - +*/ //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); const CartesianCoordinate3D& scatter_point = @@ -360,8 +360,8 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, detector_coord_B - scatter_point)); // note: costheta is identical for scatter to A or scatter to B // Hence, the Compton_cross_section and energy are identical for both cases as well. - if(max_single_scatter_cos_angle>costheta) - return 0; + // if(max_single_scatter_cos_angle>costheta) + // return 0; const float new_energy = photon_energy_after_Compton_scatter_511keV(costheta); diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 970b3b0e84..d4b9e70133 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -60,7 +60,7 @@ SingleScatterSimulation:: int low = 0; // TODO: check that the selected windows don't overcome the max num windows - + /* if (this->template_exam_info_sptr->get_num_energy_windows()>1) { @@ -87,7 +87,7 @@ SingleScatterSimulation:: static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), 2.f, this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); - +*/ //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); const CartesianCoordinate3D& scatter_point = @@ -102,8 +102,8 @@ SingleScatterSimulation:: detector_coord_B - scatter_point)); // note: costheta is identical for scatter to A or scatter to B // Hence, the Compton_cross_section and energy are identical for both cases as well. - if(max_single_scatter_cos_angle>costheta) - return 0; + // if(max_single_scatter_cos_angle>costheta) + // return 0; const float new_energy = photon_energy_after_Compton_scatter_511keV(costheta); From f05cd0f6b43c3e73f40ca2f337acd1cdf07bdc36 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 23 Oct 2019 12:09:29 +0100 Subject: [PATCH 228/274] swap energy --- src/include/stir/listmode/CListRecordROOT.h | 2 ++ src/listmode_buildblock/LmToProjData.cxx | 9 ++++++++- .../SingleScatterLikelihoodAndGradient.cxx | 8 ++++---- .../scatter_estimate_for_one_scatter_point.cxx | 10 +++++----- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index 11fc3ecf6c..b6c2e7e833 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -238,6 +238,7 @@ class CListRecordROOT : public CListRecord // currently no gating yet crystal1, crystal2); if(this->event().is_swapped()) { + //std::cout << "I m swapped" << std::endl; this->time_data.init_from_data(time2,time1); this->energy_data.init_energy_from_data(energy2,energy1); @@ -246,6 +247,7 @@ class CListRecordROOT : public CListRecord // currently no gating yet else { + //std::cout << "I m not swapped" << std::endl; this->time_data.init_from_data(time1,time2); this->energy_data.init_energy_from_data(energy1,energy2); diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index b85cbc42e8..dfc0b0eec2 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -685,12 +685,19 @@ process_data() && bin.tangential_pos_num()<= proj_data_ptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) + && ((!record.event().is_swapped() && record.energy().get_energyA_in_keV() >= low_thres_A && record.energy().get_energyA_in_keV() <= high_thres_A && record.energy().get_energyB_in_keV() >= low_thres_B && record.energy().get_energyB_in_keV() <= high_thres_B) - + || (record.event().is_swapped() + && record.energy().get_energyA_in_keV() >= low_thres_B + && record.energy().get_energyA_in_keV() <= high_thres_B + && record.energy().get_energyB_in_keV() >= low_thres_A + && record.energy().get_energyB_in_keV() <= high_thres_A))) { + + std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index c77f042028..6e64279618 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -319,7 +319,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. - /* int low = 0; + int low = 0; if (this->template_exam_info_sptr->get_num_energy_windows()>1) @@ -345,7 +345,7 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), 2.f, this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); -*/ + //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); const CartesianCoordinate3D& scatter_point = @@ -360,8 +360,8 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, detector_coord_B - scatter_point)); // note: costheta is identical for scatter to A or scatter to B // Hence, the Compton_cross_section and energy are identical for both cases as well. - // if(max_single_scatter_cos_angle>costheta) - // return 0; + if(max_single_scatter_cos_angle>costheta) + return 0; const float new_energy = photon_energy_after_Compton_scatter_511keV(costheta); diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index d4b9e70133..c66444d790 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -60,7 +60,7 @@ SingleScatterSimulation:: int low = 0; // TODO: check that the selected windows don't overcome the max num windows - /* + if (this->template_exam_info_sptr->get_num_energy_windows()>1) { @@ -87,7 +87,7 @@ SingleScatterSimulation:: static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), 2.f, this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); -*/ + //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); const CartesianCoordinate3D& scatter_point = @@ -102,8 +102,8 @@ SingleScatterSimulation:: detector_coord_B - scatter_point)); // note: costheta is identical for scatter to A or scatter to B // Hence, the Compton_cross_section and energy are identical for both cases as well. - // if(max_single_scatter_cos_angle>costheta) - // return 0; + if(max_single_scatter_cos_angle>costheta) + return 0; const float new_energy = photon_energy_after_Compton_scatter_511keV(costheta); @@ -143,7 +143,7 @@ detection_efficiency_unscattered.push_back(0); float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; - float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; + float detection_probability_YX=detection_efficiency_unscattered[index0]*detection_efficiency_scattered[index1]; if ((detection_probability_XY==0)&&(detection_probability_YX==0)) return 0; From 5bb434e547c7710c78f53ba4ec0355d5611f3759 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 23 Oct 2019 15:58:43 +0100 Subject: [PATCH 229/274] swap only window --- src/include/stir/listmode/CListRecordROOT.h | 18 +++++++++--------- .../scatter_estimate_for_one_scatter_point.cxx | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index b6c2e7e833..f8101a9a8a 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -236,23 +236,23 @@ class CListRecordROOT : public CListRecord // currently no gating yet this->event_data.init_from_data(ring1, ring2, crystal1, crystal2); - if(this->event().is_swapped()) - { + // if(this->event().is_swapped()) + // { //std::cout << "I m swapped" << std::endl; - this->time_data.init_from_data(time2,time1); + // this->time_data.init_from_data(time2,time1); - this->energy_data.init_energy_from_data(energy2,energy1); - } + // this->energy_data.init_energy_from_data(energy2,energy1); + // } - else - { + // else + // { //std::cout << "I m not swapped" << std::endl; this->time_data.init_from_data(time1,time2); this->energy_data.init_energy_from_data(energy1,energy2); - } - + // } +// // We can make a singature raw based on the two events IDs. // It is pretty unique. raw[0] = event1; diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index c66444d790..0eba7d8112 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -141,7 +141,6 @@ detection_efficiency_unscattered.push_back(0); } - float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; float detection_probability_YX=detection_efficiency_unscattered[index0]*detection_efficiency_scattered[index1]; From d7b9b912e4862a7a7153c86871fb57d77a3cd39c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 23 Oct 2019 18:20:14 +0100 Subject: [PATCH 230/274] changed condition --- src/include/stir/listmode/CListRecordROOT.h | 16 ++++++++-------- src/listmode_buildblock/CListRecordROOT.cxx | 5 +++-- src/listmode_buildblock/LmToProjData.cxx | 6 ------ .../scatter_estimate_for_one_scatter_point.cxx | 2 +- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index f8101a9a8a..13cb3106d4 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -236,22 +236,22 @@ class CListRecordROOT : public CListRecord // currently no gating yet this->event_data.init_from_data(ring1, ring2, crystal1, crystal2); - // if(this->event().is_swapped()) - // { + if(this->event().is_swapped()) + { //std::cout << "I m swapped" << std::endl; - // this->time_data.init_from_data(time2,time1); + this->time_data.init_from_data(time2,time1); - // this->energy_data.init_energy_from_data(energy2,energy1); - // } + this->energy_data.init_energy_from_data(energy2,energy1); + } - // else - // { + else + { //std::cout << "I m not swapped" << std::endl; this->time_data.init_from_data(time1,time2); this->energy_data.init_energy_from_data(energy1,energy2); - // } + } // // We can make a singature raw based on the two events IDs. // It is pretty unique. diff --git a/src/listmode_buildblock/CListRecordROOT.cxx b/src/listmode_buildblock/CListRecordROOT.cxx index d3242f142d..a1f302383f 100644 --- a/src/listmode_buildblock/CListRecordROOT.cxx +++ b/src/listmode_buildblock/CListRecordROOT.cxx @@ -88,8 +88,9 @@ void CListEventROOT::init_from_data(const int& _ring1, const int& _ring2, else if ( det2 >= scanner_sptr->get_num_detectors_per_ring()) det2 = det2 - scanner_sptr->get_num_detectors_per_ring(); - if (((det1 + det2 < 3*scanner_sptr->get_num_detectors_per_ring()/4) && (det1-det2 > 0)) - ||((det1 + det2 > 3*scanner_sptr->get_num_detectors_per_ring()/4)&&(det1-det2 < 0))) + // if (((det1 + det2 < 3*scanner_sptr->get_num_detectors_per_ring()/4) && (det1-det2 > 0)) + // ||((det1 + det2 > 3*scanner_sptr->get_num_detectors_per_ring()/4)&&(det1-det2 < 0))) + if(det1>det2) { int tmp = det1; det1 = det2; diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index dfc0b0eec2..c7922b5962 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -685,16 +685,10 @@ process_data() && bin.tangential_pos_num()<= proj_data_ptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) - && ((!record.event().is_swapped() && record.energy().get_energyA_in_keV() >= low_thres_A && record.energy().get_energyA_in_keV() <= high_thres_A && record.energy().get_energyB_in_keV() >= low_thres_B && record.energy().get_energyB_in_keV() <= high_thres_B) - || (record.event().is_swapped() - && record.energy().get_energyA_in_keV() >= low_thres_B - && record.energy().get_energyA_in_keV() <= high_thres_B - && record.energy().get_energyB_in_keV() >= low_thres_A - && record.energy().get_energyB_in_keV() <= high_thres_A))) { diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 0eba7d8112..6cf9d04e14 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -135,7 +135,7 @@ detection_efficiency_unscattered.push_back(0); int index1 = 0; if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { + {` index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; From f51f631f0394b3314ce3a912ae895c412ba7fcf5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 23 Oct 2019 18:23:15 +0100 Subject: [PATCH 231/274] removed --- .../scatter_estimate_for_one_scatter_point.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 6cf9d04e14..0eba7d8112 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -135,7 +135,7 @@ detection_efficiency_unscattered.push_back(0); int index1 = 0; if (this->template_exam_info_sptr->get_num_energy_windows()>1) - {` + { index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; From 8e77a61e84b447e7ed8cc885d8dfd51ad63ae66d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 23 Oct 2019 19:43:13 +0100 Subject: [PATCH 232/274] swap new --- src/listmode_buildblock/CListRecordROOT.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/listmode_buildblock/CListRecordROOT.cxx b/src/listmode_buildblock/CListRecordROOT.cxx index a1f302383f..ec5521d387 100644 --- a/src/listmode_buildblock/CListRecordROOT.cxx +++ b/src/listmode_buildblock/CListRecordROOT.cxx @@ -90,7 +90,7 @@ void CListEventROOT::init_from_data(const int& _ring1, const int& _ring2, // if (((det1 + det2 < 3*scanner_sptr->get_num_detectors_per_ring()/4) && (det1-det2 > 0)) // ||((det1 + det2 > 3*scanner_sptr->get_num_detectors_per_ring()/4)&&(det1-det2 < 0))) - if(det1>det2) + if(det2>det1) { int tmp = det1; det1 = det2; From e08f649d4828941b78cb7e84d18ee7f4d818929d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 13:13:50 +0100 Subject: [PATCH 233/274] removed swapping energy in root --- src/include/stir/listmode/CListRecordROOT.h | 17 +++-------------- src/listmode_buildblock/CListRecordROOT.cxx | 20 ++++---------------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index 13cb3106d4..06e875dfe5 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -236,22 +236,11 @@ class CListRecordROOT : public CListRecord // currently no gating yet this->event_data.init_from_data(ring1, ring2, crystal1, crystal2); - if(this->event().is_swapped()) - { - //std::cout << "I m swapped" << std::endl; - this->time_data.init_from_data(time2,time1); - this->energy_data.init_energy_from_data(energy2,energy1); - } + //std::cout << "I m not swapped" << std::endl + this->time_data.init_from_data(time1,time2); - - else - { - //std::cout << "I m not swapped" << std::endl; - this->time_data.init_from_data(time1,time2); - - this->energy_data.init_energy_from_data(energy1,energy2); - } + this->energy_data.init_energy_from_data(energy1,energy2); // // We can make a singature raw based on the two events IDs. // It is pretty unique. diff --git a/src/listmode_buildblock/CListRecordROOT.cxx b/src/listmode_buildblock/CListRecordROOT.cxx index ec5521d387..29464d4dd8 100644 --- a/src/listmode_buildblock/CListRecordROOT.cxx +++ b/src/listmode_buildblock/CListRecordROOT.cxx @@ -90,22 +90,10 @@ void CListEventROOT::init_from_data(const int& _ring1, const int& _ring2, // if (((det1 + det2 < 3*scanner_sptr->get_num_detectors_per_ring()/4) && (det1-det2 > 0)) // ||((det1 + det2 > 3*scanner_sptr->get_num_detectors_per_ring()/4)&&(det1-det2 < 0))) - if(det2>det1) - { - int tmp = det1; - det1 = det2; - det2 = tmp; - - ring1 = _ring2; - ring2 = _ring1; - swapped = true; - } - else - { - ring1 = _ring1; - ring2 = _ring2; - swapped = false; - } + ring1 = _ring1; + ring2 = _ring2; + swapped = false; + } END_NAMESPACE_STIR From 16b2f5a8f416617f63f8e0fbe53ee7886da2bc11 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 13:19:50 +0100 Subject: [PATCH 234/274] cleaned lm to projdata --- src/listmode_buildblock/LmToProjData.cxx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index c7922b5962..3f1adfbe20 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -528,14 +528,11 @@ process_data() // few coincidence events (as happens with ECAT scanners) current_time = 0; - float low_thres_A = template_proj_data_ptr->get_exam_info().get_low_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1); - float high_thres_A = template_proj_data_ptr->get_exam_info().get_high_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1); - float low_thres_B = template_proj_data_ptr->get_exam_info().get_low_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1); - float high_thres_B = template_proj_data_ptr->get_exam_info().get_high_energy_thres(template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1); int num_en_windows = template_proj_data_ptr->get_exam_info().get_num_energy_windows(); std::vector high_en_thres(num_en_windows); std::vector low_en_thres(num_en_windows); std::vector energy_window_pair(2); + energy_window_pair[0]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().first; energy_window_pair[1]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().second; @@ -685,10 +682,10 @@ process_data() && bin.tangential_pos_num()<= proj_data_ptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) - && record.energy().get_energyA_in_keV() >= low_thres_A - && record.energy().get_energyA_in_keV() <= high_thres_A - && record.energy().get_energyB_in_keV() >= low_thres_B - && record.energy().get_energyB_in_keV() <= high_thres_B) + && record.energy().get_energyA_in_keV() >= (low_en_thres[energy_window_pair[0]-1]) + && record.energy().get_energyA_in_keV() <= (high_en_thres[energy_window_pair[0]-1]) + && record.energy().get_energyB_in_keV() >= (low_en_thres[energy_window_pair[1]-1]) + && record.energy().get_energyB_in_keV() <= (high_en_thres[energy_window_pair[1]-1])) { From 0b6d019d7820a081cb8257f48eb5b814a57b0c0a Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 14:10:17 +0100 Subject: [PATCH 235/274] first step --- .../ProjDataInfoCylindricalArcCorr.cxx | 6 +++++- .../ProjDataInfoCylindricalNoArcCorr.cxx | 2 +- src/include/stir/Bin.h | 4 +++- src/include/stir/ProjDataInfo.h | 2 +- .../stir/ProjDataInfoCylindricalArcCorr.h | 2 +- .../stir/ProjDataInfoCylindricalNoArcCorr.h | 2 +- .../stir/ProjDataInfoCylindricalNoArcCorr.inl | 10 +++++++++- src/listmode_buildblock/LmToProjData.cxx | 19 ++++++++++--------- 8 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx b/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx index 6a14f7953a..2fa7093eff 100644 --- a/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx @@ -121,9 +121,13 @@ ProjDataInfoCylindricalArcCorr::parameter_info() const Bin ProjDataInfoCylindricalArcCorr:: -get_bin(const LOR& lor) const +get_bin(const LOR& lor, const std::pair &energy_window_pair) const { + if ((energy_window_pair.first!= 0)||(energy_window_pair.second!= 0)) + { + error("TODO NOT IMPLEMENTED YET FOR MULTIPLE ENERGY WINDOWS"); + } Bin bin; LORInAxialAndSinogramCoordinates lor_coords; if (lor.change_representation(lor_coords, get_ring_radius()) == Succeeded::no) diff --git a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx index 86d5cddee4..614f210271 100644 --- a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx @@ -538,7 +538,7 @@ find_bin_given_cartesian_coordinates_of_detection(Bin& bin, Bin ProjDataInfoCylindricalNoArcCorr:: -get_bin(const LOR& lor) const +get_bin(const LOR& lor,const std::pair &energy_window_pair) const { Bin bin; #ifndef STIR_DEVEL diff --git a/src/include/stir/Bin.h b/src/include/stir/Bin.h index b9e445653e..9c5122332a 100644 --- a/src/include/stir/Bin.h +++ b/src/include/stir/Bin.h @@ -67,7 +67,9 @@ class Bin inline int& axial_pos_num(); inline int& segment_num(); inline int& tangential_pos_num(); - inline int& view_num(); + inline int& view_num(); + inline int& first_energy_window_num(); + inline int& second_energy_window_num(); //! get an empty copy inline Bin get_empty_copy() const; diff --git a/src/include/stir/ProjDataInfo.h b/src/include/stir/ProjDataInfo.h index 2bd1712155..c9fe3846ac 100644 --- a/src/include/stir/ProjDataInfo.h +++ b/src/include/stir/ProjDataInfo.h @@ -302,7 +302,7 @@ class ProjDataInfo */ virtual Bin - get_bin(const LOR&) const = 0; + get_bin(const LOR&, const std::pair &energy_window_pair = std::pair(0,0)) const = 0; //! \name Equality of ProjDataInfo objects //@{ diff --git a/src/include/stir/ProjDataInfoCylindricalArcCorr.h b/src/include/stir/ProjDataInfoCylindricalArcCorr.h index 2375f75461..de98662e1b 100644 --- a/src/include/stir/ProjDataInfoCylindricalArcCorr.h +++ b/src/include/stir/ProjDataInfoCylindricalArcCorr.h @@ -78,7 +78,7 @@ class ProjDataInfoCylindricalArcCorr : public ProjDataInfoCylindrical virtual Bin - get_bin(const LOR&) const; + get_bin(const LOR&, const std::pair&) const; virtual std::string parameter_info() const; private: diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h index 1a03be4af2..222675e5c1 100644 --- a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h +++ b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h @@ -257,7 +257,7 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical virtual Bin - get_bin(const LOR&) const; + get_bin(const LOR&, const std::pair&) const; //! \name set of obsolete functions to go between bins<->LORs (will disappear!) diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl index 10442913e0..57f1a2c8d2 100644 --- a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl +++ b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl @@ -135,12 +135,20 @@ Succeeded ProjDataInfoCylindricalNoArcCorr:: get_bin_for_det_pair(Bin& bin, const int det_num1, const int ring_num1, - const int det_num2, const int ring_num2) const + const int det_num2, const int ring_num2) const// const std::pair& energy_window_pair) const { if (get_view_tangential_pos_num_for_det_num_pair(bin.view_num(), bin.tangential_pos_num(), det_num1, det_num2)) + { + //bin.first_energy_window_num()=energy_window_pair.first; + //bin.second_energy_window_num()=energy_window_pair.second; return get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_num1, ring_num2); + } else + { + //bin.first_energy_window_num()=energy_window_pair.seocond; + //bin.second_energy_window_num()=energy_window_pair.first; return get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_num2, ring_num1); + } } Succeeded diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 3f1adfbe20..70be4cc85d 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -531,10 +531,11 @@ process_data() int num_en_windows = template_proj_data_ptr->get_exam_info().get_num_energy_windows(); std::vector high_en_thres(num_en_windows); std::vector low_en_thres(num_en_windows); - std::vector energy_window_pair(2); + std::vector energy_window_pair_vec(2); + // const std::pair energy_window_pair = template_proj_data_ptr->get_exam_info().get_energy_window_pair(); - energy_window_pair[0]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().first; - energy_window_pair[1]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().second; + energy_window_pair_vec[0]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().first; + energy_window_pair_vec[1]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().second; for (int i = 0; i< num_en_windows; ++i) { @@ -583,7 +584,7 @@ process_data() this_frame_exam_info.set_num_energy_windows(num_en_windows); this_frame_exam_info.set_high_energy_thres_vect(high_en_thres); this_frame_exam_info.set_low_energy_thres_vect(low_en_thres); - this_frame_exam_info.set_energy_window_pair(energy_window_pair,num_en_windows); + this_frame_exam_info.set_energy_window_pair(energy_window_pair_vec,num_en_windows); proj_data_ptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); @@ -674,7 +675,7 @@ process_data() // set value in case the event decoder doesn't touch it // otherwise it would be 0 and all events will be ignored bin.set_bin_value(1); - get_bin_from_event(bin, record.event()); + get_bin_from_event(bin, record.event()); // check if it's inside the range we want to store if (bin.get_bin_value()>0 @@ -682,10 +683,10 @@ process_data() && bin.tangential_pos_num()<= proj_data_ptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) - && record.energy().get_energyA_in_keV() >= (low_en_thres[energy_window_pair[0]-1]) - && record.energy().get_energyA_in_keV() <= (high_en_thres[energy_window_pair[0]-1]) - && record.energy().get_energyB_in_keV() >= (low_en_thres[energy_window_pair[1]-1]) - && record.energy().get_energyB_in_keV() <= (high_en_thres[energy_window_pair[1]-1])) + && record.energy().get_energyA_in_keV() >= (low_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1]) + && record.energy().get_energyA_in_keV() <= (high_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1]) + && record.energy().get_energyB_in_keV() >= (low_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1]) + && record.energy().get_energyB_in_keV() <= (high_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1])) { From 43c3409f28420a58d90f759c1633121b271153d9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 15:37:10 +0100 Subject: [PATCH 236/274] added bin --- .../ProjDataInfoCylindricalArcCorr.cxx | 2 +- .../ProjDataInfoCylindricalNoArcCorr.cxx | 2 +- src/include/stir/Bin.h | 24 +++++++++++-- src/include/stir/Bin.inl | 35 +++++++++++++++++++ src/include/stir/ProjDataInfo.h | 2 +- .../stir/ProjDataInfoCylindricalNoArcCorr.h | 2 +- .../stir/ProjDataInfoCylindricalNoArcCorr.inl | 10 +++--- src/listmode_buildblock/CListEvent.cxx | 3 +- src/listmode_buildblock/LmToProjData.cxx | 18 +++++----- .../LmToProjDataBootstrap.cxx | 2 +- 10 files changed, 78 insertions(+), 22 deletions(-) diff --git a/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx b/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx index 2fa7093eff..0d92bea2d6 100644 --- a/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalArcCorr.cxx @@ -124,7 +124,7 @@ ProjDataInfoCylindricalArcCorr:: get_bin(const LOR& lor, const std::pair &energy_window_pair) const { - if ((energy_window_pair.first!= 0)||(energy_window_pair.second!= 0)) + if ((energy_window_pair.first!= 1)||(energy_window_pair.second!= 1)) { error("TODO NOT IMPLEMENTED YET FOR MULTIPLE ENERGY WINDOWS"); } diff --git a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx index 614f210271..9a5c40b82e 100644 --- a/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx +++ b/src/buildblock/ProjDataInfoCylindricalNoArcCorr.cxx @@ -566,7 +566,7 @@ get_bin(const LOR& lor,const std::pair &energy_window_pair) cons if (ring1 >=0 && ring1=0 && ring2= get_min_tangential_pos_num() && bin.tangential_pos_num() <= get_max_tangential_pos_num()) { diff --git a/src/include/stir/Bin.h b/src/include/stir/Bin.h index 9c5122332a..6e554fbce1 100644 --- a/src/include/stir/Bin.h +++ b/src/include/stir/Bin.h @@ -52,8 +52,11 @@ class Bin inline Bin(); //! A constructor : constructs a bin with value (defaulting to 0) - inline Bin(int segment_num,int view_num, int axial_pos_num, + inline Bin(int segment_num,int view_num, int axial_pos_num, int tangential_pos_num,float bin_value=0); + + inline Bin(int segment_num,int view_num, int axial_pos_num, + int tangential_pos_num, int first_energy_window, int second_energy_window, float bin_value = 0); //!get axial position number inline int axial_pos_num()const; @@ -63,7 +66,12 @@ class Bin inline int tangential_pos_num() const; //! get view number inline int view_num() const; - + //! get first_energy_window_number + inline int first_energy_window_num() const; + //! get second_energy_window_number + inline int second_energy_window_num() const; + + inline int& axial_pos_num(); inline int& segment_num(); inline int& tangential_pos_num(); @@ -78,6 +86,16 @@ class Bin inline float get_bin_value()const; //! set the value to be back projected inline void set_bin_value( float v ); + + //! get the first energy window number + inline float get_first_energy_window_num()const; + //! set the first energy window number + inline void set_first_energy_window_num( int v ); + //! get the second energy window number + inline float get_second_energy_window_num()const; + //! set the second energy window number + inline void set_second_energy_window_num( int v ); + //! accumulate voxel's contribution during forward projection inline Bin& operator+=(const float dx); @@ -100,6 +118,8 @@ private : int axial_pos; int tangential_pos; float bin_value; + int first_energy_window; + int second_energy_window; }; diff --git a/src/include/stir/Bin.inl b/src/include/stir/Bin.inl index 7fe9d8ac3b..8b9971be51 100644 --- a/src/include/stir/Bin.inl +++ b/src/include/stir/Bin.inl @@ -58,6 +58,14 @@ int Bin::view_num() const { return view;} +int + Bin::first_energy_window_num() const +{ return first_energy_window;} + +int + Bin::second_energy_window_num() const +{ return second_energy_window;} + int& Bin::axial_pos_num() { return axial_pos;} @@ -74,6 +82,15 @@ int& Bin:: view_num() { return view;} +int& + Bin::first_energy_window_num() +{ return first_energy_window;} + +int& + Bin::second_energy_window_num() +{ return second_energy_window;} + + #if 0 const ProjDataInfo * Bin::get_proj_data_info_ptr() const @@ -99,6 +116,24 @@ void Bin::set_bin_value( float v ) { bin_value = v ;} + +float +Bin::get_first_energy_window_num()const +{ return first_energy_window;} + +void +Bin::set_first_energy_window_num( int v ) +{ first_energy_window = v ;} + +float +Bin::get_second_energy_window_num()const +{ return second_energy_window;} + +void +Bin::set_second_energy_window_num( int v ) +{ second_energy_window = v ;} + + Bin& Bin::operator+=(const float dx) { bin_value+=dx; diff --git a/src/include/stir/ProjDataInfo.h b/src/include/stir/ProjDataInfo.h index c9fe3846ac..655e1a2e0b 100644 --- a/src/include/stir/ProjDataInfo.h +++ b/src/include/stir/ProjDataInfo.h @@ -302,7 +302,7 @@ class ProjDataInfo */ virtual Bin - get_bin(const LOR&, const std::pair &energy_window_pair = std::pair(0,0)) const = 0; + get_bin(const LOR&, const std::pair &energy_window_pair = std::pair(1,1)) const = 0; //! \name Equality of ProjDataInfo objects //@{ diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h index 222675e5c1..371a026df6 100644 --- a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h +++ b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.h @@ -237,7 +237,7 @@ class ProjDataInfoCylindricalNoArcCorr : public ProjDataInfoCylindrical inline Succeeded get_bin_for_det_pair(Bin&, const int det1_num, const int ring1_num, - const int det2_num, const int ring2_num) const; + const int det2_num, const int ring2_num, const std::pair &energy_window_pair = std::pair(1,1)) const; //! This routine gets the detector pair corresponding to a bin. diff --git a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl index 57f1a2c8d2..37abcab92c 100644 --- a/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl +++ b/src/include/stir/ProjDataInfoCylindricalNoArcCorr.inl @@ -135,18 +135,18 @@ Succeeded ProjDataInfoCylindricalNoArcCorr:: get_bin_for_det_pair(Bin& bin, const int det_num1, const int ring_num1, - const int det_num2, const int ring_num2) const// const std::pair& energy_window_pair) const + const int det_num2, const int ring_num2, const std::pair& energy_window_pair) const { if (get_view_tangential_pos_num_for_det_num_pair(bin.view_num(), bin.tangential_pos_num(), det_num1, det_num2)) { - //bin.first_energy_window_num()=energy_window_pair.first; - //bin.second_energy_window_num()=energy_window_pair.second; + bin.first_energy_window_num() = energy_window_pair.first;//energy_window_pair.first; + bin.second_energy_window_num()=energy_window_pair.second; return get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_num1, ring_num2); } else { - //bin.first_energy_window_num()=energy_window_pair.seocond; - //bin.second_energy_window_num()=energy_window_pair.first; + bin.first_energy_window_num()=energy_window_pair.second; + bin.second_energy_window_num()=energy_window_pair.first; return get_segment_axial_pos_num_for_ring_pair(bin.segment_num(), bin.axial_pos_num(), ring_num2, ring_num1); } } diff --git a/src/listmode_buildblock/CListEvent.cxx b/src/listmode_buildblock/CListEvent.cxx index ad801a2685..c11b31399d 100644 --- a/src/listmode_buildblock/CListEvent.cxx +++ b/src/listmode_buildblock/CListEvent.cxx @@ -45,7 +45,8 @@ void CListEvent:: get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const { - bin = proj_data_info.get_bin(get_LOR()); + const std::pair energy_window_pair(1,2); //TODO REMOVE + bin = proj_data_info.get_bin(get_LOR(),energy_window_pair); } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 70be4cc85d..131ee82d98 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -427,8 +427,8 @@ get_bin_from_event(Bin& bin, const CListEvent& event) const const float bin_value = 1/bin_efficiency; // TODO wasteful: we decode the event twice. replace by something like // template_proj_data_info_ptr->get_bin_from_uncompressed(bin, uncompressed_bin); - event.get_bin(bin, *template_proj_data_info_ptr); - + event.get_bin(bin, *template_proj_data_info_ptr);//, energy_window_pair); + if (bin.get_bin_value()>0) { bin.set_bin_value(bin_value); @@ -437,7 +437,7 @@ get_bin_from_event(Bin& bin, const CListEvent& event) const } else { - event.get_bin(bin, *template_proj_data_info_ptr); + event.get_bin(bin, *template_proj_data_info_ptr);//, energy_window_pair); } } @@ -675,18 +675,18 @@ process_data() // set value in case the event decoder doesn't touch it // otherwise it would be 0 and all events will be ignored bin.set_bin_value(1); - get_bin_from_event(bin, record.event()); - + get_bin_from_event(bin, record.event());// template_proj_data_ptr->get_exam_info().get_energy_window_pair()); + // check if it's inside the range we want to store if (bin.get_bin_value()>0 && bin.tangential_pos_num()>= proj_data_ptr->get_min_tangential_pos_num() && bin.tangential_pos_num()<= proj_data_ptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_ptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_ptr->get_max_axial_pos_num(bin.segment_num()) - && record.energy().get_energyA_in_keV() >= (low_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1]) - && record.energy().get_energyA_in_keV() <= (high_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().first-1]) - && record.energy().get_energyB_in_keV() >= (low_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1]) - && record.energy().get_energyB_in_keV() <= (high_en_thres[template_proj_data_ptr->get_exam_info().get_energy_window_pair().second-1])) + && record.energy().get_energyA_in_keV() >= (low_en_thres[bin.first_energy_window_num()-1]) + && record.energy().get_energyA_in_keV() <= (high_en_thres[bin.first_energy_window_num()-1]) + && record.energy().get_energyB_in_keV() >= (low_en_thres[bin.second_energy_window_num()-1]) + && record.energy().get_energyB_in_keV() <= (high_en_thres[bin.second_energy_window_num()-1])) { diff --git a/src/listmode_buildblock/LmToProjDataBootstrap.cxx b/src/listmode_buildblock/LmToProjDataBootstrap.cxx index d67de6db04..6b2752c7e3 100644 --- a/src/listmode_buildblock/LmToProjDataBootstrap.cxx +++ b/src/listmode_buildblock/LmToProjDataBootstrap.cxx @@ -166,7 +166,7 @@ start_new_time_frame(const unsigned int new_frame_num) // set value in case the event decoder doesn't touch it // otherwise it would be 0 and all events will be ignored bin.set_bin_value(1); - base_type::get_bin_from_event(bin, record.event()); + base_type::get_bin_from_event(bin, record.event()); // check if it's inside the range we want to store if (bin.get_bin_value()>0 && bin.tangential_pos_num()>= this->template_proj_data_info_ptr->get_min_tangential_pos_num() From 5df73be55ce26ec059ad593363492a79d8f79c63 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 15:46:19 +0100 Subject: [PATCH 237/274] added energy to bin --- src/include/stir/listmode/CListRecord.h | 2 +- src/include/stir/listmode/LmToProjData.h | 2 +- src/listmode_buildblock/CListEvent.cxx | 4 ++-- src/listmode_buildblock/LmToProjData.cxx | 12 +++++++----- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/include/stir/listmode/CListRecord.h b/src/include/stir/listmode/CListRecord.h index da596fc48d..db40e951c1 100644 --- a/src/include/stir/listmode/CListRecord.h +++ b/src/include/stir/listmode/CListRecord.h @@ -108,7 +108,7 @@ class CListEvent */ virtual void - get_bin(Bin& bin, const ProjDataInfo&) const; + get_bin(Bin& bin, const ProjDataInfo&, const std::pair &energy_window_pair = std::pair(1,1)) const; //! This method checks if the template is valid for LmToProjData /*! Used before the actual processing of the data (see issue #61), before calling get_bin() diff --git a/src/include/stir/listmode/LmToProjData.h b/src/include/stir/listmode/LmToProjData.h index 9665c32133..628ccd038e 100644 --- a/src/include/stir/listmode/LmToProjData.h +++ b/src/include/stir/listmode/LmToProjData.h @@ -192,7 +192,7 @@ class LmToProjData : public ParsingObject (on top of anything done by normalisation_ptr). \todo Would need timing info or so for e.g. time dependent normalisation or angle info for a rotating scanner.*/ - virtual void get_bin_from_event(Bin& bin, const CListEvent&) const; + virtual void get_bin_from_event(Bin& bin, const CListEvent&, const std::pair &energy_window_pair = std::pair(1,1)) const; //! A function that should return the number of uncompressed bins in the current bin /*! \todo it is not compatiable with e.g. HiDAC doesn't belong here anyway diff --git a/src/listmode_buildblock/CListEvent.cxx b/src/listmode_buildblock/CListEvent.cxx index c11b31399d..b000dc4242 100644 --- a/src/listmode_buildblock/CListEvent.cxx +++ b/src/listmode_buildblock/CListEvent.cxx @@ -43,9 +43,9 @@ set_prompt(const bool) void CListEvent:: -get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const +get_bin(Bin& bin, const ProjDataInfo& proj_data_info, const std::pair &energy_window_pair) const { - const std::pair energy_window_pair(1,2); //TODO REMOVE + //const std::pair energy_window_pair(1,2); //TODO REMOVE bin = proj_data_info.get_bin(get_LOR(),energy_window_pair); } diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 131ee82d98..a3abcc0bb2 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -388,12 +388,12 @@ LmToProjData(const char * const par_filename) ***************************************************************/ void LmToProjData:: -get_bin_from_event(Bin& bin, const CListEvent& event) const +get_bin_from_event(Bin& bin, const CListEvent& event, const std::pair &energy_window_pair) const { if (do_pre_normalisation) { Bin uncompressed_bin; - event.get_bin(uncompressed_bin, *proj_data_info_cyl_uncompressed_ptr); + event.get_bin(uncompressed_bin, *proj_data_info_cyl_uncompressed_ptr, energy_window_pair); if (uncompressed_bin.get_bin_value()<=0) return; // rejected for some strange reason @@ -427,7 +427,7 @@ get_bin_from_event(Bin& bin, const CListEvent& event) const const float bin_value = 1/bin_efficiency; // TODO wasteful: we decode the event twice. replace by something like // template_proj_data_info_ptr->get_bin_from_uncompressed(bin, uncompressed_bin); - event.get_bin(bin, *template_proj_data_info_ptr);//, energy_window_pair); + event.get_bin(bin, *template_proj_data_info_ptr,energy_window_pair);//, energy_window_pair); if (bin.get_bin_value()>0) { @@ -437,7 +437,7 @@ get_bin_from_event(Bin& bin, const CListEvent& event) const } else { - event.get_bin(bin, *template_proj_data_info_ptr);//, energy_window_pair); + event.get_bin(bin, *template_proj_data_info_ptr,energy_window_pair);//, energy_window_pair); } } @@ -675,7 +675,7 @@ process_data() // set value in case the event decoder doesn't touch it // otherwise it would be 0 and all events will be ignored bin.set_bin_value(1); - get_bin_from_event(bin, record.event());// template_proj_data_ptr->get_exam_info().get_energy_window_pair()); + get_bin_from_event(bin, record.event(), template_proj_data_ptr->get_exam_info().get_energy_window_pair()); // check if it's inside the range we want to store if (bin.get_bin_value()>0 @@ -690,6 +690,8 @@ process_data() { + // std::cout<< "energy first: " << bin.first_energy_window_num() << '\n'; + // std::cout<< "energy second: " << bin.second_energy_window_num() << '\n'; std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); From 31fe2793d2aa65c835be1481915472e7f7e61eeb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 15:48:20 +0100 Subject: [PATCH 238/274] test to see diff --- src/listmode_buildblock/LmToProjData.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index a3abcc0bb2..558529b999 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -692,8 +692,8 @@ process_data() // std::cout<< "energy first: " << bin.first_energy_window_num() << '\n'; // std::cout<< "energy second: " << bin.second_energy_window_num() << '\n'; - std::cout<< "energy A: " << record.energy().get_energyA_in_keV() << '\n'; - std::cout<< "energy B: " << record.energy().get_energyB_in_keV() << '\n'; + std::cout<< "energy A new: " << record.energy().get_energyA_in_keV() << '\n'; + std::cout<< "energy B new: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_ptr->get_min_view_num()); assert(bin.view_num()<=proj_data_ptr->get_max_view_num()); From b04b0ebe60bfbefaec2b1b94d90664ea2b23c14b Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 18:38:20 +0100 Subject: [PATCH 239/274] fixed bug for swig --- src/include/stir/Bin.h | 6 +++--- src/include/stir/Bin.inl | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/include/stir/Bin.h b/src/include/stir/Bin.h index 6e554fbce1..e8fd49339c 100644 --- a/src/include/stir/Bin.h +++ b/src/include/stir/Bin.h @@ -52,11 +52,11 @@ class Bin inline Bin(); //! A constructor : constructs a bin with value (defaulting to 0) - inline Bin(int segment_num,int view_num, int axial_pos_num, - int tangential_pos_num,float bin_value=0); + //inline Bin(int segment_num,int view_num, int axial_pos_num, + // int tangential_pos_num,float bin_value=0); inline Bin(int segment_num,int view_num, int axial_pos_num, - int tangential_pos_num, int first_energy_window, int second_energy_window, float bin_value = 0); + int tangential_pos_num, float bin_value = 0, int first_energy_window = 1, int second_energy_window = 1); //!get axial position number inline int axial_pos_num()const; diff --git a/src/include/stir/Bin.inl b/src/include/stir/Bin.inl index 8b9971be51..aa9ae7749a 100644 --- a/src/include/stir/Bin.inl +++ b/src/include/stir/Bin.inl @@ -36,9 +36,11 @@ Bin::Bin() {} -Bin::Bin(int segment_num,int view_num, int axial_pos_num,int tangential_pos_num,float bin_value) +Bin::Bin(int segment_num,int view_num, int axial_pos_num,int tangential_pos_num,float bin_value, int first_energy_window, + int second_energy_window) :segment(segment_num),view(view_num), - axial_pos(axial_pos_num),tangential_pos(tangential_pos_num),bin_value(bin_value) + axial_pos(axial_pos_num),tangential_pos(tangential_pos_num),bin_value(bin_value),first_energy_window(first_energy_window), + second_energy_window(second_energy_window) {} From d7f41c1a801876de1f0c2905f0440216a48475cd Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 24 Oct 2019 18:58:14 +0100 Subject: [PATCH 240/274] fixed bug constructor bin --- src/include/stir/Bin.h | 5 ++++- src/include/stir/Bin.inl | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/include/stir/Bin.h b/src/include/stir/Bin.h index e8fd49339c..780f50bcca 100644 --- a/src/include/stir/Bin.h +++ b/src/include/stir/Bin.h @@ -56,7 +56,10 @@ class Bin // int tangential_pos_num,float bin_value=0); inline Bin(int segment_num,int view_num, int axial_pos_num, - int tangential_pos_num, float bin_value = 0, int first_energy_window = 1, int second_energy_window = 1); + int tangential_pos_num, float bin_value = 0); + + inline Bin(int segment_num,int view_num, int axial_pos_num, + int tangential_pos_num, float bin_value, int first_energy_window, int second_energy_window); //!get axial position number inline int axial_pos_num()const; diff --git a/src/include/stir/Bin.inl b/src/include/stir/Bin.inl index aa9ae7749a..47aeb4a08a 100644 --- a/src/include/stir/Bin.inl +++ b/src/include/stir/Bin.inl @@ -36,9 +36,14 @@ Bin::Bin() {} +Bin::Bin(int segment_num,int view_num, int axial_pos_num,int tangential_pos_num,float bin_value) + :segment(segment_num),view(view_num), + axial_pos(axial_pos_num),tangential_pos(tangential_pos_num),bin_value(bin_value) + {} + Bin::Bin(int segment_num,int view_num, int axial_pos_num,int tangential_pos_num,float bin_value, int first_energy_window, int second_energy_window) - :segment(segment_num),view(view_num), + :segment(segment_num),view(view_num), axial_pos(axial_pos_num),tangential_pos(tangential_pos_num),bin_value(bin_value),first_energy_window(first_energy_window), second_energy_window(second_energy_window) {} From 057ce33da10ea84d3f9d163e3879949adbc4fc50 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 25 Oct 2019 15:34:02 +0100 Subject: [PATCH 241/274] gaussian_model_and_unlisting --- src/include/stir/scatter/ScatterSimulation.h | 2 +- .../SingleScatterLikelihoodAndGradient.cxx | 4 +++- src/scatter_buildblock/scatter_detection_modelling.cxx | 4 ++-- .../scatter_estimate_for_one_scatter_point.cxx | 6 ++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index fa0ce2d072..718429e1da 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -211,7 +211,7 @@ class ScatterSimulation : public RegisteredObject, total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_gauss(const float energy, const int en_window = 0) const; + float detection_efficiency_num(const float energy, const int en_window = 0) const; float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 6e64279618..f9b218f763 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -484,7 +484,9 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, // the energy dependency is left out - const double common_factor = scatter_volume/total_Compton_cross_section_511keV; + const double common_factor = + 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * + scatter_volume/total_Compton_cross_section_511keV; // Single ScatterForward Model diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 5bdc68b052..e3f4aa702d 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -101,7 +101,7 @@ compute_emis_to_det_points_solid_angle_factor( float ScatterSimulation:: -detection_efficiency_gauss(const float energy, const int en_window) const +detection_efficiency(const float energy, const int en_window) const { // factor 2.35482 is used to convert FWHM to sigma const float sigma_times_sqrt2= @@ -168,7 +168,7 @@ ScatterSimulation::detection_efficiency_integral(const float incoming_photon_ene } float -ScatterSimulation::detection_efficiency(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_num(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); diff --git a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx index 0eba7d8112..28ea7587e0 100644 --- a/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx +++ b/src/scatter_buildblock/scatter_estimate_for_one_scatter_point.cxx @@ -142,7 +142,7 @@ detection_efficiency_unscattered.push_back(0); } float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; - float detection_probability_YX=detection_efficiency_unscattered[index0]*detection_efficiency_scattered[index1]; + float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; if ((detection_probability_XY==0)&&(detection_probability_YX==0)) return 0; @@ -211,7 +211,9 @@ detection_efficiency_unscattered.push_back(0); // (computed with the same detection model as used in the scatter code) // the energy dependency is left out - const double common_factor = scatter_volume/total_Compton_cross_section_511keV; + const double common_factor = + 1/detection_efficiency_no_scatter(det_num_A, det_num_B) * + scatter_volume/total_Compton_cross_section_511keV; float scatter_ratio=0 ; From 8ad5a44d4ad2715630afb1c0ace46b5f704c6871 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 25 Oct 2019 15:34:34 +0100 Subject: [PATCH 242/274] my fist commit --- src/include/stir/Bin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/stir/Bin.h b/src/include/stir/Bin.h index 780f50bcca..1f2698869e 100644 --- a/src/include/stir/Bin.h +++ b/src/include/stir/Bin.h @@ -54,7 +54,7 @@ class Bin //! A constructor : constructs a bin with value (defaulting to 0) //inline Bin(int segment_num,int view_num, int axial_pos_num, // int tangential_pos_num,float bin_value=0); - +// inline Bin(int segment_num,int view_num, int axial_pos_num, int tangential_pos_num, float bin_value = 0); From cad30ceba8b4adb7c01cb21fb7741ed7f3ea062f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 11 Nov 2019 12:04:16 +0000 Subject: [PATCH 243/274] zero grad --- .../SingleScatterLikelihoodAndGradient.cxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index f9b218f763..7f44e41425 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -899,8 +899,12 @@ get_ratio(const ProjData& projdata,const ProjData& norm,const ProjData &add_proj ++bin.view_num()) { for (bin.tangential_pos_num()= sino.get_min_tangential_pos_num(); bin.tangential_pos_num()<= sino.get_max_tangential_pos_num(); ++bin.tangential_pos_num()) - ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; - ratio_HR.set_sinogram(ratio_sino); + if(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]==0) + ratio_sino[bin.view_num()][bin.tangential_pos_num()] = 0; + else + ratio_sino[bin.view_num()][bin.tangential_pos_num()] = sino[bin.axial_pos_num()][bin.tangential_pos_num()]/(est_sino[bin.axial_pos_num()][bin.tangential_pos_num()]+add_sino[bin.axial_pos_num()][bin.tangential_pos_num()])-1; + ratio_HR.set_sinogram(ratio_sino); + } } From 0f95dfa3b06b86e8d007d7f3254e10926ad5d2dc Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 22 Apr 2020 22:00:54 +0200 Subject: [PATCH 244/274] typo --- src/IO/InterfileHeader.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index 3d10d1365c..fb9a2afcd3 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -151,6 +151,7 @@ InterfileHeader::InterfileHeader() lower_en_window_thres.resize(num_energy_windows); upper_en_window_thres.resize(num_energy_windows); lower_en_window_thres[0]=-1.F; + // upper_en_window_thres[0]=-1.F; num_time_frames = 1; image_scaling_factors.resize(num_time_frames); From 57d25ba5102feb65ffd34337c5b2a86f53947a6d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 22 Apr 2020 22:14:41 +0200 Subject: [PATCH 245/274] old commit --- src/swig/stir.i | 120 ++++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/swig/stir.i b/src/swig/stir.i index 9802a24f70..688aa78fda 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -16,12 +16,12 @@ See STIR/LICENSE.txt for details */ /*! - \file + \file \brief Interface file for SWIG - \author Kris Thielemans + \author Kris Thielemans */ - +// %module stir %{ @@ -72,7 +72,7 @@ #include "stir/zoom.h" #include "stir/GeneralisedPoissonNoiseGenerator.h" - + #include "stir/IO/read_from_file.h" #include "stir/IO/write_to_file.h" #include "stir/IO/InterfileOutputFileFormat.h" @@ -87,7 +87,7 @@ #include "stir/ChainedDataProcessor.h" #include "stir/SeparableCartesianMetzImageFilter.h" -#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" +#include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h" #include "stir/OSMAPOSL/OSMAPOSLReconstruction.h" #include "stir/OSSPS/OSSPSReconstruction.h" #include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" @@ -116,7 +116,7 @@ SWIG_AsVal_double (PyObject * obj, double *val); #endif - // local helper functions for conversions etc. These are not "exposed" to the target language + // local helper functions for conversions etc. These are not "exposed" to the target language // (but only enter in the wrapper) namespace swigstir { #if defined(SWIGPYTHON) @@ -173,15 +173,15 @@ { PyObject *iterator = PyObject_GetIter(arg); - + PyObject *item; typename stir::Array::full_iterator array_iter = array_ptr->begin_all(); - while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) + while ((item = PyIter_Next(iterator)) && array_iter != array_ptr->end_all()) { double val; // TODO currently hard-wired as double which might imply extra conversions int ecode = SWIG_AsVal_double(item, &val); - if (SWIG_IsOK(ecode)) + if (SWIG_IsOK(ecode)) { *array_iter++ = static_cast(val); } @@ -203,7 +203,7 @@ } Py_DECREF(iterator); - if (PyErr_Occurred()) + if (PyErr_Occurred()) { throw std::runtime_error("Error during fill()"); } @@ -212,7 +212,7 @@ } #if 0 - + // TODO does not work yet. // it doesn't compile as includes are in init section, which follows after this in the wrapper // Even if it did compile, it might not work anyway as I haven't tested it. @@ -321,7 +321,7 @@ float const* data_ptr = (float *)mxGetData(pm); a.fill(static_cast(*data_ptr)); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for filling a stir array"); } } @@ -344,8 +344,8 @@ } if (matlab_num_dims > static_cast(num_dimensions)) { - throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % - num_dimensions)); + throw std::runtime_error(boost::str(boost::format("number of dimensions in matlab array is incorrect for constructing a stir array of dimension %d") % + num_dimensions)); } if (do_resize) { @@ -356,7 +356,7 @@ a.resize(sizes); } else - { + { // check sizes BasicCoordinate minind,maxind; a.get_regular_range(minind,maxind); @@ -372,7 +372,7 @@ throw std::runtime_error("sizes of first dimensions of the stir array have to be 1 if initialising from a lower dimensional matlab array"); } } - } + } if (mxIsDouble(pm)) { double * data_ptr = mxGetPr(pm); @@ -382,10 +382,10 @@ float * data_ptr = (float *)mxGetData(pm); std::copy(data_ptr, data_ptr+a.size_all(), a.begin_all()); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); } - } + } //////////// same for Coordinate @@ -414,7 +414,7 @@ float const* data_ptr = (float *)mxGetData(pm); a.fill(static_cast(*data_ptr)); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for filling a stir coordinate"); } } @@ -437,8 +437,8 @@ } if (matlab_num_dims != static_cast(1)) { - throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % - matlab_num_dims % num_dimensions)); + throw std::runtime_error(boost::str(boost::format("number of dimensions %d of matlab array is incorrect for constructing a stir coordinate of dimension %d (expecting a column vector)") % + matlab_num_dims % num_dimensions)); } if (m_sizes[0]!=static_cast(num_dimensions)) { @@ -453,10 +453,10 @@ float * data_ptr = (float *)mxGetData(pm); std::copy(data_ptr, data_ptr+a.size(), a.begin()); } else - { + { throw std::runtime_error("currently only supporting double or single arrays for constructing a stir array"); } - } + } #endif } // end namespace swigstir %} @@ -501,7 +501,7 @@ } catch (const std::string& e) { SWIG_exception(SWIG_RuntimeError, e.c_str()); } -} +} // declare some functions that return a new pointer such that SWIG can release memory properly %newobject *::clone; @@ -513,7 +513,7 @@ %ignore *::read_from_stream; #if defined(SWIGPYTHON) -%rename(__assign__) *::operator=; +%rename(__assign__) *::operator=; #endif // include standard swig support for some bits of the STL (i.e. standard C++ lib) @@ -565,7 +565,7 @@ namespace std { %template(StringList) list; } -// section for helper classes for creating new iterators. +// section for helper classes for creating new iterators. // The code here is nearly a copy of what's in PyIterators.swg, // except that the decr() function isn't defined. This is because we need it for some STIR iterators // which are forward_iterators. @@ -576,7 +576,7 @@ namespace std { %{ namespace swigstir { #ifdef SWIGPYTHON - template::value_type, typename FromOper = swig::from_oper > class SwigPyForwardIteratorClosed_T : public swig::SwigPyIterator_T @@ -585,14 +585,14 @@ namespace std { FromOper from; typedef OutIterator out_iterator; typedef ValueType value_type; - typedef swig::SwigPyIterator_T base; + typedef swig::SwigPyIterator_T base; typedef SwigPyForwardIteratorClosed_T self_type; - + SwigPyForwardIteratorClosed_T(out_iterator curr, out_iterator first, out_iterator last, PyObject *seq) : swig::SwigPyIterator_T(curr, seq), begin(first), end(last) { } - + PyObject *value() const { if (base::current == end) { throw swig::stop_iteration(); @@ -600,7 +600,7 @@ namespace std { return swig::from(static_cast(*(base::current))); } } - + swig::SwigPyIterator *copy() const { return new self_type(*this); @@ -704,14 +704,14 @@ namespace std { // } proj_data.fill_from(array_iter); } - - + + } // end of namespace %} // end of initial code specification for inclusino in the SWIG wrapper // doesn't work (yet?) because of bug in int template arguments -// %rename(__getitem__) *::at; +// %rename(__getitem__) *::at; // MACROS to define index access (Work-in-progress) %define %ADD_indexaccess(INDEXTYPE,RETTYPE,TYPE...) @@ -884,7 +884,7 @@ T * operator-> () const; // use simpler version for SWIG to make the hierarchy a bit easier namespace stir { template - class RegisteredObject + class RegisteredObject { public: //! List all possible registered names to the stream @@ -1005,14 +1005,14 @@ T * operator-> () const; static stir::VoxelsOnCartesianGrid * read_from_file(const std::string& filename) { using namespace stir; - unique_ptr > + unique_ptr > ret(read_from_file >(filename)); return dynamic_cast *>(ret.release()); } } //%ADD_indexaccess(int,stir::BasicCoordinate::value_type,stir::BasicCoordinate); -namespace stir { +namespace stir { #ifdef SWIGPYTHON // add extra features to the coordinates to make them a bit more Python friendly %extend BasicCoordinate { @@ -1029,7 +1029,7 @@ namespace stir { // print as (1,2,3) as opposed to non-informative default provided by SWIG std::string __str__() - { + { std::ostringstream s; s<<'('; for (int d=1; d<=num_dimensions-1; ++d) @@ -1040,7 +1040,7 @@ namespace stir { // print as classname((1,2,3)) as opposed to non-informative default provided by SWIG std::string __repr__() - { + { #if SWIG_VERSION < 0x020009 // don't know how to get the Python typename std::string repr = "stir.Coordinate"; @@ -1071,8 +1071,8 @@ namespace stir { return $self->size(); } #if defined(SWIGPYTHON_BUILTIN) - %feature("python:slot", "tp_str", functype="reprfunc") __str__; - %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; + %feature("python:slot", "tp_str", functype="reprfunc") __str__; + %feature("python:slot", "tp_repr", functype="reprfunc") __repr__; %feature("python:slot", "nb_nonzero", functype="inquiry") __nonzero__; %feature("python:slot", "sq_length", functype="lenfunc") __len__; #endif // SWIGPYTHON_BUILTIN @@ -1082,14 +1082,14 @@ namespace stir { %extend BasicCoordinate { // print as [1;2;3] as opposed to non-informative default provided by SWIG void disp() - { + { std::ostringstream s; s<<'['; for (int d=1; d<=num_dimensions-1; ++d) s << (*$self)[d] << "; "; s << (*$self)[num_dimensions] << "]\n"; mexPrintf(s.str().c_str()); - + } //%feature("autodoc", "construct from vector, e.g. [2;3;4] for a 3d coordinate") BasicCoordinate(const mxArray *pm) @@ -1115,7 +1115,7 @@ namespace stir { %template(Float3Coordinate) Coordinate3D< float >; %template(FloatCartesianCoordinate3D) CartesianCoordinate3D; %template(IntCartesianCoordinate3D) CartesianCoordinate3D; - + %template(Int2BasicCoordinate) BasicCoordinate<2,int>; %template(Size2BasicCoordinate) BasicCoordinate<2,std::size_t>; %template(Float2BasicCoordinate) BasicCoordinate<2,float>; @@ -1195,7 +1195,7 @@ namespace stir { snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", arg->ob_type->tp_name); throw std::invalid_argument(str); - } + } } } #endif @@ -1241,7 +1241,7 @@ namespace stir { { swigstir::fill_Array_from_matlab(*$self, pm, false /*do not resize */); } } #endif - // TODO next line doesn't give anything useful as SWIG doesn't recognise that + // TODO next line doesn't give anything useful as SWIG doesn't recognise that // the return value is an array. So, we get a wrapped object that we cannot handle //%ADD_indexaccess(int,Array::value_type, Array); @@ -1294,7 +1294,7 @@ namespace stir { %rename (get_back_projector) *::get_back_projector_sptr; %rename (get_kappa) *::get_kappa_sptr; %rename (get_attenuation_image) *::get_attenuation_image_sptr; -/* would be nice, but needs swig to be compiled with PCRE support +/* would be nice, but needs swig to be compiled with PCRE support %rename("rstrip:[_ptr]") %rename("rstrip:[_sptr]") */ @@ -1371,9 +1371,9 @@ namespace stir { %include "stir/ProjDataInfo.h" %newobject *::construct_proj_data_info; -%extend stir::ProjDataInfo +%extend stir::ProjDataInfo { - // work around the current SWIG limitation that it doesn't wrap unique_ptr. + // work around the current SWIG limitation that it doesn't wrap unique_ptr. // we do this with the crazy (and ugly) way to let SWIG create a new function // which is the same as the original, but returns a bare pointer. // (This will be wrapped as a shared_ptr in the end). @@ -1385,7 +1385,7 @@ namespace stir { const int num_views, const int num_tangential_poss, const bool arc_corrected = true) { - return + return construct_proj_data_info(scanner_sptr, span, max_delta, num_views, num_tangential_poss, arc_corrected).get(); @@ -1405,13 +1405,13 @@ namespace stir { %include "stir/ProjData.h" namespace stir { -%extend ProjData +%extend ProjData { #ifdef SWIGPYTHON %feature("autodoc", "create a stir 3D Array from the projection data (internal)") to_array; %newobject to_array; Array<3,float> to_array() - { + { Array<3,float> array = swigstir::projdata_to_3D(*$self); return array; } @@ -1423,7 +1423,7 @@ namespace stir { { Array<3,float> array = swigstir::create_array_for_proj_data(*$self); swigstir::fill_Array_from_Python_iterator(&array, arg); - swigstir::fill_proj_data_from_3D(*$self, array); + swigstir::fill_proj_data_from_3D(*$self, array); } else { @@ -1431,19 +1431,19 @@ namespace stir { snprintf(str, 1000, "Wrong argument-type used for fill(): should be a scalar or an iterator or so, but is of type %s", arg->ob_type->tp_name); throw std::invalid_argument(str); - } + } } #elif defined(SWIGMATLAB) %newobject to_matlab; mxArray * to_matlab() - { + { Array<3,float> array = swigstir::projdata_to_3D(*$self); - return swigstir::Array_to_matlab(array); + return swigstir::Array_to_matlab(array); } void fill(const mxArray *pm) - { + { Array<3,float> array; swigstir::fill_Array_from_matlab(array, pm, true); swigstir::fill_proj_data_from_3D(*$self, array); @@ -1456,7 +1456,7 @@ namespace stir { %include "stir/ProjDataInterfile.h" %include "stir/ProjDataInMemory.h" -namespace stir { +namespace stir { %template(FloatViewgram) Viewgram; %template(FloatSinogram) Sinogram; // TODO don't want to give a name @@ -1685,12 +1685,12 @@ namespace stir { %include "stir/recon_buildblock/ProjMatrixByBinUsingRayTracing.h" -%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) +%template (internalRPForwardProjectorByBinUsingProjMatrixByBin) stir::RegisteredParsingObject; %include "stir/recon_buildblock/ForwardProjectorByBinUsingProjMatrixByBin.h" -%template (internalRPBackProjectorByBinUsingProjMatrixByBin) +%template (internalRPBackProjectorByBinUsingProjMatrixByBin) stir::RegisteredParsingObject; %include "stir/recon_buildblock/BackProjectorByBinUsingProjMatrixByBin.h" From 7f7cec0b7a8aab0072c45690fc6def4d67038857 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 23 Apr 2020 00:45:42 +0200 Subject: [PATCH 246/274] edits scatter swig --- src/swig/stir.i | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swig/stir.i b/src/swig/stir.i index 617462e276..dc5e0e780e 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -1769,9 +1769,9 @@ stir::ScatterSimulation %include "stir/scatter/SingleScatterSimulation.h" -%shared_ptr(stir::ScatterEstimation); -%shared_ptr(stir::ParsingObject); -%include "stir/scatter/ScatterEstimation.h" +//%shared_ptr(stir::ScatterEstimation); +//%shared_ptr(stir::ParsingObject); +//%include "stir/scatter/ScatterEstimation.h" From 07635577ac23b17c52b04d1c4a7690681f6e0f67 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 23 Apr 2020 01:03:15 +0200 Subject: [PATCH 247/274] bin --- src/include/stir/Bin.h | 3 --- src/include/stir/Bin.inl | 8 -------- 2 files changed, 11 deletions(-) diff --git a/src/include/stir/Bin.h b/src/include/stir/Bin.h index 1f2698869e..3dd0b146e3 100644 --- a/src/include/stir/Bin.h +++ b/src/include/stir/Bin.h @@ -57,9 +57,6 @@ class Bin // inline Bin(int segment_num,int view_num, int axial_pos_num, int tangential_pos_num, float bin_value = 0); - - inline Bin(int segment_num,int view_num, int axial_pos_num, - int tangential_pos_num, float bin_value, int first_energy_window, int second_energy_window); //!get axial position number inline int axial_pos_num()const; diff --git a/src/include/stir/Bin.inl b/src/include/stir/Bin.inl index 47aeb4a08a..cef0da9ecf 100644 --- a/src/include/stir/Bin.inl +++ b/src/include/stir/Bin.inl @@ -40,14 +40,6 @@ Bin::Bin(int segment_num,int view_num, int axial_pos_num,int tangential_pos_num, :segment(segment_num),view(view_num), axial_pos(axial_pos_num),tangential_pos(tangential_pos_num),bin_value(bin_value) {} - -Bin::Bin(int segment_num,int view_num, int axial_pos_num,int tangential_pos_num,float bin_value, int first_energy_window, - int second_energy_window) - :segment(segment_num),view(view_num), - axial_pos(axial_pos_num),tangential_pos(tangential_pos_num),bin_value(bin_value),first_energy_window(first_energy_window), - second_energy_window(second_energy_window) - {} - int Bin:: axial_pos_num()const From 3d2f6c4f3c6f426e40e754a6252b1613177dcafd Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 30 Apr 2020 18:07:57 +0200 Subject: [PATCH 248/274] mergedwithNIKOS8th --- src/include/stir/scatter/ScatterEstimation.h | 4 ++-- src/swig/CMakeLists.txt | 2 +- src/swig/stir.i | 10 ++++------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/include/stir/scatter/ScatterEstimation.h b/src/include/stir/scatter/ScatterEstimation.h index 207847ac2a..b8dcd59539 100644 --- a/src/include/stir/scatter/ScatterEstimation.h +++ b/src/include/stir/scatter/ScatterEstimation.h @@ -188,9 +188,9 @@ class ScatterEstimation: public ParsingObject inline void set_scatter_simulation_method_sptr(const shared_ptr); //! Set the zoom factor in the XY plane for the downsampling of the activity and attenuation image. - inline void set_zoom_xy(float); + // inline void set_zoom_xy(float); //! Set the zoom factor in the Z axis for the downsampling of the activity and attenuation image. - inline void set_zoom_z(float); + // inline void set_zoom_z(float); // Get functions diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt index 8f7d483d17..7db5aa66bd 100644 --- a/src/swig/CMakeLists.txt +++ b/src/swig/CMakeLists.txt @@ -157,7 +157,7 @@ if (BUILD_SWIG_MATLAB) set (Matlab_CXXLINKER_FLAGS "/EXPORT:mexFunction") endif() SET_TARGET_PROPERTIES(${SWIG_MODULE_stirMATLAB_REAL_NAME} PROPERTIES - SUFFIX "_wrap.${MATLAB_MEX_EXT}" PREFIX "${MATLAB_PREFIX}" + SUFFIX "_wrap.${Matlab_MEX_EXT}" PREFIX "${MATLAB_PREFIX}" LINK_FLAGS "${Matlab_CXXLINKER_FLAGS}" FOLDER "Matlab") target_link_libraries(${SWIG_MODULE_stirMATLAB_REAL_NAME} ${OpenMP_EXE_LINKER_FLAGS}) diff --git a/src/swig/stir.i b/src/swig/stir.i index dc5e0e780e..0f55ed3121 100644 --- a/src/swig/stir.i +++ b/src/swig/stir.i @@ -108,8 +108,8 @@ #include "stir/scatter/ScatterSimulation.h" #include "stir/scatter/SingleScatterSimulation.h" -#include "stir/scatter/ScatterEstimation.h" #include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +#include "stir/scatter/ScatterEstimation.h" // TODO need this (bug in swig) // this bug occurs (only?) when using "%template(name) someclass;" inside the namespace @@ -1769,11 +1769,6 @@ stir::ScatterSimulation %include "stir/scatter/SingleScatterSimulation.h" -//%shared_ptr(stir::ScatterEstimation); -//%shared_ptr(stir::ParsingObject); -//%include "stir/scatter/ScatterEstimation.h" - - %shared_ptr(stir::RegisteredParsingObject< stir::SingleScatterLikelihoodAndGradient, @@ -1787,6 +1782,9 @@ stir::ScatterSimulation %include "stir/scatter/SingleScatterLikelihoodAndGradient.h" +%shared_ptr(stir::ScatterEstimation); +%shared_ptr(stir::ParsingObject); +%include "stir/scatter/ScatterEstimation.h" %include "stir/recon_buildblock/QuadraticPrior.h" From 9fa2013eb1d2a2a2ab4f9f21b6d70b893e972a92 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 2 May 2020 15:27:33 +0200 Subject: [PATCH 249/274] src --- src/scatter_utilities/estimate_scatter.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_utilities/estimate_scatter.cxx b/src/scatter_utilities/estimate_scatter.cxx index b3c4f4ebb2..4ac5a4d878 100644 --- a/src/scatter_utilities/estimate_scatter.cxx +++ b/src/scatter_utilities/estimate_scatter.cxx @@ -36,7 +36,7 @@ #include "stir/scatter/ScatterEstimation.h" #include "stir/Succeeded.h" /***********************************************************/ - +// static void print_usage_and_exit() { std::cerr<<"This executable runs a Scatter simulation method based on the options " From 9e6af02d4bf8018cc026cb9b365972b6547f71fb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 2 May 2020 15:28:18 +0200 Subject: [PATCH 250/274] src2 --- src/scatter_utilities/estimate_scatter.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_utilities/estimate_scatter.cxx b/src/scatter_utilities/estimate_scatter.cxx index 4ac5a4d878..b3c4f4ebb2 100644 --- a/src/scatter_utilities/estimate_scatter.cxx +++ b/src/scatter_utilities/estimate_scatter.cxx @@ -36,7 +36,7 @@ #include "stir/scatter/ScatterEstimation.h" #include "stir/Succeeded.h" /***********************************************************/ -// + static void print_usage_and_exit() { std::cerr<<"This executable runs a Scatter simulation method based on the options " From d92eea3e63fbecbc4c3e60372edd4212059c52b5 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 14 Oct 2020 20:15:03 -0400 Subject: [PATCH 251/274] tested with random hardcoded --- src/scatter_buildblock/ScatterSimulation.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 0e899674da..c4ab26d970 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -236,7 +236,7 @@ void ScatterSimulation::set_defaults() { this->attenuation_threshold = 0.01f ; - this->randomly_place_scatter_points = true; + this->randomly_place_scatter_points = false; this->use_cache = true; this->zoom_xy = -1.f; this->zoom_z = -1.f; @@ -259,7 +259,7 @@ ScatterSimulation:: ask_parameters() { this->attenuation_threshold = ask_num("attenuation threshold(cm^-1)",0.0f, 5.0f, 0.01f); - this->randomly_place_scatter_points = ask_num("random place scatter points?",0, 1, 1); + this->randomly_place_scatter_points = ask_num("random place scatter points?",0, 1, 0); this->use_cache = ask_num(" Use cache?",0, 1, 1); this->density_image_filename = ask_string("density image filename", ""); this->activity_image_filename = ask_string("activity image filename", ""); From 4df1b05a5f017a28f7b0e438cefbc0ac65d93d95 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 14 Oct 2020 21:57:10 -0400 Subject: [PATCH 252/274] cleaning scatter code --- src/IO/InterfileHeader.cxx | 8 +- src/include/stir/ExamInfo.h | 12 +- src/include/stir/ExamInfo.inl | 2 - .../SingleScatterLikelihoodAndGradient.h | 13 - ...ingleScatterLikelihoodAndGradient copy.cxx | 824 ------------------ .../SingleScatterLikelihoodAndGradient.cxx | 161 +--- 6 files changed, 13 insertions(+), 1007 deletions(-) delete mode 100644 src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index a78de4da92..0f3c52fdb1 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -223,12 +223,8 @@ InterfileHeader::InterfileHeader() // support for Louvain la Neuve's extension of 3.3 add_key("quantification units", &lln_quantification_units); -add_key("energy window pair", - KeyArgument::LIST_OF_INTS, - (KeywordProcessor)&InterfileHeader::en_window_pair_set, - &energy_window_pair); - add_key("number of energy windows", - KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_num_energy_windows,&num_energy_windows); + add_key("energy window pair", KeyArgument::LIST_OF_INTS, (KeywordProcessor)&InterfileHeader::en_window_pair_set, &energy_window_pair); + add_key("number of energy windows", KeyArgument::INT, (KeywordProcessor)&InterfileHeader::read_num_energy_windows,&num_energy_windows); add_vectorised_key("energy window lower level", &lower_en_window_thresholds); add_vectorised_key("energy window upper level", &upper_en_window_thresholds); diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index 746e63db3b..113ba48e01 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -105,11 +105,14 @@ public : inline void set_low_energy_thres(float new_val,int en_window = 0); //! Set the high energy boundary inline void set_high_energy_thres(float new_val,int en_window = 0); + //! Set the low energy boundary as a vector (currently only used in listmode code) + inline void set_low_energy_thres_vect(std::vector new_val,bool switch_energy = false); + //! Set the high energy boundary as a vector (currently only used in listmode code) + inline void set_high_energy_thres_vect(std::vector new_val,bool switch_energy = false); //! Set the number of energy windows inline void set_num_energy_windows(int n_win); + //! Set the energy window pair inline void set_energy_window_pair(std::vector val,int n_win); - inline void set_low_energy_thres_vect(std::vector new_val,bool switch_energy = false); - inline void set_high_energy_thres_vect(std::vector new_val,bool switch_energy = false); //@} inline bool has_energy_information() const @@ -158,6 +161,11 @@ public : //! If scatter simulation is not needed, can default to -1 std::vector up_energy_thres; + //! + //! \brief en_win_pair + //! \author Ludovica Brusaferri + //! \details This is the value of the energy window pair for a certain sinogram + //! Can default to {1,1} std::vector en_win_pair; }; diff --git a/src/include/stir/ExamInfo.inl b/src/include/stir/ExamInfo.inl index 2283ce53e4..f666ee699b 100644 --- a/src/include/stir/ExamInfo.inl +++ b/src/include/stir/ExamInfo.inl @@ -57,7 +57,6 @@ ExamInfo::set_low_energy_thres_vect(std::vector new_val, bool switch_ener { low_energy_thres = new_val; //TODO extend to the case of more than two - //Decrescent ordering if (switch_energy) { @@ -72,7 +71,6 @@ ExamInfo::set_high_energy_thres_vect(std::vector new_val, bool switch_ene { up_energy_thres = new_val; //TODO extend to the case of more than two - //Decrescent ordering if (switch_energy) { diff --git a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h index e7bc198888..a1cc2ffcd0 100644 --- a/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h +++ b/src/include/stir/scatter/SingleScatterLikelihoodAndGradient.h @@ -64,7 +64,6 @@ class SingleScatterLikelihoodAndGradient : public double L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); double L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); - void L_G_function_from_est_data(const ProjData& data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient = true ,const bool isgradient_mu = true,const float rescale = 1.F); ProjDataInMemory likelihood_and_gradient_scatter(const ProjData &projdata,const ProjData& norm, const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu); ProjDataInMemory get_jacobian(std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); ProjDataInMemory get_ratio(const ProjData& projdata,const ProjData& norm,const ProjData &add_projdata, const ProjData &est_projdata, std::vector &ratio_vector); @@ -95,21 +94,9 @@ class SingleScatterLikelihoodAndGradient : public const bool isgradient_mu); double L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, const bool compute_gradient, const bool isgradient_mu); - double L_G_for_view_segment_number(const ProjData&data,const ProjData&add_sino,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu); - - inline float KL(const double a, const float b, const float threshold_a = 0); - double L_G_for_viewgram(const Viewgram& viewgram,const Viewgram& v_add, Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - - - void L_G_for_view_segment_number_from_est_data(const ProjData&data,VoxelsOnCartesianGrid& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu); - - - void L_G_for_viewgram_from_est_data(const Viewgram& viewgram,VoxelsOnCartesianGrid& gradient_image,const float rescale, const bool compute_gradient,const bool isgradient_mu); - void get_jacobian_for_view_segment_number(std::vector > &gradient_image_array,ProjData &est_data,const ViewSegmentNumbers& vs_num, const bool compute_gradient,const bool isgradient_mu); - void get_jacobian_for_viewgram(Viewgram& v_est, std::vector > &gradient_image_array,const bool compute_gradient, const bool isgradient_mu); }; diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx deleted file mode 100644 index f7d12bd428..0000000000 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient copy.cxx +++ /dev/null @@ -1,824 +0,0 @@ -/* - Copyright (C) 2016 University College London - This file is part of STIR. - - This file is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - See STIR/LICENSE.txt for details -*/ -#include "stir/scatter/SingleScatterLikelihoodAndGradient.h" -#include "stir/scatter/ScatterSimulation.h" -#include "stir/ViewSegmentNumbers.h" -#include "stir/Bin.h" - -#include "stir/Viewgram.h" -#include "stir/is_null_ptr.h" -#include "stir/IO/read_from_file.h" -#include "stir/IO/write_to_file.h" -#include "stir/info.h" -#include "stir/error.h" -#include -#include - -#include "stir/zoom.h" -#include "stir/SSRB.h" - -#include "stir/stir_math.h" -#include "stir/NumericInfo.h" - -START_NAMESPACE_STIR - -const char * const -SingleScatterLikelihoodAndGradient::registered_name = - "Single Scatter Likelihood And Gradient"; - - -SingleScatterLikelihoodAndGradient:: -SingleScatterLikelihoodAndGradient() : - base_type() -{ - this->set_defaults(); -} - - - -SingleScatterLikelihoodAndGradient:: -SingleScatterLikelihoodAndGradient(const std::string& parameter_filename) -{ - this->initialise(parameter_filename); -} - -SingleScatterLikelihoodAndGradient:: -~SingleScatterLikelihoodAndGradient() -{} - -static const float total_Compton_cross_section_511keV = -ScatterSimulation:: -total_Compton_cross_section(511.F); - -double -SingleScatterLikelihoodAndGradient:: -L_G_function(const ProjData& data,VoxelsOnCartesianGrid& gradient_image, const bool compute_gradient, const bool isgradient_mu, const float rescale) -{ - - shared_ptr add_sino(new ProjDataInMemory(this->output_proj_data_sptr->get_exam_info_sptr(), - this->output_proj_data_sptr->get_proj_data_info_ptr()->create_shared_clone())); - add_sino->fill(0.000000000000000000001); - - L_G_function(data,*add_sino,gradient_image,compute_gradient,isgradient_mu,rescale); -} - -double -SingleScatterLikelihoodAndGradient:: -L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) -{ - - this->output_proj_data_sptr->fill(0.f); - - std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; - - if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && - this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) - { - std::cout << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; - - } - - - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - std::cout << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); - this->remove_cache_for_integrals_over_attenuation(); - this->sample_scatter_points(); - this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - - ViewSegmentNumbers vs_num; - - int bin_counter = 0; - int axial_bins = 0 ; - double sum = 0; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns - coordinate in a coordinate system where z=0 in the first ring of the scanner. - We want to shift this to a coordinate system where z=0 in the middle - of the scanner. - We can use get_m() as that uses the 'middle of the scanner' system. - (sorry) - */ -#ifndef NDEBUG - { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( - detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - assert(detector_coord_A.z() == 0); - assert(detector_coord_B.z() == 0); - // check that get_m refers to the middle of the scanner - const float m_first = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); - assert(fabs(m_last + m_first) < m_last * 10E-4); - } -#endif - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - - info("ScatterSimulator: Initialization finished ..."); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); - ++vs_num.view_num()) - { - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - - sum+=this->L_G_for_view_segment_number(data, add_sino,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); - - bin_counter += - this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - std::cout<< bin_counter << " / "<< total_bins < 1.E20) - warning("KL large at a=%g b=%g, threshold %g\n",a,b,threshold_a); -#ifdef ICHANGEDIT -#undef NDEBUG -#endif -#endif - assert(res>=-1.e-4); - return res; -} - - -double -SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram(const Viewgram& viewgram, const Viewgram& v_add,Viewgram& v_est,VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) -{ - - const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); - - // First construct a vector of all bins that we'll process. - // The reason for making this list before the actual calculation is that we can then parallelise over all bins - // without having to think about double loops. - std::vector all_bins; - { - Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); - - for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); - bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - { - all_bins.push_back(bin); - } - } - } - // now compute scatter for all bins - - double sum = 0; - - - VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); - -#ifdef STIR_OPENMP -#pragma omp parallel for reduction(+:total_scatter) schedule(dynamic) -#endif - - for (int i = 0; i < static_cast(all_bins.size()); ++i) - { - //creates a template image to fill - tmp_gradient_image.fill(0); - - const Bin bin = all_bins[i]; - - //forward model - const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); - - v_est[bin.axial_pos_num()][bin.tangential_pos_num()] = static_cast(rescale*y); - //in case a scaling factor for the data is needed,i.e. for adding different level of noise. By default is set to 1. - - float eps = v_add[bin.axial_pos_num()][bin.tangential_pos_num()]; - //float eps = 0.000000000000000000001; - sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-eps; - gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)-1); - if (sum != sum) error('Nan Here'); - } - - return sum; -} - - - - -double -SingleScatterLikelihoodAndGradient:: -L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, const bool compute_gradient,const bool isgradient_mu) -{ - double scatter_ratio_singles = 0; - unsigned det_num_B=0; - unsigned det_num_A=0; - - this->find_detectors(det_num_A, det_num_B,bin); - - for(std::size_t scatter_point_num =0; - scatter_point_num < this->scatt_points_vector.size(); - ++scatter_point_num) - { - - - - - scatter_ratio_singles += - L_G_for_one_scatter_point(gradient_image_bin, - scatter_point_num, - det_num_A, det_num_B,compute_gradient, isgradient_mu); - - } - - return scatter_ratio_singles; - //if (scatter_ratio_singles<0) std::cerr << "scatter_ratio_singles<0:" <& gradient, - const std::size_t scatter_point_num, - const unsigned det_num_A, - const unsigned det_num_B, const bool compute_gradient,const bool isgradient_mu) -{ - - // The code now supports more than one energy window: the low energy threshold has to correspond to lowest window. - - int low = 0; - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - - { - - int first_window=this->template_exam_info_sptr->get_energy_window_pair().first-1; - int second_window=this->template_exam_info_sptr->get_energy_window_pair().second-1; - - if(this->template_exam_info_sptr->get_low_energy_thres(first_window) <= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) - - { - low = first_window; - } - - else if(this->template_exam_info_sptr->get_low_energy_thres(first_window) >= this->template_exam_info_sptr->get_low_energy_thres(second_window) ) - - { - low = second_window; - } - - } - - static const float max_single_scatter_cos_angle=max_cos_angle(this->template_exam_info_sptr->get_low_energy_thres(low), - 2.f, - this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution()); - - //static const float min_energy=energy_lower_limit(lower_energy_threshold,2.,energy_resolution); - - const CartesianCoordinate3D& scatter_point = - this->scatt_points_vector[scatter_point_num].coord; - const CartesianCoordinate3D& detector_coord_A = - this->detection_points_vector[det_num_A]; - const CartesianCoordinate3D& detector_coord_B = - this->detection_points_vector[det_num_B]; - // note: costheta is -cos_angle such that it is 1 for zero scatter angle - const float costheta = static_cast( - -cos_angle(detector_coord_A - scatter_point, - detector_coord_B - scatter_point)); - // note: costheta is identical for scatter to A or scatter to B - // Hence, the Compton_cross_section and energy are identical for both cases as well. - if(max_single_scatter_cos_angle>costheta) - return 0; - const float new_energy = - photon_energy_after_Compton_scatter_511keV(costheta); - - // The detection efficiency varies with respect to the energy window. - //The code can now compute the scatter for a combination of two windows X and Y - //Default: one window -> The code will combine the window with itself - - - //compute the probability of detection for two given energy windows X and Y - - - std::vectordetection_efficiency_scattered; - std::vectordetection_efficiency_unscattered; - - - detection_efficiency_scattered.push_back(0); - detection_efficiency_unscattered.push_back(0); - - - - //detection efficiency of each window for that energy - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - detection_efficiency_scattered[i] = detection_efficiency(new_energy,i); - detection_efficiency_unscattered[i] = detection_efficiency(511.F,i); - } - - - int index0 = 0; - int index1 = 0; - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - index0 = this->template_exam_info_sptr->get_energy_window_pair().first-1; - index1 = this->template_exam_info_sptr->get_energy_window_pair().second-1; - - } - - - float detection_probability_XY=detection_efficiency_scattered[index0]*detection_efficiency_unscattered[index1]; - float detection_probability_YX=detection_efficiency_scattered[index1]*detection_efficiency_unscattered[index0]; - - - - - const float emiss_to_detA = - cached_integral_over_activity_image_between_scattpoint_det - (static_cast (scatter_point_num), - det_num_A); - const float emiss_to_detB = - cached_integral_over_activity_image_between_scattpoint_det - (static_cast (scatter_point_num), - det_num_B); - if (emiss_to_detA==0 && emiss_to_detB==0) - return 0; - const float atten_to_detA = - cached_exp_integral_over_attenuation_image_between_scattpoint_det - (scatter_point_num, - det_num_A); - const float atten_to_detB = - cached_exp_integral_over_attenuation_image_between_scattpoint_det - (scatter_point_num, - det_num_B); - - const float dif_Compton_cross_section_value = - dif_Compton_cross_section(costheta, 511.F); - - const float rA_squared=static_cast(norm_squared(scatter_point-detector_coord_A)); - const float rB_squared=static_cast(norm_squared(scatter_point-detector_coord_B)); - - const float scatter_point_mu= - scatt_points_vector[scatter_point_num].mu_value; - - const CartesianCoordinate3D - detA_to_ring_center(0,-detector_coord_A[2],-detector_coord_A[3]); - const CartesianCoordinate3D - detB_to_ring_center(0,-detector_coord_B[2],-detector_coord_B[3]); - const float cos_incident_angle_AS = static_cast( - cos_angle(scatter_point - detector_coord_A, - detA_to_ring_center)); - const float cos_incident_angle_BS = static_cast( - cos_angle(scatter_point - detector_coord_B, - detB_to_ring_center)); - - if (cos_incident_angle_AS*cos_incident_angle_BS<0) - return 0; - -#ifndef NDEBUG - { - // check if mu-value ok - // currently terribly shift needed as in sample_scatter_points (TODO) - const VoxelsOnCartesianGrid& image = - dynamic_cast&>(*this->density_image_for_scatter_points_sptr); - const CartesianCoordinate3D voxel_size = image.get_voxel_size(); - const float z_to_middle = - (image.get_max_index() + image.get_min_index())*voxel_size.z()/2.F; - CartesianCoordinate3D shifted=scatter_point; - shifted.z() += z_to_middle; - assert(scatter_point_mu== - (*this->density_image_for_scatter_points_sptr)[this->density_image_for_scatter_points_sptr->get_indices_closest_to_physical_coordinates(shifted)]); - } -#endif - -#ifndef NEWSCALE - /* projectors work in pixel units, so convert attenuation data - from cm^-1 to pixel_units^-1 */ - const float rescale = - dynamic_cast &>(*density_image_sptr). - get_grid_spacing()[3]/10; -#else - const float rescale = - 0.1F; -#endif - - - //normalisation - - - // we will divide by the effiency of the detector pair for unscattered photons - // (computed with the same detection model as used in the scatter code) - // This way, the scatter estimate will correspond to a 'normalised' scatter estimate. - - // there is a scatter_volume factor for every scatter point, as the sum over scatter points - // is an approximation for the integral over the scatter point. - - // the factors total_Compton_cross_section_511keV should probably be moved to the scatter_computation code - - - // currently the scatter simulation is normalised w.r.t. the detection efficiency in the photopeak window - //find the window that contains 511 keV - - int index_photopeak = 0; //default for one energy window - - if (this->template_exam_info_sptr->get_num_energy_windows()>1) - { - for (int i = 0 ; i < this->template_exam_info_sptr->get_num_energy_windows() ; ++i) - { - if( this->template_exam_info_sptr->get_high_energy_thres(i) >= 511.F && this->template_exam_info_sptr->get_low_energy_thres(i) <= 511.F) - - { - - index_photopeak = i; - } - - } - } - - //normalisation factor between trues and scattered counts - - const double common_factor = - 1/detection_efficiency_no_scatter(det_num_A, det_num_B, index_photopeak) * - scatter_volume/total_Compton_cross_section_511keV; - - - // Single ScatterForward Model - - float scatter_ratio=0; - - scatter_ratio= (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - - - /*Single Scatter Forward model Jacobian w.r.t. attenuation: - * The derivative is given by three terms, respectively in [A,S], [B,S] and [S] */ - - float contribution_AS_mu = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - total_Compton_cross_section_relative_to_511keV(new_energy)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - float contribution_BS_mu = (detection_probability_XY*emiss_to_detA* - (1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)* - (total_Compton_cross_section_relative_to_511keV(new_energy)) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)* - pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - float contribution_S = (detection_probability_XY*emiss_to_detA*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1) - +detection_probability_YX*emiss_to_detB*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - - /*Single Scatter Forward model Jacobian w.r.t. activity: - * - * The derivative is given by two terms, respectively in [A,S] and [B,S] */ - - - float contribution_AS_act = (detection_probability_XY*(1.F/rB_squared)*pow(atten_to_detB,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - float contribution_BS_act = (detection_probability_YX*(1.F/rA_squared)*pow(atten_to_detA,total_Compton_cross_section_relative_to_511keV(new_energy)-1)) - *atten_to_detB - *atten_to_detA - *scatter_point_mu - *cos_incident_angle_AS - *cos_incident_angle_BS - *dif_Compton_cross_section_value - *common_factor; - - - //Fill gradient image along [A,S], [B,S] and in [S] - - -if(compute_gradient) -{ - if (isgradient_mu) - - { - line_contribution(gradient,rescale,scatter_point, - detector_coord_B,contribution_BS_mu); - - line_contribution(gradient,rescale,scatter_point, - detector_coord_A,contribution_AS_mu); - - s_contribution(gradient,scatter_point, - contribution_S); - - } - - else - - { - - line_contribution_act(gradient,scatter_point, - detector_coord_B,contribution_BS_act); - - line_contribution_act(gradient,scatter_point, - detector_coord_A,contribution_AS_act); - } - -} - - - - return scatter_ratio; - -} - - - -double -SingleScatterLikelihoodAndGradient:: -L_G_function_from_est_data(const ProjData& data,const ProjData &est_data,VoxelsOnCartesianGrid& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) -{ - - this->output_proj_data_sptr->fill(0.f); - - std::cout << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; - - if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && - this->template_exam_info_sptr->get_energy_window_pair().second!= -1 ) - { - std::cout << "energy window pair :="<<" {"<< this->template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; - - } - - - for (int i = 0; i < this->template_exam_info_sptr->get_num_energy_windows(); ++i) - { - std::cout << "energy window lower level"<<"["<remove_cache_for_integrals_over_activity(); - this->remove_cache_for_integrals_over_attenuation(); - this->sample_scatter_points(); - this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - - ViewSegmentNumbers vs_num; - - int bin_counter = 0; - int axial_bins = 0 ; - double sum = 0; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns - coordinate in a coordinate system where z=0 in the first ring of the scanner. - We want to shift this to a coordinate system where z=0 in the middle - of the scanner. - We can use get_m() as that uses the 'middle of the scanner' system. - (sorry) - */ -#ifndef NDEBUG - { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( - detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - assert(detector_coord_A.z() == 0); - assert(detector_coord_B.z() == 0); - // check that get_m refers to the middle of the scanner - const float m_first = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); - assert(fabs(m_last + m_first) < m_last * 10E-4); - } -#endif - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - - info("ScatterSimulator: Initialization finished ..."); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); - ++vs_num.view_num()) - { - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - - sum+=this->L_G_for_view_segment_number_from_est_data(data, est_data,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); - - bin_counter += - this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - std::cout<< bin_counter << " / "<< total_bins <template_exam_info_sptr->get_energy_window_pair().first << ',' << this->template_exam_info_sptr->get_energy_window_pair().second <<"}\n"; - } @@ -174,12 +172,7 @@ L_G_function(const ProjData& data,const ProjData &add_sino,VoxelsOnCartesianGrid } } - - - std::cout << "LIKELIHOOD:= " << sum << '\n'; - - return sum; } @@ -193,7 +186,6 @@ L_G_for_view_segment_number(const ProjData&data, const ProjData&add_sino,VoxelsO Viewgram v_est= this->proj_data_info_cyl_noarc_cor_sptr->get_empty_viewgram(vs_num.view_num(), vs_num.segment_num()); double sum = L_G_for_viewgram(viewgram,v_add,v_est,gradient_image, rescale, compute_gradient,isgradient_mu); - return sum; } @@ -266,10 +258,8 @@ L_G_for_viewgram(const Viewgram& viewgram, const Viewgram& v_add,V //in case a scaling factor for the data is needed,i.e. for adding different level of noise. By default is set to 1. float eps = v_add[bin.axial_pos_num()][bin.tangential_pos_num()]; - //float eps = 0.000000000000000000001; sum+=viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]*log(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)- v_est[bin.axial_pos_num()][bin.tangential_pos_num()]-eps; gradient_image += tmp_gradient_image*(viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]/(v_est[bin.axial_pos_num()][bin.tangential_pos_num()]+eps)-1); - if (sum != sum) error('Nan Here'); } return sum; @@ -292,19 +282,13 @@ L_G_estimate(VoxelsOnCartesianGrid& gradient_image_bin,const Bin bin, con scatter_point_num < this->scatt_points_vector.size(); ++scatter_point_num) { - - - - scatter_ratio_singles += L_G_for_one_scatter_point(gradient_image_bin, scatter_point_num, det_num_A, det_num_B,compute_gradient, isgradient_mu); - } return scatter_ratio_singles; - //if (scatter_ratio_singles<0) std::cerr << "scatter_ratio_singles<0:" <& gradient_image,const bool compute_gradient, const bool isgradient_mu, const float rescale) -{ - - info("ScatterSimulator: Running Scatter Simulation ..."); - info("ScatterSimulator: Initialising ..."); - // The activiy image might have been changed, during the estimation process. - this->remove_cache_for_integrals_over_activity(); - this->remove_cache_for_integrals_over_attenuation(); - this->sample_scatter_points(); - this->initialise_cache_for_scattpoint_det_integrals_over_attenuation(); - this->initialise_cache_for_scattpoint_det_integrals_over_activity(); - - ViewSegmentNumbers vs_num; - - int bin_counter = 0; - int axial_bins = 0 ; - double sum = 0; - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - axial_bins += this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()); - - const int total_bins = - this->proj_data_info_cyl_noarc_cor_sptr->get_num_views() * axial_bins * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - /* Currently, proj_data_info.find_cartesian_coordinates_of_detection() returns - coordinate in a coordinate system where z=0 in the first ring of the scanner. - We want to shift this to a coordinate system where z=0 in the middle - of the scanner. - We can use get_m() as that uses the 'middle of the scanner' system. - (sorry) - */ -#ifndef NDEBUG - { - CartesianCoordinate3D detector_coord_A, detector_coord_B; - // check above statement - this->proj_data_info_cyl_noarc_cor_sptr->find_cartesian_coordinates_of_detection( - detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); - assert(detector_coord_A.z() == 0); - assert(detector_coord_B.z() == 0); - // check that get_m refers to the middle of the scanner - const float m_first = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(0), 0)); - const float m_last = - this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(0), 0)); - assert(fabs(m_last + m_first) < m_last * 10E-4); - } -#endif - this->shift_detector_coordinates_to_origin = - CartesianCoordinate3D(this->proj_data_info_cyl_noarc_cor_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); - - info("ScatterSimulator: Initialization finished ..."); - - for (vs_num.segment_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_segment_num(); - vs_num.segment_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_segment_num(); - ++vs_num.segment_num()) - { - for (vs_num.view_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_view_num(); - vs_num.view_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_view_num(); - ++vs_num.view_num()) - { - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - - this->L_G_for_view_segment_number_from_est_data(data,gradient_image,vs_num,rescale,compute_gradient,isgradient_mu); - - bin_counter += - this->proj_data_info_cyl_noarc_cor_sptr->get_num_axial_poss(vs_num.segment_num()) * - this->proj_data_info_cyl_noarc_cor_sptr->get_num_tangential_poss(); - //info(boost::format("ScatterSimulator: %d / %d") % bin_counter% total_bins); - - std::cout<< bin_counter << " / "<< total_bins <& gradient_image,const ViewSegmentNumbers& vs_num, const float rescale, const bool compute_gradient,const bool isgradient_mu) -{ - - Viewgram viewgram=data.get_viewgram(vs_num.view_num(), vs_num.segment_num(),false); - - L_G_for_viewgram_from_est_data(viewgram,gradient_image, rescale, compute_gradient,isgradient_mu); - - -} - - -void -SingleScatterLikelihoodAndGradient:: -L_G_for_viewgram_from_est_data(const Viewgram& viewgram, VoxelsOnCartesianGrid& gradient_image,const float rescale,const bool compute_gradient, const bool isgradient_mu) -{ - - const ViewSegmentNumbers vs_num(viewgram.get_view_num(),viewgram.get_segment_num()); - - // First construct a vector of all bins that we'll process. - // The reason for making this list before the actual calculation is that we can then parallelise over all bins - // without having to think about double loops. - std::vector all_bins; - { - Bin bin(vs_num.segment_num(), vs_num.view_num(), 0, 0); - - for (bin.axial_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_axial_pos_num(bin.segment_num()); - bin.axial_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_axial_pos_num(bin.segment_num()); - ++bin.axial_pos_num()) - { - for (bin.tangential_pos_num() = this->proj_data_info_cyl_noarc_cor_sptr->get_min_tangential_pos_num(); - bin.tangential_pos_num() <= this->proj_data_info_cyl_noarc_cor_sptr->get_max_tangential_pos_num(); - ++bin.tangential_pos_num()) - { - all_bins.push_back(bin); - } - } - } - // now compute scatter for all bins - - double sum = 0; - - - VoxelsOnCartesianGrid tmp_gradient_image(gradient_image); - - - for (int i = 0; i < static_cast(all_bins.size()); ++i) - { - //creates a template image to fill - tmp_gradient_image.fill(0); - const Bin bin = all_bins[i]; - - //forward model - const double y = L_G_estimate(tmp_gradient_image,bin,compute_gradient,isgradient_mu); - gradient_image += tmp_gradient_image*viewgram[bin.axial_pos_num()][bin.tangential_pos_num()]; - if (sum != sum) error('Nan Here'); - } -} - - ProjDataInMemory SingleScatterLikelihoodAndGradient:: likelihood_and_gradient_scatter(const ProjData &projdata, const ProjData& norm , const ProjData &add_projdata, VoxelsOnCartesianGrid& gradient_image_HR, VoxelsOnCartesianGrid& gradient_image_LR,const bool compute_gradient, const bool isgradient_mu) From b95f50b37118a399e16a4f1732b94dd3ca41fe85 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 14 Oct 2020 22:01:08 -0400 Subject: [PATCH 253/274] cleaned --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index a659e3e7b7..f43931d8ba 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -444,8 +444,6 @@ L_G_for_one_scatter_point(VoxelsOnCartesianGrid& gradient, const float rescale = 0.1F; #endif - - //normalisation // we will divide by the solid angle factors for unscattered photons // (computed with the same detection model as used in the scatter code) From aabc0e215ca6554e7ea7e66b10acee7a6db64d41 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 14 Oct 2020 22:15:15 -0400 Subject: [PATCH 254/274] removed efficiency integrals --- src/include/stir/scatter/ScatterSimulation.h | 10 +- .../scatter_detection_modelling.cxx | 126 +++--------------- 2 files changed, 24 insertions(+), 112 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index c2aa3fbd90..f6369eeb98 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -223,20 +223,14 @@ class ScatterSimulation : public RegisteredObject total_Compton_cross_section_relative_to_511keV(const float energy); //@} - float detection_efficiency_num(const float energy, const int en_window = 0) const; - float detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const; - float detection_efficiency_integral(const float incoming_photon_energy, const int en_window = 0) const; float detection_efficiency(const float incoming_photon_energy, const int en_window = 0) const; - std::vector detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; + float detection_efficiency_numerical_formulation(const float energy, const int en_window = 0) const; + std::vector detection_spectrum_numerical_formulation(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const; float detection_model_with_fitted_parameters(const float x, const float energy) const; float photoelectric(const float K, const float std_peak, const float x, const float energy) const; float compton_plateau(const float K, const float std_peak, const float x, const float energy, const float scaling_std_compton,const float shift_compton) const; float flat_continuum(const float K, const float std_peak, const float x, const float energy) const; float exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const; - float integral_photoelectric(const float LT, const float HT, const float FWHM, const float energy) const; - float integral_compton_plateau(const float LT, const float HT, const float FWHM, const float energy) const; - float integral_flat_continuum(const float LT, const float HT, const float FWHM, const float energy) const; - float integral_exponential_tail(const float LT, const float HT, const float FWHM, const float energy) const; //! find scatter points /*! This function sets scatt_points_vector and scatter_volume. It will also remove any cached integrals as they would be incorrect otherwise. diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index a7eef75899..47d390c30c 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -131,57 +131,8 @@ detection_efficiency(const float energy, const int en_window) const return efficiency; } -std::vector -ScatterSimulation::detection_spectrum(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const -{ - - std::vector output(size); - double increment_x = (HLD - LLD) / (size - 1); - - for(int i = 0; i < size; ++i) - { - output[i] = LLD + (i * increment_x); - std::cout << output[i] << std::endl; - } - - for(int i = 0; i < size; ++i) - { - output[i] = detection_model_with_fitted_parameters(output[i], incoming_photon_energy); - } - - return output; -} - float -ScatterSimulation::detection_efficiency_integral(const float incoming_photon_energy, const int en_window) const -{ - - const float HT = this->template_exam_info_sptr->get_high_energy_thres(en_window); - const float LT = this->template_exam_info_sptr->get_low_energy_thres(en_window); - const float FWHM = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); - const float f1 = integral_photoelectric(LT,HT, FWHM, incoming_photon_energy) ; - const float f2 = integral_compton_plateau(LT,HT, FWHM, incoming_photon_energy) ; - const float f3 = integral_flat_continuum(LT,HT, FWHM, incoming_photon_energy) ; - const float f4 = integral_exponential_tail(LT,HT, FWHM, incoming_photon_energy) ; - return f1+f2+f3+f4; - } - -float -ScatterSimulation::detection_efficiency_integral(const float incoming_photon_energy, const float LT, const float HT, const float FWHM) const -{ - - //const float HT = this->template_exam_info_sptr->get_high_energy_thres(en_window); - //const float LT = this->template_exam_info_sptr->get_low_energy_thres(en_window); - //const float FWHM = this->proj_data_info_cyl_noarc_cor_sptr->get_scanner_ptr()->get_energy_resolution(); - const float f1 = integral_photoelectric(LT,HT, FWHM, incoming_photon_energy) ; - const float f2 = integral_compton_plateau(LT,HT, FWHM, incoming_photon_energy) ; - const float f3 = integral_flat_continuum(LT,HT, FWHM, incoming_photon_energy) ; - const float f4 = integral_exponential_tail(LT,HT, FWHM, incoming_photon_energy) ; - return f1+f2+f3+f4; - } - -float -ScatterSimulation::detection_efficiency_num(const float incoming_photon_energy, const int en_window) const +ScatterSimulation::detection_efficiency_numerical_formulation(const float incoming_photon_energy, const int en_window) const { const float HLD = this->template_exam_info_sptr->get_high_energy_thres(en_window); @@ -202,6 +153,27 @@ ScatterSimulation::detection_efficiency_num(const float incoming_photon_energy, return sum; } +std::vector +ScatterSimulation::detection_spectrum_numerical_formulation(const float LLD, const float HLD, const float size, const float incoming_photon_energy) const +{ + + std::vector output(size); + double increment_x = (HLD - LLD) / (size - 1); + + for(int i = 0; i < size; ++i) + { + output[i] = LLD + (i * increment_x); + std::cout << output[i] << std::endl; + } + + for(int i = 0; i < size; ++i) + { + output[i] = detection_model_with_fitted_parameters(output[i], incoming_photon_energy); + } + + return output; +} + float ScatterSimulation:: @@ -278,60 +250,6 @@ exponential_tail(const float K, const float std_peak, const float x, const float return 0; } -float -ScatterSimulation:: -integral_photoelectric(const float LT, const float HT, const float FWHM, const float energy) const -{ -const float den = energy; -const float num = -145.897*erf((1.66511*(energy -HT))/(energy*FWHM))+145.897*erf((1.66511*abs((energy -LT)))/(energy*FWHM)); - return num/den; -} - -float -ScatterSimulation:: -integral_compton_plateau(const float LT, const float HT, const float FWHM, const float energy) const -{ -const float a = pow((255.5+energy),3); -const float b = sqrt(energy*FWHM); -const float fact1 = 1/(a*b)*FWHM; -const float fact2a = 8.88178*1e-16*erf(0.0832061*sqrt(energy/FWHM)); -const float fact2b = -6.28408*erf((0.0832061*energy-0.141027*HT)/sqrt(energy*FWHM)); -const float fact2c = ((0.522874*energy-0.886227*LT)*erf((0.0832061*abs(energy-1.69492*LT))/(sqrt(energy*FWHM))))/(abs(0.0832061*energy-0.141027*LT)); -const float fact2 = fact2a+fact2b+fact2c; -const float fact3 = (energy*(96199.6+energy*(753.03+(1.65785+0.00036048*energy)*energy)) - + (-2.4579*1e07+energy*(-240499+energy*(-705.966+(-0.36841+0.000720959*energy)*energy)))*log(1+0.00391389*energy)); - -return fact1*fact2*fact3; -} - -float -ScatterSimulation:: -integral_flat_continuum(const float LT, const float HT, const float FWHM, const float energy) const -{ - const float num1 = pow((energy-LT),2); - const float den1 = pow((energy*FWHM),2); - const float fact1 = -5.52632*1e-07+5.52632*1e-07*exp(-(2.77259*num1)/(den1))*energy*FWHM; - const float fact2 = 1.631*1e-06*energy-1.631*1e-06*LT; - const float fact3 = erfc((1.66511*(-energy*LT))/(energy*FWHM)); - return fact1 + fact2*fact3; -} - -float -ScatterSimulation:: -integral_exponential_tail(const float LT, const float HT, const float FWHM, const float energy) const -{ -const float fact1 = 6.058*1e-06*exp(0.64874/FWHM)*energy*FWHM; -const float fact2 = -1.26141*exp(-0.64874/FWHM)*erf(0.417191+(1.66511-(1.66511*LT)/(energy))/FWHM); -const float fact3 = 1.26141*exp(-0.64874/FWHM)*erf(0.417191+(1.66511-(1.66511*HT)/(energy))/FWHM); -const float fact4 = 1.54145*exp(-0.64874*LT/(energy*FWHM))*erfc(-0.611995+(-1.66511+(1.66511*LT)/(energy))/FWHM); -const float fact5 = -1.54145*exp(-0.64874*HT/(energy*FWHM))*erfc(-0.611995+(-1.66511+(1.66511*HT)/(energy))/FWHM); -if (energy<150) - return 0; -else - return fact1*(fact2+fact3+fact4+fact5); -} - - float ScatterSimulation:: max_cos_angle(const float low, const float approx, const float resolution_at_511keV) From a7b9bbac56000f1cb38354eda5437082f9e893ec Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 15 Oct 2020 16:15:13 -0400 Subject: [PATCH 255/274] ok with may 22 --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index f43931d8ba..03f4213ed1 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -774,7 +774,7 @@ get_ratio(const ProjData& projdata,const ProjData& norm,const ProjData &add_proj if(ratio_vector.size()!=counter) error("SIZE is %d , but it should be %d",ratio_vector.size(),counter); -return est_projdata_HR; +return est_projdata_HR;// } END_NAMESPACE_STIR From 5983a02fa219d8efb9f5ddb60856f014199cc100 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 15 Oct 2020 21:40:20 -0400 Subject: [PATCH 256/274] unit test --- src/scatter_buildblock/ScatterSimulation.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 8a48ba43f1..2a5286ac52 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -74,11 +74,12 @@ process_data() { if (!this->_already_set_up) error("ScatterSimulation: need to call set_up() first"); - // this is useful in the scatter estimation process. this->output_proj_data_sptr->fill(0.f); //show energy window information + std::cerr << "LOW THRES PROCESS DATA 0:" << this->template_exam_info_sptr->get_low_energy_thres(0) << "\n"; + std::cerr << "LOW THRES PROCESS DATA 1:" << this->template_exam_info_sptr->get_low_energy_thres(1) << "\n"; std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && @@ -742,7 +743,8 @@ set_template_proj_data_info(const std::string& filename) shared_ptr template_proj_data_sptr(ProjData::read_from_file(this->template_proj_data_filename)); this->set_exam_info(template_proj_data_sptr->get_exam_info()); - + std::cerr << "LOW THRES SET TEMP 0:" << template_proj_data_sptr->get_exam_info().get_low_energy_thres(0) << "\n"; + std::cerr << "LOW THRES SET TEMP 1:" << template_proj_data_sptr->get_exam_info().get_low_energy_thres(1) << "\n"; this->set_template_proj_data_info(*template_proj_data_sptr->get_proj_data_info_sptr()); } From 8d26da805477c416e718edf04fae5b105f87cfa9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 15 Oct 2020 22:25:45 -0400 Subject: [PATCH 257/274] test --- src/scatter_buildblock/ScatterSimulation.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 2a5286ac52..b677e0a9de 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -78,8 +78,6 @@ process_data() this->output_proj_data_sptr->fill(0.f); //show energy window information - std::cerr << "LOW THRES PROCESS DATA 0:" << this->template_exam_info_sptr->get_low_energy_thres(0) << "\n"; - std::cerr << "LOW THRES PROCESS DATA 1:" << this->template_exam_info_sptr->get_low_energy_thres(1) << "\n"; std::cerr << "number of energy windows:= "<< this->template_exam_info_sptr->get_num_energy_windows() << '\n'; if(this->template_exam_info_sptr->get_energy_window_pair().first!= -1 && @@ -344,7 +342,8 @@ set_up() error("ScatterSimulation: projection data info not set. Aborting."); if(!template_exam_info_sptr->has_energy_information()) - error("ScatterSimulation: template energy window information not set. Aborting."); + std::cerr << "DOES NOT HAVE ENERGY\n"; + // error("ScatterSimulation: template energy window information not set. Aborting."); if(is_null_ptr(activity_image_sptr)) error("ScatterSimulation: activity image not set. Aborting."); @@ -781,6 +780,8 @@ ScatterSimulation:: set_exam_info(const ExamInfo& arg) { this->template_exam_info_sptr = arg.create_shared_clone(); + std::cerr << "LOW THRES EX INFO 0:" << template_exam_info_sptr->get_low_energy_thres(0) << "\n"; + std::cerr << "LOW THRES EX INFO 1:" << template_exam_info_sptr->get_low_energy_thres(1) << "\n"; } Succeeded From 5461eb6f96af06217d03eb96cb1d89fa99943dfb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 15 Oct 2020 22:50:35 -0400 Subject: [PATCH 258/274] merged with brutal fix --- src/scatter_buildblock/ScatterSimulation.cxx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index b677e0a9de..4c7daf6065 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -342,8 +342,7 @@ set_up() error("ScatterSimulation: projection data info not set. Aborting."); if(!template_exam_info_sptr->has_energy_information()) - std::cerr << "DOES NOT HAVE ENERGY\n"; - // error("ScatterSimulation: template energy window information not set. Aborting."); + error("ScatterSimulation: template energy window information not set. Aborting."); if(is_null_ptr(activity_image_sptr)) error("ScatterSimulation: activity image not set. Aborting."); @@ -779,7 +778,13 @@ void ScatterSimulation:: set_exam_info(const ExamInfo& arg) { - this->template_exam_info_sptr = arg.create_shared_clone(); + this->template_exam_info_sptr = arg.create_shared_clone(); + + for (int i = 0; i < arg.get_num_energy_windows(); ++i) + { + this->template_exam_info_sptr->set_high_energy_thres(arg.get_high_energy_thres(i),i); + this->template_exam_info_sptr->set_low_energy_thres(arg.get_low_energy_thres(i),i); + } std::cerr << "LOW THRES EX INFO 0:" << template_exam_info_sptr->get_low_energy_thres(0) << "\n"; std::cerr << "LOW THRES EX INFO 1:" << template_exam_info_sptr->get_low_energy_thres(1) << "\n"; } From b7ffffd4d9be3e2c55da84f878ba709f80c395b9 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Thu, 15 Oct 2020 22:51:53 -0400 Subject: [PATCH 259/274] remove printing --- src/scatter_buildblock/ScatterSimulation.cxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 4c7daf6065..9203149b61 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -741,8 +741,6 @@ set_template_proj_data_info(const std::string& filename) shared_ptr template_proj_data_sptr(ProjData::read_from_file(this->template_proj_data_filename)); this->set_exam_info(template_proj_data_sptr->get_exam_info()); - std::cerr << "LOW THRES SET TEMP 0:" << template_proj_data_sptr->get_exam_info().get_low_energy_thres(0) << "\n"; - std::cerr << "LOW THRES SET TEMP 1:" << template_proj_data_sptr->get_exam_info().get_low_energy_thres(1) << "\n"; this->set_template_proj_data_info(*template_proj_data_sptr->get_proj_data_info_sptr()); } @@ -785,8 +783,6 @@ set_exam_info(const ExamInfo& arg) this->template_exam_info_sptr->set_high_energy_thres(arg.get_high_energy_thres(i),i); this->template_exam_info_sptr->set_low_energy_thres(arg.get_low_energy_thres(i),i); } - std::cerr << "LOW THRES EX INFO 0:" << template_exam_info_sptr->get_low_energy_thres(0) << "\n"; - std::cerr << "LOW THRES EX INFO 1:" << template_exam_info_sptr->get_low_energy_thres(1) << "\n"; } Succeeded From 0bc485f966541f9e88d7087db365c0c209b3f191 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 16 Oct 2020 11:23:10 -0400 Subject: [PATCH 260/274] cleaned exam info --- src/IO/InterfileHeader.cxx | 2 +- src/include/stir/ExamInfo.h | 23 +++++++++++++++-------- src/include/stir/ExamInfo.inl | 25 +++---------------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/IO/InterfileHeader.cxx b/src/IO/InterfileHeader.cxx index 46942d30cd..6244b58e5c 100644 --- a/src/IO/InterfileHeader.cxx +++ b/src/IO/InterfileHeader.cxx @@ -391,7 +391,7 @@ bool InterfileHeader::post_processing() if (energy_window_pair[1] > num_energy_windows) error("The selected window %d exceeds the number of energy windows %d.\n",energy_window_pair[1],num_energy_windows); - exam_info_sptr->set_energy_window_pair(energy_window_pair,num_energy_windows); + exam_info_sptr->set_energy_window_pair(energy_window_pair); } //set the high and low energy window threshold diff --git a/src/include/stir/ExamInfo.h b/src/include/stir/ExamInfo.h index 113ba48e01..ddb120591c 100644 --- a/src/include/stir/ExamInfo.h +++ b/src/include/stir/ExamInfo.h @@ -63,8 +63,8 @@ public : low_energy_thres.resize(1); up_energy_thres.resize(1); en_win_pair.resize(2); - low_energy_thres[0]=1.F; - up_energy_thres[0]=1.F; + low_energy_thres[0]=-1.F; + up_energy_thres[0]=-1.F; en_win_pair[0]=1.F; en_win_pair[1]=1.F; @@ -106,17 +106,18 @@ public : //! Set the high energy boundary inline void set_high_energy_thres(float new_val,int en_window = 0); //! Set the low energy boundary as a vector (currently only used in listmode code) - inline void set_low_energy_thres_vect(std::vector new_val,bool switch_energy = false); + inline void set_low_energy_thres_vect(std::vector new_val); //! Set the high energy boundary as a vector (currently only used in listmode code) - inline void set_high_energy_thres_vect(std::vector new_val,bool switch_energy = false); + inline void set_high_energy_thres_vect(std::vector new_val); //! Set the number of energy windows inline void set_num_energy_windows(int n_win); //! Set the energy window pair - inline void set_energy_window_pair(std::vector val,int n_win); + inline void set_energy_window_pair(std::vector val); //@} inline bool has_energy_information() const { + //TODO ADD LOOP: for (int i=0; i< num_windows; i++) return (low_energy_thres[0] > 0.f)&&(up_energy_thres[0] > 0.f); } @@ -141,15 +142,21 @@ public : std::string parameter_info() const; private: - //! + //! + //! \brief num_windows + //! \author Ludovica Brusaferri + //! \details This is the value of the number of enegry windows + //! This parameter was initially introduced for scatter simulation. + //! If scatter simulation is not needed, can default to 1 + int num_windows; + + //! //! \brief low_energy_thres //! \author Nikos Efthimiou //! \details This is the value of low energy threshold of the energy window. //! The units are keV //! This parameter was initially introduced for scatter simulation. //! If scatter simulation is not needed, can default to -1 - - int num_windows; std::vector low_energy_thres; //! diff --git a/src/include/stir/ExamInfo.inl b/src/include/stir/ExamInfo.inl index f666ee699b..b67ef39f83 100644 --- a/src/include/stir/ExamInfo.inl +++ b/src/include/stir/ExamInfo.inl @@ -53,30 +53,15 @@ ExamInfo::set_high_energy_thres(float new_val,int en_window) } void -ExamInfo::set_low_energy_thres_vect(std::vector new_val, bool switch_energy) +ExamInfo::set_low_energy_thres_vect(std::vector new_val) { low_energy_thres = new_val; - //TODO extend to the case of more than two - //Decrescent ordering - if (switch_energy) - { - low_energy_thres[1] = new_val[0]; - low_energy_thres[0] = new_val[1]; - } - } void -ExamInfo::set_high_energy_thres_vect(std::vector new_val, bool switch_energy) +ExamInfo::set_high_energy_thres_vect(std::vector new_val) { up_energy_thres = new_val; - //TODO extend to the case of more than two - //Decrescent ordering - if (switch_energy) - { - up_energy_thres[1] = new_val[0]; - up_energy_thres[0] = new_val[1]; - } } void @@ -88,13 +73,9 @@ ExamInfo::set_num_energy_windows(int n_win) void -ExamInfo::set_energy_window_pair(std::vector val,int n_win) +ExamInfo::set_energy_window_pair(std::vector val) { - - - en_win_pair=val; - } From 14385372f26ac2af8143f39f43d7d13110ed065c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 17 Oct 2020 21:46:56 -0400 Subject: [PATCH 261/274] checkout listmode --- src/IO/InputStreamFromROOTFile.cxx | 23 ++--- ...putStreamFromROOTFileForCylindricalPET.cxx | 25 +++--- src/IO/InputStreamFromROOTFileForECATPET.cxx | 23 ++--- src/include/stir/IO/InputStreamFromROOTFile.h | 25 ++---- .../stir/IO/InputStreamFromROOTFile.inl | 36 ++------ ...InputStreamFromROOTFileForCylindricalPET.h | 5 +- .../IO/InputStreamFromROOTFileForECATPET.h | 4 - src/include/stir/listmode/CListRecord.h | 3 - .../stir/listmode/CListRecordECAT8_32bit.h | 14 +-- .../stir/listmode/CListRecordECAT962.h | 20 ----- .../stir/listmode/CListRecordECAT966.h | 24 +----- src/include/stir/listmode/CListRecordROOT.h | 65 +------------- src/include/stir/listmode/CListRecordROOT.inl | 3 - src/include/stir/listmode/CListRecordSAFIR.h | 7 -- src/include/stir/listmode/LmToProjData.h | 1 - src/listmode_buildblock/CListModeDataROOT.cxx | 4 - src/listmode_buildblock/LmToProjData.cxx | 85 +++++++------------ .../LmToProjDataBootstrap.cxx | 2 +- 18 files changed, 79 insertions(+), 290 deletions(-) diff --git a/src/IO/InputStreamFromROOTFile.cxx b/src/IO/InputStreamFromROOTFile.cxx index 1dd59b7261..f74a159d0c 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -41,13 +41,11 @@ InputStreamFromROOTFile:: InputStreamFromROOTFile(std::string filename, std::string chain_name, bool exclude_scattered, bool exclude_randoms, - int maximum_order_of_scatter, - float low_energy_window_1, float up_energy_window_1, - float low_energy_window_2, float up_energy_window_2, + float low_energy_window, float up_energy_window, int offset_dets) : filename(filename), chain_name(chain_name), - exclude_scattered(exclude_scattered), exclude_randoms(exclude_randoms), maximum_order_of_scatter(maximum_order_of_scatter), - low_energy_window_1(low_energy_window_1), up_energy_window_1(up_energy_window_1),low_energy_window_2(low_energy_window_2), up_energy_window_2(up_energy_window_2), offset_dets(offset_dets) + exclude_scattered(exclude_scattered), exclude_randoms(exclude_randoms), + low_energy_window(low_energy_window), up_energy_window(up_energy_window), offset_dets(offset_dets) { set_defaults(); reset(); @@ -59,12 +57,9 @@ InputStreamFromROOTFile::set_defaults() starting_stream_position = 0; singles_readout_depth = -1; exclude_scattered = false; - maximum_order_of_scatter = 0; exclude_randoms = false; - low_energy_window_1 = 0.f; - up_energy_window_1 = 1000.f; - low_energy_window_2 = 0.f; - up_energy_window_2 = 1000.f; + low_energy_window = 0.f; + up_energy_window = 1000.f; read_optional_root_fields=false; } @@ -75,14 +70,10 @@ InputStreamFromROOTFile::initialise_keymap() this->parser.add_key("Singles readout depth", &this->singles_readout_depth); this->parser.add_key("name of input TChain", &this->chain_name); this->parser.add_key("exclude scattered events", &this->exclude_scattered); - this->parser.add_key("maximum order of scatter", &this->maximum_order_of_scatter); this->parser.add_key("exclude random events", &this->exclude_randoms); this->parser.add_key("offset (num of detectors)", &this->offset_dets); - this->parser.add_key("number of energy windows", &this->num_en_windows); - this->parser.add_key("low energy window 1 (MeV)", &this->low_energy_window_1); - this->parser.add_key("upper energy window 1 (MeV)", &this->up_energy_window_1); - this->parser.add_key("low energy window 2 (MeV)", &this->low_energy_window_2); - this->parser.add_key("upper energy window 2 (MeV)", &this->up_energy_window_2); + this->parser.add_key("low energy window (keV)", &this->low_energy_window); + this->parser.add_key("upper energy window (keV)", &this->up_energy_window); this->parser.add_key("read optional ROOT fields", &this->read_optional_root_fields); } diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index f680f1de80..1e233791e0 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -38,9 +38,8 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, int submodule_repeater_x, int submodule_repeater_y, int submodule_repeater_z, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, - bool _exclude_scattered, bool _exclude_randoms, int _maximum_order_of_scatter, - float _low_energy_window_1, float _up_energy_window_1, - float _low_energy_window_2, float _up_energy_window_2, + bool _exclude_scattered, bool _exclude_randoms, + float _low_energy_window, float _up_energy_window, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), @@ -54,11 +53,8 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - maximum_order_of_scatter = _maximum_order_of_scatter; - low_energy_window_1 = _low_energy_window_1; - up_energy_window_1 = _up_energy_window_1; - low_energy_window_2 = _low_energy_window_2; - up_energy_window_2 = _up_energy_window_2; + low_energy_window = _low_energy_window; + up_energy_window = _up_energy_window; offset_dets = _offset_dets; half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; @@ -82,15 +78,16 @@ get_next_record(CListRecordROOT& record) current_position ++ ; - if ( (this->comptonphantom1 > maximum_order_of_scatter || this->comptonphantom2 >this->maximum_order_of_scatter) && this->exclude_scattered ) + if ( (this->comptonphantom1 > 0 || this->comptonphantom2 > 0) && this->exclude_scattered ) continue; if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) continue; - if (this->energy1 < this->low_energy_window_1 || - this->energy1 > this->up_energy_window_1 || - this->energy2 < this->low_energy_window_2|| - this->energy2 > this->up_energy_window_2) + if (this->energy1 < this->low_energy_window || + this->energy1 > this->up_energy_window || + this->energy2 < this->low_energy_window || + this->energy2 > this->up_energy_window) continue; + break; } @@ -125,7 +122,7 @@ get_next_record(CListRecordROOT& record) record.init_from_data(ring1, ring2, crystal1, crystal2, time1, time2, - eventID1, eventID2,energy1,energy2); + eventID1, eventID2); } std::string diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 272b8ec49b..937f80b58a 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -37,9 +37,6 @@ InputStreamFromROOTFileForECATPET(std::string _filename, std::string _chain_name, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int block_repeater_y, int block_repeater_z, - bool _exclude_scattered, bool _exclude_randoms, int _maximum_order_of_scatter, - float _low_energy_window_1, float _up_energy_window_1, - float _low_energy_window_2, float _up_energy_window_2, bool _exclude_scattered, bool _exclude_randoms, float _low_energy_window, float _up_energy_window, int _offset_dets): @@ -53,11 +50,8 @@ InputStreamFromROOTFileForECATPET(std::string _filename, chain_name = _chain_name; exclude_scattered = _exclude_scattered; exclude_randoms = _exclude_randoms; - maximum_order_of_scatter = _maximum_order_of_scatter; - low_energy_window_1 = _low_energy_window_1; - up_energy_window_1 = _up_energy_window_1; - low_energy_window_2 = _low_energy_window_2; - up_energy_window_2 = _up_energy_window_2; + low_energy_window = _low_energy_window; + up_energy_window = _up_energy_window; offset_dets = _offset_dets; half_block = crystal_repeater_y / 2 - 1; @@ -80,15 +74,16 @@ get_next_record(CListRecordROOT& record) current_position ++ ; - if ( (comptonphantom1 > maximum_order_of_scatter || comptonphantom2 > maximum_order_of_scatter) && exclude_scattered ) + if ( (comptonphantom1 > 0 || comptonphantom2 > 0) && exclude_scattered ) continue; if ( eventID1 != eventID2 && exclude_randoms ) continue; - if (this->energy1 < this->low_energy_window_1 || - this->energy1 > this->up_energy_window_1 || - this->energy2 < this->low_energy_window_2|| - this->energy2 > this->up_energy_window_2) + if (energy1 < low_energy_window || + energy1 > up_energy_window || + energy2 < low_energy_window || + energy2 > up_energy_window) continue; + break; } @@ -117,7 +112,7 @@ get_next_record(CListRecordROOT& record) record.init_from_data(ring1, ring2, crystal1, crystal2, time1, time2, - eventID1, eventID2,energy1,energy2); + eventID1, eventID2); } std::string diff --git a/src/include/stir/IO/InputStreamFromROOTFile.h b/src/include/stir/IO/InputStreamFromROOTFile.h index a57e6d21f3..bf95dfc316 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.h +++ b/src/include/stir/IO/InputStreamFromROOTFile.h @@ -80,9 +80,8 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! constructor InputStreamFromROOTFile(std::string filename, std::string chain_name, - bool exclude_scattered, bool exclude_randoms,int maximum_order_of_scatter, - float low_energy_window_1, float up_energy_window_1, - float low_energy_window_2, float up_energy_window_2, + bool exclude_scattered, bool exclude_randoms, + float low_energy_window, float up_energy_window, int offset_dets); @@ -131,12 +130,10 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile virtual int get_num_trans_crystals_per_singles_unit() const = 0; //! Lower energy threshold - inline std::vector get_low_energy_thres_in_keV() const; + inline float get_low_energy_thres() const; //! Upper energy threshold - inline std::vector get_up_energy_thres_in_keV() const; + inline float get_up_energy_thres() const; - //! Upper number of energy windows - inline int get_number_of_energy_windows() const; //! Set singles_readout_depth inline void set_singles_readout_depth(int); @@ -148,8 +145,6 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile inline void set_exclude_random_events(bool); - inline void set_maximum_order_of_scatter(int); - inline void set_detectors_offset(int); inline void set_low_energy_window(float); @@ -201,20 +196,12 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! Skip scattered events (comptonphantom1 > 0 && comptonphantom2 > 0) bool exclude_scattered; - //! Scatter order to skip; - bool maximum_order_of_scatter; //! Skip random events (eventID1 != eventID2) bool exclude_randoms; //! Lower energy threshold - float low_energy_window_1; - //! Upper energy threshold - float up_energy_window_1; - //! Lower energy threshold - float low_energy_window_2; + float low_energy_window; //! Upper energy threshold - float up_energy_window_2; - - int num_en_windows; + float up_energy_window; //! This value will apply a rotation on the detectors' id in the same ring. int offset_dets; //!For the singles_readout_depth from GATE's online documentation: diff --git a/src/include/stir/IO/InputStreamFromROOTFile.inl b/src/include/stir/IO/InputStreamFromROOTFile.inl index b63cdfc498..97d5a44486 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.inl +++ b/src/include/stir/IO/InputStreamFromROOTFile.inl @@ -79,37 +79,20 @@ set_saved_get_positions(const std::vector &poss) saved_get_positions = poss; } -int +float InputStreamFromROOTFile:: -get_number_of_energy_windows() const +get_low_energy_thres() const { - return num_en_windows; -} - -std::vector -InputStreamFromROOTFile:: -get_low_energy_thres_in_keV() const -{ - std::vector low_energy_window; - low_energy_window.resize(2); - low_energy_window[0]=1e3*low_energy_window_1; - low_energy_window[1]=1e3*low_energy_window_2; return low_energy_window; } -std::vector +float InputStreamFromROOTFile:: -get_up_energy_thres_in_keV() const +get_up_energy_thres() const { - std::vector up_energy_window; - up_energy_window.resize(2); - up_energy_window[0]=1e3*up_energy_window_1; - up_energy_window[1]=1e3*up_energy_window_2; return up_energy_window; } - - std::string InputStreamFromROOTFile:: get_ROOT_filename() const @@ -141,13 +124,6 @@ InputStreamFromROOTFile::set_exclude_scattered_events(bool val) exclude_scattered = val; } -void -InputStreamFromROOTFile::set_maximum_order_of_scatter(int val) -{ - maximum_order_of_scatter= val; -} - - void InputStreamFromROOTFile::set_exclude_random_events(bool val) { @@ -163,13 +139,13 @@ InputStreamFromROOTFile::set_detectors_offset(int val) void InputStreamFromROOTFile::set_low_energy_window(float val) { - low_energy_window_1= val; + low_energy_window = val; } void InputStreamFromROOTFile::set_upper_energy_window(float val) { - up_energy_window_1 = val; + up_energy_window = val; } void diff --git a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h index 2a2488c886..0ac72fdc9c 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h @@ -100,9 +100,8 @@ class InputStreamFromROOTFileForCylindricalPET : public int submodule_repeater_x, int submodule_repeater_y, int submodule_repeater_z, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, - bool exclude_scattered, bool exclude_randoms, int maximum_order_of_scatter, - float low_energy_window_1, float up_energy_window_1, - float low_energy_window_2, float up_energy_window_2, + bool exclude_scattered, bool exclude_randoms, + float low_energy_window, float up_energy_window, int offset_dets); virtual ~InputStreamFromROOTFileForCylindricalPET() {} diff --git a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h index f17197b8de..e4700b5450 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h @@ -93,10 +93,6 @@ class InputStreamFromROOTFileForECATPET : public InputStreamFromROOTFileForECATPET(std::string filename, std::string chain_name, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, - int blocks_repeater_y,int blocks_repeater_z, - bool exclude_scattered, bool exclude_randoms,int maximum_order_of_scatter, - float low_energy_window_1, float up_energy_window_1, - float low_energy_window_2, float up_energy_window_2, int blocks_repeater_y, int blocks_repeater_z, bool exclude_scattered, bool exclude_randoms, float low_energy_window, float up_energy_window, diff --git a/src/include/stir/listmode/CListRecord.h b/src/include/stir/listmode/CListRecord.h index 6ef221fb1a..6ab64f58f6 100644 --- a/src/include/stir/listmode/CListRecord.h +++ b/src/include/stir/listmode/CListRecord.h @@ -55,9 +55,6 @@ class CListEvent : public ListEvent { public: - virtual bool is_swapped() const = 0; - - //! Changes the event from prompt to delayed or vice versa /*! Default implementation just returns Succeeded::no. */ virtual diff --git a/src/include/stir/listmode/CListRecordECAT8_32bit.h b/src/include/stir/listmode/CListRecordECAT8_32bit.h index 7713445537..55e17234cd 100644 --- a/src/include/stir/listmode/CListRecordECAT8_32bit.h +++ b/src/include/stir/listmode/CListRecordECAT8_32bit.h @@ -100,7 +100,6 @@ class CListEventECAT8_32bit : public CListEventCylindricalScannerWithDiscreteDet return Succeeded::yes; } inline bool is_prompt() const { return this->data.delayed == 1; } - inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } inline Succeeded set_prompt(const bool prompt = true) { if (prompt) this->data.delayed=1; else this->data.delayed=0; return Succeeded::yes; } @@ -186,8 +185,6 @@ class CListTimeECAT8_32bit : public ListTime return Succeeded::yes; } - - private: BOOST_STATIC_ASSERT(sizeof(CListTimeDataECAT8_32bit)==4); union @@ -197,12 +194,6 @@ class CListTimeECAT8_32bit : public ListTime }; }; - - -//! A class for storing and using an energy 'event' from a listmode file from the ECAT 8_32bit scanner -/*! \ingroup listmode - */ - //! A class for a general element of a listmode file for a Siemens scanner using the ECAT8 32bit format. /*! \ingroup listmode We currently only support coincidence events and a timing flag. @@ -225,8 +216,6 @@ class CListTimeECAT8_32bit : public ListTime */ bool is_event() const { return this->any_data.is_event(); } - - virtual CListEventECAT8_32bit& event() { return this->event_data; } virtual const CListEventECAT8_32bit& event() const @@ -236,7 +225,6 @@ class CListTimeECAT8_32bit : public ListTime virtual const CListTimeECAT8_32bit& time() const { return this->time_data; } - bool operator==(const CListRecord& e2) const { return dynamic_cast(&e2) != 0 && @@ -275,7 +263,7 @@ class CListTimeECAT8_32bit : public ListTime private: CListEventECAT8_32bit event_data; - CListTimeECAT8_32bit time_data; + CListTimeECAT8_32bit time_data; CListDataAnyECAT8_32bit any_data; boost::int32_t raw; // this raw field isn't strictly necessary, get rid of it? diff --git a/src/include/stir/listmode/CListRecordECAT962.h b/src/include/stir/listmode/CListRecordECAT962.h index 19bb1f71c6..c3985caa4b 100644 --- a/src/include/stir/listmode/CListRecordECAT962.h +++ b/src/include/stir/listmode/CListRecordECAT962.h @@ -66,7 +66,6 @@ class CListEventDataECAT962 { public: inline bool is_prompt() const { return random == 0; } - inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } inline Succeeded set_prompt(const bool prompt = true) { if (prompt) random=0; else random=1; return Succeeded::yes; } @@ -184,16 +183,6 @@ class CListTimeDataECAT962 #endif }; - -//! A class for storing and using an energy 'event' from a listmode file -/*! \ingroup listmode - */ -class CListEnergyDataECAT962 -{ - public: -}; - - //! A class for a general element of a listmode file /*! \ingroup listmode For the 962 it's either a coincidence event, or a timing flag.*/ @@ -211,8 +200,6 @@ class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, p bool is_time() const { return time_data.type == 1U; } - bool is_energy() const - { return true; } bool is_gating_input() const { return this->is_time(); } bool is_event() const @@ -246,12 +233,6 @@ class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, p inline Succeeded set_gating(unsigned int g) { return time_data.set_gating(g); } - // energy - inline double get_energyA_in_keV() const - { return 0.F; } - inline double get_energyB_in_keV() const - { return 0.F; } - // event inline bool is_prompt() const { return event_data.is_prompt(); } inline Succeeded set_prompt(const bool prompt = true) @@ -279,7 +260,6 @@ class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, p union { CListEventDataECAT962 event_data; CListTimeDataECAT962 time_data; - CListEnergyDataECAT962 energy_data; boost::int32_t raw; }; BOOST_STATIC_ASSERT(sizeof(boost::int32_t)==4); diff --git a/src/include/stir/listmode/CListRecordECAT966.h b/src/include/stir/listmode/CListRecordECAT966.h index 3f3f854f77..52078bc713 100644 --- a/src/include/stir/listmode/CListRecordECAT966.h +++ b/src/include/stir/listmode/CListRecordECAT966.h @@ -130,7 +130,6 @@ class CListEventECAT966 : public CListEventCylindricalScannerWithViewTangRingRin return Succeeded::yes; } inline bool is_prompt() const { return this->data.random == 0; } - inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } inline Succeeded set_prompt(const bool prompt = true) { if (prompt) this->data.random=0; else this->data.random=1; return Succeeded::yes; } @@ -201,21 +200,6 @@ class CListTimeECAT966 : public ListTime, public ListGatingInput }; }; - -//! A class for storing and using a energy'event' from a listmode file from the ECAT 966 scanner -/*! \ingroup listmode - */ -class CListEnergyECAT966 : public CListEnergy -{ - public: - bool is_energy() const - {return true; } - inline double get_energyA_in_keV() const - { return 0.F; } - inline double get_energyB_in_keV() const - { return 0.F; } -}; - //! A class for a general element of a listmode file /*! \ingroup listmode For the 966 it's either a coincidence event, or a timing flag.*/ @@ -236,13 +220,8 @@ class CListRecordECAT966 : public CListRecordWithGatingInput { return this->event_data; } virtual CListTimeECAT966& time() { return this->time_data; } - virtual const CListTimeECAT966& time() const + virtual const CListTimeECAT966& time() const { return this->time_data; } - virtual CListEnergyECAT966& energy() - { return this->energy_data; } - virtual const CListEnergyECAT966& energy() const - { return this->energy_data; } - virtual CListTimeECAT966& gating_input() { return this->time_data; } virtual const CListTimeECAT966& gating_input() const @@ -281,7 +260,6 @@ class CListRecordECAT966 : public CListRecordWithGatingInput private: CListEventECAT966 event_data; CListTimeECAT966 time_data; - CListEnergyECAT966 energy_data; boost::int32_t raw; }; diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index f2746d15c7..afd11ec401 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -125,48 +125,6 @@ class CListTimeROOT : public ListTime //! \brief timeB //! \details The detection time of the second of the two photons double timeB; - - -}; - -//! A class for storing and using an energy 'event' from a listmode file -/*! \ingroup listmode - */ -class CListEnergyROOT : public CListEnergy -{ -public: - - void init_energy_from_data(double energy1, double energy2) - { - energyA = energy1; - energyB = energy2; - } - - //! Returns always true - bool is_energy() const - { return true; } - //! Get the detection energy of the first photon - //! in keV - inline double get_energyA_in_keV() const - { return 1e3*energyA; } - //! Get the detection energy of the second photon - //! in keV - inline double get_energyB_in_keV() const - { return 1e3*energyB; } - -private: - - //! - //! \brief energyA - //! \details The detected energy of the first of the two photons, in MeV - double energyA; - - //! - //! \brief energyB - //! \details The detected energy of the second of the two photons, in MeV - double energyB; - - }; //! A class for a general element of a listmode file for a Siemens scanner using the ROOT files @@ -178,8 +136,6 @@ class CListRecordROOT : public CListRecord // currently no gating yet //! Returns always true bool inline is_event() const; //! Returns always true - bool inline is_energy() const; - //! Returns always true bool inline is_full_event() const; virtual CListEventROOT& event() @@ -202,17 +158,6 @@ class CListRecordROOT : public CListRecord // currently no gating yet return this->time_data; } - virtual CListEnergyROOT& energy() - { - return this->energy_data; - } - - virtual const CListEnergyROOT& energy() const - { - return this->energy_data; - } - - bool operator==(const CListRecord& e2) const { return dynamic_cast(&e2) != 0 && @@ -229,19 +174,16 @@ class CListRecordROOT : public CListRecord // currently no gating yet const int& crystal1, const int& crystal2, double time1, double time2, - const int& event1, const int& event2, - double energy1 = 0.511F, double energy2 = 0.511F) + const int& event1, const int& event2) { /// \warning ROOT data are time and event at the same time. this->event_data.init_from_data(ring1, ring2, crystal1, crystal2); - //std::cout << "I m not swapped" << std::endl - this->time_data.init_from_data(time1,time2); + this->time_data.init_from_data( + time1,time2); - this->energy_data.init_energy_from_data(energy1,energy2); -// // We can make a singature raw based on the two events IDs. // It is pretty unique. raw[0] = event1; @@ -253,7 +195,6 @@ class CListRecordROOT : public CListRecord // currently no gating yet private: CListEventROOT event_data; CListTimeROOT time_data; - CListEnergyROOT energy_data; boost::int32_t raw[2]; // this raw field isn't strictly necessary, get rid of it? }; diff --git a/src/include/stir/listmode/CListRecordROOT.inl b/src/include/stir/listmode/CListRecordROOT.inl index 676af76c23..26270593c4 100644 --- a/src/include/stir/listmode/CListRecordROOT.inl +++ b/src/include/stir/listmode/CListRecordROOT.inl @@ -33,9 +33,6 @@ bool CListRecordROOT::is_time() const bool CListRecordROOT::is_event() const { return true; } -bool CListRecordROOT::is_energy() const -{ return true; } - bool CListRecordROOT::is_full_event() const { return true; } diff --git a/src/include/stir/listmode/CListRecordSAFIR.h b/src/include/stir/listmode/CListRecordSAFIR.h index a753ecaa4d..4338124ea2 100644 --- a/src/include/stir/listmode/CListRecordSAFIR.h +++ b/src/include/stir/listmode/CListRecordSAFIR.h @@ -81,7 +81,6 @@ class CListEventSAFIR : public CListEvent //! Returns 0 if event is prompt and 1 if random/delayed inline bool is_prompt() const { return !(static_cast(this)->is_prompt()); } - inline bool is_swapped() const { throw "is_swapped function non implemented in this class"; } //! Function to set map for detector indices to coordinates. inline void set_map( shared_ptr new_map ) { map = new_map; } @@ -165,8 +164,6 @@ class CListTimeDataSAFIR #endif }; - - //! Class for general record, containing a union of data, time and raw record and providing access to certain elements. class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventSAFIR { @@ -187,7 +184,6 @@ class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventS virtual bool is_event() const { return time_data.type == 0; } - virtual CListEvent& event() { return *this; } @@ -206,8 +202,6 @@ class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventS virtual const ListTime& time() const { return *this; } - - virtual bool operator==(const CListRecord& e2) const { return dynamic_cast(&e2) != 0 && @@ -220,7 +214,6 @@ class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventS inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { return time_data.set_time_in_millisecs(time_in_millisecs); } - inline bool is_prompt() const { return !(event_data.isRandom); } Succeeded diff --git a/src/include/stir/listmode/LmToProjData.h b/src/include/stir/listmode/LmToProjData.h index 322bfac5cb..7f2cc7bfdd 100644 --- a/src/include/stir/listmode/LmToProjData.h +++ b/src/include/stir/listmode/LmToProjData.h @@ -237,7 +237,6 @@ class LmToProjData : public LmToProjDataAbstract bool interactive; shared_ptr template_proj_data_info_ptr; - shared_ptr template_proj_data_ptr; //! This will be used for pre-normalisation shared_ptr normalisation_ptr; //! This will be used for post-normalisation diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 8f74f825d2..dd5e5b45c8 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -252,16 +252,12 @@ check_scanner_match_geometry(std::string& ret, const shared_ptr& scanne if (scanner_sptr->get_num_rings() != root_file_sptr->get_num_rings()) { stream << "the number of rings, "; - std::cout << "rings STIR:" << scanner_sptr->get_num_rings() << "\n"; - std::cout << "rings GATE:" << root_file_sptr->get_num_rings() << "\n"; ok = false; } if (scanner_sptr->get_num_detectors_per_ring() != root_file_sptr->get_num_dets_per_ring()) { stream << "the number of detector per ring, "; - std::cout << "n det STIR:" << scanner_sptr->get_num_detectors_per_ring() << "\n"; - std::cout << "n det GATE:" << root_file_sptr->get_num_dets_per_ring() << "\n"; ok = false; } diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 80f67c1d3f..91fb7bbfd0 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -213,7 +213,7 @@ post_processing() warning("You have to specify template_projdata\n"); return true; } - template_proj_data_ptr = + shared_ptr template_proj_data_ptr = ProjData::read_from_file(template_proj_data_name); template_proj_data_info_ptr.reset(template_proj_data_ptr->get_proj_data_info_sptr()->clone()); @@ -427,8 +427,8 @@ get_bin_from_event(Bin& bin, const ListEvent& event) const const float bin_value = 1/bin_efficiency; // TODO wasteful: we decode the event twice. replace by something like // template_proj_data_info_ptr->get_bin_from_uncompressed(bin, uncompressed_bin); - event.get_bin(bin, *template_proj_data_info_ptr);//, energy_window_pair); - + event.get_bin(bin, *template_proj_data_info_ptr); + if (bin.get_bin_value()>0) { bin.set_bin_value(bin_value); @@ -437,7 +437,7 @@ get_bin_from_event(Bin& bin, const ListEvent& event) const } else { - event.get_bin(bin, *template_proj_data_info_ptr);//, energy_window_pair); + event.get_bin(bin, *template_proj_data_info_ptr); } } @@ -528,25 +528,8 @@ process_data() // few coincidence events (as happens with ECAT scanners) current_time = 0; - int num_en_windows = template_proj_data_ptr->get_exam_info().get_num_energy_windows(); - std::vector high_en_thres(num_en_windows); - std::vector low_en_thres(num_en_windows); - std::vector energy_window_pair_vec(2); - // const std::pair energy_window_pair = template_proj_data_ptr->get_exam_info().get_energy_window_pair(); - - energy_window_pair_vec[0]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().first; - energy_window_pair_vec[1]=template_proj_data_ptr->get_exam_info().get_energy_window_pair().second; - - for (int i = 0; i< num_en_windows; ++i) - { - low_en_thres[i] = template_proj_data_ptr->get_exam_info().get_low_energy_thres(i); - high_en_thres[i] = template_proj_data_ptr->get_exam_info().get_high_energy_thres(i); - } - - double time_of_last_stored_event = 0; long num_stored_events = 0; - VectorWithOffset segments (template_proj_data_info_ptr->get_min_segment_num(), template_proj_data_info_ptr->get_max_segment_num()); @@ -585,11 +568,11 @@ process_data() proj_data_sptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); - } long num_prompts_in_frame = 0; long num_delayeds_in_frame = 0; + const double start_time = frame_defs.get_start_time(current_frame_num); const double end_time = frame_defs.get_end_time(current_frame_num); @@ -660,20 +643,18 @@ process_data() assert(current_time>=start_time); process_new_time_event(record.time()); } - // note: could do "else if" here if we would be sure that // a record can never be both timing and coincidence event // and there might be a scanner around that has them both combined. - if (record.is_event()) + if (record.is_event()) { - assert(start_time <= current_time); Bin bin; // set value in case the event decoder doesn't touch it // otherwise it would be 0 and all events will be ignored bin.set_bin_value(1); - get_bin_from_event(bin, record.event()); - + get_bin_from_event(bin, record.event()); + // check if it's inside the range we want to store if (bin.get_bin_value()>0 && bin.tangential_pos_num()>= proj_data_sptr->get_min_tangential_pos_num() @@ -696,32 +677,30 @@ process_data() if (!do_time_frame) more_events-= event_increment; - - // now check if we have its segment in memory - if (bin.segment_num() >= start_segment_index && bin.segment_num()<=end_segment_index) - - { - do_post_normalisation(bin); - - num_stored_events += event_increment; - if (record.event().is_prompt()) - ++num_prompts_in_frame; - else - ++num_delayeds_in_frame; - - if (num_stored_events%500000L==0) cout << "\r" << num_stored_events << " events stored" << flush; - - if (interactive) - printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g stored with incr %d \n", - bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), - current_time, event_increment); - else - (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += - bin.get_bin_value() * - event_increment; - } - - } + + // now check if we have its segment in memory + if (bin.segment_num() >= start_segment_index && bin.segment_num()<=end_segment_index) + { + do_post_normalisation(bin); + + num_stored_events += event_increment; + if (record.event().is_prompt()) + ++num_prompts_in_frame; + else + ++num_delayeds_in_frame; + + if (num_stored_events%500000L==0) cout << "\r" << num_stored_events << " events stored" << flush; + + if (interactive) + printf("Seg %4d view %4d ax_pos %4d tang_pos %4d time %8g stored with incr %d \n", + bin.segment_num(), bin.view_num(), bin.axial_pos_num(), bin.tangential_pos_num(), + current_time, event_increment); + else + (*segments[bin.segment_num()])[bin.view_num()][bin.axial_pos_num()][bin.tangential_pos_num()] += + bin.get_bin_value() * + event_increment; + } + } else // event is rejected for some reason { if (interactive) diff --git a/src/listmode_buildblock/LmToProjDataBootstrap.cxx b/src/listmode_buildblock/LmToProjDataBootstrap.cxx index 1108485546..e660cd7ceb 100644 --- a/src/listmode_buildblock/LmToProjDataBootstrap.cxx +++ b/src/listmode_buildblock/LmToProjDataBootstrap.cxx @@ -172,7 +172,7 @@ start_new_time_frame(const unsigned int new_frame_num) // set value in case the event decoder doesn't touch it // otherwise it would be 0 and all events will be ignored bin.set_bin_value(1); - base_type::get_bin_from_event(bin, record.event()); + base_type::get_bin_from_event(bin, record.event()); // check if it's inside the range we want to store if (bin.get_bin_value()>0 && bin.tangential_pos_num()>= this->template_proj_data_info_ptr->get_min_tangential_pos_num() From 51be2aaabe5631ae022cd3493b4fa8f652896185 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 19 Oct 2020 13:47:56 -0400 Subject: [PATCH 262/274] can read energy info --- ...putStreamFromROOTFileForCylindricalPET.cxx | 3 +- src/IO/InputStreamFromROOTFileForECATPET.cxx | 3 +- src/include/stir/listmode/CListModeDataROOT.h | 1 + .../stir/listmode/CListRecordECAT8_32bit.h | 23 +++++++- .../stir/listmode/CListRecordECAT962.h | 24 +++++++- .../stir/listmode/CListRecordECAT966.h | 22 ++++++++ src/include/stir/listmode/CListRecordGEHDF5.h | 21 ++++++- src/include/stir/listmode/CListRecordROOT.h | 56 ++++++++++++++++++- src/include/stir/listmode/CListRecordROOT.inl | 3 + src/include/stir/listmode/CListRecordSAFIR.h | 25 ++++++++- src/include/stir/listmode/ListEnergy.h | 56 +++++++++++++++++++ src/include/stir/listmode/ListRecord.h | 7 ++- src/include/stir/listmode/LmToProjData.h | 1 + src/include/stir/listmode/SPECTListRecord.h | 6 +- .../listmode/CListRecordLMF.h | 18 +++++- src/listmode_buildblock/LmToProjData.cxx | 2 + 16 files changed, 260 insertions(+), 11 deletions(-) create mode 100644 src/include/stir/listmode/ListEnergy.h diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 1e233791e0..160b182866 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -122,7 +122,8 @@ get_next_record(CListRecordROOT& record) record.init_from_data(ring1, ring2, crystal1, crystal2, time1, time2, - eventID1, eventID2); + eventID1, eventID2, + energy1,energy2); } std::string diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index 937f80b58a..e8faa30729 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -112,7 +112,8 @@ get_next_record(CListRecordROOT& record) record.init_from_data(ring1, ring2, crystal1, crystal2, time1, time2, - eventID1, eventID2); + eventID1, eventID2, + energy1,energy2); } std::string diff --git a/src/include/stir/listmode/CListModeDataROOT.h b/src/include/stir/listmode/CListModeDataROOT.h index 1481de0413..18afcf6753 100644 --- a/src/include/stir/listmode/CListModeDataROOT.h +++ b/src/include/stir/listmode/CListModeDataROOT.h @@ -29,6 +29,7 @@ #define __stir_listmode_CListModeDataROOT_H__ #include "stir/listmode/CListModeData.h" +#include "stir/listmode/ListEnergy.h" #include "stir/listmode/CListRecordROOT.h" #include "stir/IO/InputStreamFromROOTFile.h" #include "stir/KeyParser.h" diff --git a/src/include/stir/listmode/CListRecordECAT8_32bit.h b/src/include/stir/listmode/CListRecordECAT8_32bit.h index 55e17234cd..1de42a7c99 100644 --- a/src/include/stir/listmode/CListRecordECAT8_32bit.h +++ b/src/include/stir/listmode/CListRecordECAT8_32bit.h @@ -36,6 +36,7 @@ #include "boost/static_assert.hpp" #include "boost/cstdint.hpp" #include "stir/DetectionPositionPair.h" +#include "stir/listmode/ListEnergy.h" START_NAMESPACE_STIR namespace ecat { @@ -194,6 +195,20 @@ class CListTimeECAT8_32bit : public ListTime }; }; +//! A class for storing and using an energy 'event' from a listmode file from the ECAT 8_32bit scanner +/*! \ingroup listmode + */ +class CListEnergyECAT8_32bit : public ListEnergy +{ + public: + bool is_energy() const + { return true; } + inline double get_energyA_in_keV() const + { return 0.F; } + inline double get_energyB_in_keV() const + { return 0.F; } +}; + //! A class for a general element of a listmode file for a Siemens scanner using the ECAT8 32bit format. /*! \ingroup listmode We currently only support coincidence events and a timing flag. @@ -210,6 +225,8 @@ class CListTimeECAT8_32bit : public ListTime bool is_time() const { return this->any_data.is_time(); } + bool is_energy() const + { return true; } /* bool is_gating_input() const { return this->is_time(); } @@ -224,7 +241,10 @@ class CListTimeECAT8_32bit : public ListTime { return this->time_data; } virtual const CListTimeECAT8_32bit& time() const { return this->time_data; } - + virtual CListEnergyECAT8_32bit& energy() + { return this->energy_data; } + virtual const CListEnergyECAT8_32bit& energy() const + { return this->energy_data; } bool operator==(const CListRecord& e2) const { return dynamic_cast(&e2) != 0 && @@ -264,6 +284,7 @@ class CListTimeECAT8_32bit : public ListTime private: CListEventECAT8_32bit event_data; CListTimeECAT8_32bit time_data; + CListEnergyECAT8_32bit energy_data; CListDataAnyECAT8_32bit any_data; boost::int32_t raw; // this raw field isn't strictly necessary, get rid of it? diff --git a/src/include/stir/listmode/CListRecordECAT962.h b/src/include/stir/listmode/CListRecordECAT962.h index c3985caa4b..c7366b8fd1 100644 --- a/src/include/stir/listmode/CListRecordECAT962.h +++ b/src/include/stir/listmode/CListRecordECAT962.h @@ -31,6 +31,7 @@ #include "stir/listmode/CListRecord.h" #include "stir/listmode/ListGatingInput.h" #include "stir/listmode/ListTime.h" +#include "stir/listmode/ListEnergy.h" #include "stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h" #include "stir/ProjDataInfoCylindrical.h" #include "stir/ProjDataInfoCylindricalNoArcCorr.h" @@ -183,10 +184,18 @@ class CListTimeDataECAT962 #endif }; +//! A class for storing and using an energy 'event' from a listmode file +/*! \ingroup listmode + */ +class CListEnergyDataECAT962 +{ + public: +}; + //! A class for a general element of a listmode file /*! \ingroup listmode For the 962 it's either a coincidence event, or a timing flag.*/ -class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, public ListGatingInput, +class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, public ListEnergy, public ListGatingInput, public CListEventCylindricalScannerWithViewTangRingRingEncoding { public: @@ -200,6 +209,8 @@ class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, p bool is_time() const { return time_data.type == 1U; } + bool is_energy() const + { return true; } bool is_gating_input() const { return this->is_time(); } bool is_event() const @@ -212,6 +223,10 @@ class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, p { return *this; } virtual const ListTime& time() const { return *this; } + virtual ListEnergy& energy() + { return *this; } + virtual const ListEnergy& energy() const + { return *this; } virtual ListGatingInput& gating_input() { return *this; } virtual const ListGatingInput& gating_input() const @@ -233,6 +248,12 @@ class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, p inline Succeeded set_gating(unsigned int g) { return time_data.set_gating(g); } + // energy + inline double get_energyA_in_keV() const + { return 0.F; } + inline double get_energyB_in_keV() const + { return 0.F; } + // event inline bool is_prompt() const { return event_data.is_prompt(); } inline Succeeded set_prompt(const bool prompt = true) @@ -260,6 +281,7 @@ class CListRecordECAT962 : public CListRecordWithGatingInput, public ListTime, p union { CListEventDataECAT962 event_data; CListTimeDataECAT962 time_data; + CListEnergyDataECAT962 energy_data; boost::int32_t raw; }; BOOST_STATIC_ASSERT(sizeof(boost::int32_t)==4); diff --git a/src/include/stir/listmode/CListRecordECAT966.h b/src/include/stir/listmode/CListRecordECAT966.h index 52078bc713..36a6d1d964 100644 --- a/src/include/stir/listmode/CListRecordECAT966.h +++ b/src/include/stir/listmode/CListRecordECAT966.h @@ -31,6 +31,7 @@ #include "stir/listmode/CListRecord.h" #include "stir/listmode/ListGatingInput.h" #include "stir/listmode/ListTime.h" +#include "stir/listmode/ListEnergy.h" #include "stir/listmode/CListEventCylindricalScannerWithViewTangRingRingEncoding.h" #include "stir/ProjDataInfoCylindrical.h" #include "stir/IO/stir_ecat_common.h" // for namespace macros @@ -200,6 +201,20 @@ class CListTimeECAT966 : public ListTime, public ListGatingInput }; }; +//! A class for storing and using a energy'event' from a listmode file from the ECAT 966 scanner +/*! \ingroup listmode + */ +class CListEnergyECAT966 : public ListEnergy +{ + public: + bool is_energy() const + {return true; } + inline double get_energyA_in_keV() const + { return 0.F; } + inline double get_energyB_in_keV() const + { return 0.F; } +}; + //! A class for a general element of a listmode file /*! \ingroup listmode For the 966 it's either a coincidence event, or a timing flag.*/ @@ -210,6 +225,8 @@ class CListRecordECAT966 : public CListRecordWithGatingInput bool is_time() const { return this->time_data.is_time(); } + bool is_energy() const + { return true; } bool is_gating_input() const { return this->is_time(); } bool is_event() const @@ -222,6 +239,10 @@ class CListRecordECAT966 : public CListRecordWithGatingInput { return this->time_data; } virtual const CListTimeECAT966& time() const { return this->time_data; } + virtual CListEnergyECAT966& energy() + { return this->energy_data; } + virtual const CListEnergyECAT966& energy() const + { return this->energy_data; } virtual CListTimeECAT966& gating_input() { return this->time_data; } virtual const CListTimeECAT966& gating_input() const @@ -260,6 +281,7 @@ class CListRecordECAT966 : public CListRecordWithGatingInput private: CListEventECAT966 event_data; CListTimeECAT966 time_data; + CListEnergyECAT966 energy_data; boost::int32_t raw; }; diff --git a/src/include/stir/listmode/CListRecordGEHDF5.h b/src/include/stir/listmode/CListRecordGEHDF5.h index 86a0bec20b..94033113cf 100644 --- a/src/include/stir/listmode/CListRecordGEHDF5.h +++ b/src/include/stir/listmode/CListRecordGEHDF5.h @@ -19,6 +19,7 @@ #define __stir_listmode_CListRecordGEHDF5_H__ #include "stir/listmode/CListRecord.h" +#include "stir/listmode/ListEnergy.h" #include "stir/listmode/CListEventCylindricalScannerWithDiscreteDetectors.h" #include "stir/Succeeded.h" #include "stir/ByteOrder.h" @@ -181,7 +182,19 @@ namespace RDF_HDF5 { All types of records are stored in a (private) union with the "basic" classes such as CListEventDataGEHDF5. This class essentially just forwards the work to the "basic" classes. */ -class CListRecordGEHDF5 : public CListRecord, public ListTime, // public CListGatingInput, + + class CListEnergyDataGEHDF5: public ListEnergy + { + public: + bool is_energy() const + {return true; } + inline double get_energyA_in_keV() const + { return 0.F; } + inline double get_energyB_in_keV() const + { return 0.F; } + }; + +class CListRecordGEHDF5 : public CListRecord, public ListTime, public ListEnergy, // public CListGatingInput, public CListEventCylindricalScannerWithDiscreteDetectors { typedef detail::CListEventDataGEHDF5 DataType; @@ -213,6 +226,8 @@ class CListRecordGEHDF5 : public CListRecord, public ListTime, // public CListGa bool is_event() const { return this->event_data.is_event(); } + bool is_energy() const + { return true; } virtual CListEvent& event() { return *this; } virtual const CListEvent& event() const @@ -221,6 +236,10 @@ class CListRecordGEHDF5 : public CListRecord, public ListTime, // public CListGa { return *this; } virtual const ListTime& time() const { return *this; } + virtual ListEnergy& energy() + { return *this; } + virtual const ListEnergy& energy() const + { return *this; } #if 0 virtual CListGatingInput& gating_input() { return *this; } diff --git a/src/include/stir/listmode/CListRecordROOT.h b/src/include/stir/listmode/CListRecordROOT.h index afd11ec401..3c9effc33e 100644 --- a/src/include/stir/listmode/CListRecordROOT.h +++ b/src/include/stir/listmode/CListRecordROOT.h @@ -127,6 +127,45 @@ class CListTimeROOT : public ListTime double timeB; }; +//! A class for storing and using an energy 'event' from a listmode file +/*! \ingroup listmode + */ +class CListEnergyROOT : public ListEnergy +{ +public: + + void init_energy_from_data(double energy1, double energy2) + { + energyA = energy1; + energyB = energy2; + } + + //! Returns always true + bool is_energy() const + { return true; } + //! Get the detection energy of the first photon + //! in keV + inline double get_energyA_in_keV() const + { return 1e3*energyA; } + //! Get the detection energy of the second photon + //! in keV + inline double get_energyB_in_keV() const + { return 1e3*energyB; } + +private: + + //! + //! \brief energyA + //! \details The detected energy of the first of the two photons, in MeV + double energyA; + + //! + //! \brief energyB + //! \details The detected energy of the second of the two photons, in MeV + double energyB; + + +}; //! A class for a general element of a listmode file for a Siemens scanner using the ROOT files class CListRecordROOT : public CListRecord // currently no gating yet { @@ -136,6 +175,8 @@ class CListRecordROOT : public CListRecord // currently no gating yet //! Returns always true bool inline is_event() const; //! Returns always true + bool inline is_energy() const; + //! Returns always true bool inline is_full_event() const; virtual CListEventROOT& event() @@ -158,6 +199,16 @@ class CListRecordROOT : public CListRecord // currently no gating yet return this->time_data; } + virtual CListEnergyROOT& energy() + { + return this->energy_data; + } + + virtual const CListEnergyROOT& energy() const + { + return this->energy_data; + } + bool operator==(const CListRecord& e2) const { return dynamic_cast(&e2) != 0 && @@ -174,7 +225,8 @@ class CListRecordROOT : public CListRecord // currently no gating yet const int& crystal1, const int& crystal2, double time1, double time2, - const int& event1, const int& event2) + const int& event1, const int& event2, + double energy1 = 0.511F, double energy2 = 0.511F) { /// \warning ROOT data are time and event at the same time. @@ -184,6 +236,7 @@ class CListRecordROOT : public CListRecord // currently no gating yet this->time_data.init_from_data( time1,time2); + this->energy_data.init_energy_from_data(energy1,energy2); // We can make a singature raw based on the two events IDs. // It is pretty unique. raw[0] = event1; @@ -195,6 +248,7 @@ class CListRecordROOT : public CListRecord // currently no gating yet private: CListEventROOT event_data; CListTimeROOT time_data; + CListEnergyROOT energy_data; boost::int32_t raw[2]; // this raw field isn't strictly necessary, get rid of it? }; diff --git a/src/include/stir/listmode/CListRecordROOT.inl b/src/include/stir/listmode/CListRecordROOT.inl index 26270593c4..676af76c23 100644 --- a/src/include/stir/listmode/CListRecordROOT.inl +++ b/src/include/stir/listmode/CListRecordROOT.inl @@ -33,6 +33,9 @@ bool CListRecordROOT::is_time() const bool CListRecordROOT::is_event() const { return true; } +bool CListRecordROOT::is_energy() const +{ return true; } + bool CListRecordROOT::is_full_event() const { return true; } diff --git a/src/include/stir/listmode/CListRecordSAFIR.h b/src/include/stir/listmode/CListRecordSAFIR.h index 4338124ea2..2024f778ba 100644 --- a/src/include/stir/listmode/CListRecordSAFIR.h +++ b/src/include/stir/listmode/CListRecordSAFIR.h @@ -164,8 +164,16 @@ class CListTimeDataSAFIR #endif }; +//! Class for record with time data +class CListEnergyDataSAFIR +{ + +public: + +}; + //! Class for general record, containing a union of data, time and raw record and providing access to certain elements. -class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventSAFIR +class CListRecordSAFIR : public CListRecord, public ListTime, public ListEnergy, public CListEventSAFIR { public: typedef CListEventDataSAFIR DataType; @@ -184,6 +192,9 @@ class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventS virtual bool is_event() const { return time_data.type == 0; } + virtual bool is_energy() const + { return true;} + virtual CListEvent& event() { return *this; } @@ -202,6 +213,12 @@ class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventS virtual const ListTime& time() const { return *this; } + virtual ListEnergy& energy() + { return *this; } + + virtual const ListEnergy& energy() const + { return *this; } + virtual bool operator==(const CListRecord& e2) const { return dynamic_cast(&e2) != 0 && @@ -214,6 +231,11 @@ class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventS inline Succeeded set_time_in_millisecs(const unsigned long time_in_millisecs) { return time_data.set_time_in_millisecs(time_in_millisecs); } + inline double get_energyA_in_keV() const + { return 0.F; } + inline double get_energyB_in_keV() const + { return 0.F; } + inline bool is_prompt() const { return !(event_data.isRandom); } Succeeded @@ -241,6 +263,7 @@ class CListRecordSAFIR : public CListRecord, public ListTime, public CListEventS union { CListEventDataSAFIR event_data; CListTimeDataSAFIR time_data; + CListEnergyDataSAFIR energy_data; boost::int64_t raw; }; BOOST_STATIC_ASSERT(sizeof(boost::uint64_t)==8); diff --git a/src/include/stir/listmode/ListEnergy.h b/src/include/stir/listmode/ListEnergy.h new file mode 100644 index 0000000000..d7128387a4 --- /dev/null +++ b/src/include/stir/listmode/ListEnergy.h @@ -0,0 +1,56 @@ +// +/*! + \file + \ingroup listmode + \brief Declarations of class stir::ListEnergy which + is used for list mode data. + + \author Ludovica Brusaferri + +*/ +/* + Copyright (C) 2019, University College of London + This file is part of STIR. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See STIR/LICENSE.txt for details +*/ + +#ifndef __stir_listmode_ListEnergy_H__ +#define __stir_listmode_ListEnergy_H__ + +#include "stir/Succeeded.h" +#include "stir/round.h" + +START_NAMESPACE_STIR +//class Succeeded; + +//! A class for storing and using an energy record from a listmode file +/*! \ingroup listmode + ListEnergy is used to provide an interface to the 'energy' events + in the list mode stream. + + \todo this is still under development. +*/ +class ListEnergy +{ +public: + virtual ~ListEnergy() {} + + virtual double get_energyA_in_keV() const = 0; + virtual double get_energyB_in_keV() const = 0; + +}; + +END_NAMESPACE_STIR + +#endif diff --git a/src/include/stir/listmode/ListRecord.h b/src/include/stir/listmode/ListRecord.h index 78c255f63e..c8880059bd 100644 --- a/src/include/stir/listmode/ListRecord.h +++ b/src/include/stir/listmode/ListRecord.h @@ -34,6 +34,7 @@ #include "ListEvent.h" #include "ListTime.h" +#include "ListEnergy.h" #include "stir/Succeeded.h" START_NAMESPACE_STIR @@ -60,10 +61,14 @@ class ListRecord virtual bool is_event() const = 0; + virtual bool is_energy() const = 0; + virtual ListEvent& event() = 0; virtual const ListEvent& event() const = 0; virtual ListTime& time() = 0; - virtual const ListTime& time() const = 0; + virtual const ListTime& time() const = 0; + virtual ListEnergy& energy() = 0; + virtual const ListEnergy& energy() const = 0; }; END_NAMESPACE_STIR diff --git a/src/include/stir/listmode/LmToProjData.h b/src/include/stir/listmode/LmToProjData.h index 7f2cc7bfdd..c2b3e1327b 100644 --- a/src/include/stir/listmode/LmToProjData.h +++ b/src/include/stir/listmode/LmToProjData.h @@ -45,6 +45,7 @@ START_NAMESPACE_STIR class ListEvent; class ListTime; +class ListEnergy; /*! \ingroup listmode diff --git a/src/include/stir/listmode/SPECTListRecord.h b/src/include/stir/listmode/SPECTListRecord.h index 0e8c4182e9..bb80b17eea 100644 --- a/src/include/stir/listmode/SPECTListRecord.h +++ b/src/include/stir/listmode/SPECTListRecord.h @@ -33,6 +33,7 @@ #include "stir/listmode/ListTime.h" +#include "stir/listmode/ListEnergy.h" #include "ListRecord.h" #include "stir/listmode/SPECTListEvent.h" @@ -59,11 +60,14 @@ class SPECTListRecord : public ListRecord virtual bool is_event() const = 0; + //virtual bool is_energy() const = 0; + virtual SPECTListEvent& event() = 0; virtual const SPECTListEvent& event() const = 0; virtual ListTime& time() = 0; virtual const ListTime& time() const = 0; - + virtual ListEnergy & energy() = 0; + virtual const ListEnergy& energy() const = 0; virtual bool operator==(const SPECTListRecord& e2) const = 0; bool operator!=(const SPECTListRecord& e2) const { return !(*this == e2); } diff --git a/src/include/stir_experimental/listmode/CListRecordLMF.h b/src/include/stir_experimental/listmode/CListRecordLMF.h index ced054ad59..f49ca9f988 100644 --- a/src/include/stir_experimental/listmode/CListRecordLMF.h +++ b/src/include/stir_experimental/listmode/CListRecordLMF.h @@ -71,6 +71,14 @@ class CListTimeDataLMF unsigned long time; // in millisecs TODO }; +//! A class for storing and using an energy 'event' from a listmode file +/*! \ingroup ClearPET_utilities + */ +class CListEnergyDataLMF +{ + public: +}; + //! A class for a general element of a listmode file /*! \ingroup ClearPET_utilities @@ -80,7 +88,7 @@ I store both time and CListEvent info in one CListRecordLMF. That's obviously not necessary nor desirable. */ -class CListRecordLMF : public CListRecord, public ListTime, public CListEvent +class CListRecordLMF : public CListRecord, public ListTime, public ListEnergy, public CListEvent { public: @@ -93,6 +101,8 @@ class CListRecordLMF : public CListRecord, public ListTime, public CListEvent { return is_time_flag == true; } bool is_event() const { return is_time_flag == false; } + bool is_energy() const + { return true; } virtual CListEvent& event() { return *this; } virtual const CListEvent& event() const @@ -101,7 +111,10 @@ class CListRecordLMF : public CListRecord, public ListTime, public CListEvent { return *this; } virtual const ListTime& time() const { return *this; } - + virtual ListEnergy& energy() + { return *this; } + virtual const ListEnergy& energy() const + { return *this; } bool operator==(const CListRecord& e2) const; // time @@ -125,6 +138,7 @@ class CListRecordLMF : public CListRecord, public ListTime, public CListEvent CListEventDataLMF event_data; CListTimeDataLMF time_data; + CListEnergyDataLMF energy_data; bool is_time_flag; }; diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 91fb7bbfd0..ede5ae287a 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -663,6 +663,8 @@ process_data() && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) ) { + std::cout<< "energy A new: " << record.energy().get_energyA_in_keV()<< '\n'; + std::cout<< "energy B new: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_sptr->get_min_view_num()); assert(bin.view_num()<=proj_data_sptr->get_max_view_num()); From dfafb4304830af74ee60409ce323af43a3072313 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 19 Oct 2020 14:40:50 -0400 Subject: [PATCH 263/274] added energy window info --- src/IO/InputStreamFromROOTFile.cxx | 25 ++++++++----- ...putStreamFromROOTFileForCylindricalPET.cxx | 23 +++++++----- src/IO/InputStreamFromROOTFileForECATPET.cxx | 23 +++++++----- src/include/stir/IO/InputStreamFromROOTFile.h | 31 ++++++++++------ .../stir/IO/InputStreamFromROOTFile.inl | 37 ++++++++++++++----- ...InputStreamFromROOTFileForCylindricalPET.h | 5 ++- .../IO/InputStreamFromROOTFileForECATPET.h | 5 ++- src/listmode_buildblock/CListModeDataROOT.cxx | 4 +- 8 files changed, 96 insertions(+), 57 deletions(-) diff --git a/src/IO/InputStreamFromROOTFile.cxx b/src/IO/InputStreamFromROOTFile.cxx index f74a159d0c..1f038c524b 100644 --- a/src/IO/InputStreamFromROOTFile.cxx +++ b/src/IO/InputStreamFromROOTFile.cxx @@ -40,12 +40,13 @@ InputStreamFromROOTFile() InputStreamFromROOTFile:: InputStreamFromROOTFile(std::string filename, std::string chain_name, - bool exclude_scattered, bool exclude_randoms, - float low_energy_window, float up_energy_window, + int maximum_order_of_scatter, bool exclude_randoms, + float low_energy_window_1, float up_energy_window_1, + float low_energy_window_2, float up_energy_window_2, int offset_dets) : filename(filename), chain_name(chain_name), - exclude_scattered(exclude_scattered), exclude_randoms(exclude_randoms), - low_energy_window(low_energy_window), up_energy_window(up_energy_window), offset_dets(offset_dets) + maximum_order_of_scatter(maximum_order_of_scatter), exclude_randoms(exclude_randoms), + low_energy_window_1(low_energy_window_1), up_energy_window_1(up_energy_window_1),low_energy_window_2(low_energy_window_2), up_energy_window_2(up_energy_window_2), offset_dets(offset_dets) { set_defaults(); reset(); @@ -56,10 +57,12 @@ InputStreamFromROOTFile::set_defaults() { starting_stream_position = 0; singles_readout_depth = -1; - exclude_scattered = false; + maximum_order_of_scatter = 0; exclude_randoms = false; - low_energy_window = 0.f; - up_energy_window = 1000.f; + low_energy_window_1 = 0.f; + up_energy_window_1 = 1000.f; + low_energy_window_2 = 0.f; + up_energy_window_2 = 1000.f; read_optional_root_fields=false; } @@ -69,11 +72,13 @@ InputStreamFromROOTFile::initialise_keymap() this->parser.add_key("name of data file", &this->filename); this->parser.add_key("Singles readout depth", &this->singles_readout_depth); this->parser.add_key("name of input TChain", &this->chain_name); - this->parser.add_key("exclude scattered events", &this->exclude_scattered); + this->parser.add_key("maximum order of scatter", &this->maximum_order_of_scatter); this->parser.add_key("exclude random events", &this->exclude_randoms); this->parser.add_key("offset (num of detectors)", &this->offset_dets); - this->parser.add_key("low energy window (keV)", &this->low_energy_window); - this->parser.add_key("upper energy window (keV)", &this->up_energy_window); + this->parser.add_key("low energy window 1 (MeV)", &this->low_energy_window_1); + this->parser.add_key("upper energy window 1 (MeV)", &this->up_energy_window_1); + this->parser.add_key("low energy window 2 (MeV)", &this->low_energy_window_2); + this->parser.add_key("upper energy window 2 (MeV)", &this->up_energy_window_2); this->parser.add_key("read optional ROOT fields", &this->read_optional_root_fields); } diff --git a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx index 160b182866..e91cb406d8 100644 --- a/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx +++ b/src/IO/InputStreamFromROOTFileForCylindricalPET.cxx @@ -38,8 +38,9 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, int submodule_repeater_x, int submodule_repeater_y, int submodule_repeater_z, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, - bool _exclude_scattered, bool _exclude_randoms, - float _low_energy_window, float _up_energy_window, + int _maximum_order_of_scatter, bool _exclude_randoms, + float _low_energy_window_1, float _up_energy_window_1, + float _low_energy_window_2, float _up_energy_window_2, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), @@ -51,10 +52,12 @@ InputStreamFromROOTFileForCylindricalPET(std::string _filename, filename = _filename; chain_name = _chain_name; - exclude_scattered = _exclude_scattered; + maximum_order_of_scatter = _maximum_order_of_scatter; exclude_randoms = _exclude_randoms; - low_energy_window = _low_energy_window; - up_energy_window = _up_energy_window; + low_energy_window_1 = _low_energy_window_1; + up_energy_window_1 = _up_energy_window_1; + low_energy_window_2 = _low_energy_window_2; + up_energy_window_2 = _up_energy_window_2; offset_dets = _offset_dets; half_block = module_repeater_y * submodule_repeater_y * crystal_repeater_y / 2 - 1; @@ -78,14 +81,14 @@ get_next_record(CListRecordROOT& record) current_position ++ ; - if ( (this->comptonphantom1 > 0 || this->comptonphantom2 > 0) && this->exclude_scattered ) + if (comptonphantom1 + comptonphantom2 > maximum_order_of_scatter) continue; if ( (this->eventID1 != this->eventID2) && this->exclude_randoms) continue; - if (this->energy1 < this->low_energy_window || - this->energy1 > this->up_energy_window || - this->energy2 < this->low_energy_window || - this->energy2 > this->up_energy_window) + if (this->energy1 < this->low_energy_window_1 || + this->energy1 > this->up_energy_window_1 || + this->energy2 < this->low_energy_window_2|| + this->energy2 > this->up_energy_window_2) continue; break; diff --git a/src/IO/InputStreamFromROOTFileForECATPET.cxx b/src/IO/InputStreamFromROOTFileForECATPET.cxx index e8faa30729..4efe3fa3d7 100644 --- a/src/IO/InputStreamFromROOTFileForECATPET.cxx +++ b/src/IO/InputStreamFromROOTFileForECATPET.cxx @@ -37,8 +37,9 @@ InputStreamFromROOTFileForECATPET(std::string _filename, std::string _chain_name, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int block_repeater_y, int block_repeater_z, - bool _exclude_scattered, bool _exclude_randoms, - float _low_energy_window, float _up_energy_window, + int _maximum_order_of_scater, bool _exclude_randoms, + float _low_energy_window_1, float _up_energy_window_1, + float _low_energy_window_2, float _up_energy_window_2, int _offset_dets): base_type(), crystal_repeater_x(crystal_repeater_x), crystal_repeater_y(crystal_repeater_y), crystal_repeater_z(crystal_repeater_z), @@ -48,10 +49,12 @@ InputStreamFromROOTFileForECATPET(std::string _filename, filename = _filename; chain_name = _chain_name; - exclude_scattered = _exclude_scattered; + maximum_order_of_scatter = _maximum_order_of_scater; exclude_randoms = _exclude_randoms; - low_energy_window = _low_energy_window; - up_energy_window = _up_energy_window; + low_energy_window_1 = _low_energy_window_1; + up_energy_window_1 = _up_energy_window_1; + low_energy_window_2 = _low_energy_window_2; + up_energy_window_2 = _up_energy_window_2; offset_dets = _offset_dets; half_block = crystal_repeater_y / 2 - 1; @@ -74,14 +77,14 @@ get_next_record(CListRecordROOT& record) current_position ++ ; - if ( (comptonphantom1 > 0 || comptonphantom2 > 0) && exclude_scattered ) + if (comptonphantom1 + comptonphantom2 > maximum_order_of_scatter) continue; if ( eventID1 != eventID2 && exclude_randoms ) continue; - if (energy1 < low_energy_window || - energy1 > up_energy_window || - energy2 < low_energy_window || - energy2 > up_energy_window) + if (this->energy1 < this->low_energy_window_1 || + this->energy1 > this->up_energy_window_1 || + this->energy2 < this->low_energy_window_2|| + this->energy2 > this->up_energy_window_2) continue; break; diff --git a/src/include/stir/IO/InputStreamFromROOTFile.h b/src/include/stir/IO/InputStreamFromROOTFile.h index bf95dfc316..ae45698b0b 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.h +++ b/src/include/stir/IO/InputStreamFromROOTFile.h @@ -80,8 +80,9 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile //! constructor InputStreamFromROOTFile(std::string filename, std::string chain_name, - bool exclude_scattered, bool exclude_randoms, - float low_energy_window, float up_energy_window, + int maximum_order_of_scatter, bool exclude_randoms, + float low_energy_window_1, float up_energy_window_1, + float low_energy_window_2, float up_energy_window_2, int offset_dets); @@ -130,9 +131,11 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile virtual int get_num_trans_crystals_per_singles_unit() const = 0; //! Lower energy threshold - inline float get_low_energy_thres() const; + inline std::vector get_low_energy_thres_in_keV() const; //! Upper energy threshold - inline float get_up_energy_thres() const; + inline std::vector get_up_energy_thres_in_keV() const; + //! Number of energy windows + inline int get_number_of_energy_windows() const; //! Set singles_readout_depth inline void set_singles_readout_depth(int); @@ -141,15 +144,15 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile inline void set_chain_name(const std::string&); - inline void set_exclude_scattered_events(bool); + inline void set_maximum_order_of_scatter(int); inline void set_exclude_random_events(bool); inline void set_detectors_offset(int); - inline void set_low_energy_window(float); + inline void set_low_energy_window(const std::vector &); - inline void set_upper_energy_window(float); + inline void set_upper_energy_window(const std::vector &); //! Set the read_optional_root_fields flag inline void set_optional_ROOT_fields(bool); @@ -194,14 +197,20 @@ class InputStreamFromROOTFile : public RegisteredObject< InputStreamFromROOTFile float sourcePosX1, sourcePosX2, sourcePosY1, sourcePosY2, sourcePosZ1, sourcePosZ2; //@} - //! Skip scattered events (comptonphantom1 > 0 && comptonphantom2 > 0) - bool exclude_scattered; + //! Skip scattered events (comptonphantom1 + comptonphantom2 > maximum_order_of_scatter); + int maximum_order_of_scatter; //! Skip random events (eventID1 != eventID2) bool exclude_randoms; //! Lower energy threshold - float low_energy_window; + float low_energy_window_1; //! Upper energy threshold - float up_energy_window; + float up_energy_window_1; + //! Lower energy threshold + float low_energy_window_2; + //! Upper energy threshold + float up_energy_window_2; + //! Number of energy windows + int num_en_windows; //! This value will apply a rotation on the detectors' id in the same ring. int offset_dets; //!For the singles_readout_depth from GATE's online documentation: diff --git a/src/include/stir/IO/InputStreamFromROOTFile.inl b/src/include/stir/IO/InputStreamFromROOTFile.inl index 97d5a44486..4024ce898f 100644 --- a/src/include/stir/IO/InputStreamFromROOTFile.inl +++ b/src/include/stir/IO/InputStreamFromROOTFile.inl @@ -72,6 +72,13 @@ get_saved_get_positions() const return saved_get_positions; } +int +InputStreamFromROOTFile:: +get_number_of_energy_windows() const +{ + return num_en_windows; +} + void InputStreamFromROOTFile:: set_saved_get_positions(const std::vector &poss) @@ -79,17 +86,25 @@ set_saved_get_positions(const std::vector &poss) saved_get_positions = poss; } -float +std::vector InputStreamFromROOTFile:: -get_low_energy_thres() const +get_low_energy_thres_in_keV() const { + std::vector low_energy_window; + low_energy_window.resize(2); + low_energy_window[0]=1e3*low_energy_window_1; + low_energy_window[1]=1e3*low_energy_window_2; return low_energy_window; } -float +std::vector InputStreamFromROOTFile:: -get_up_energy_thres() const +get_up_energy_thres_in_keV() const { + std::vector up_energy_window; + up_energy_window.resize(2); + up_energy_window[0]=1e3*up_energy_window_1; + up_energy_window[1]=1e3*up_energy_window_2; return up_energy_window; } @@ -119,9 +134,9 @@ InputStreamFromROOTFile::set_chain_name(const std::string& val) } void -InputStreamFromROOTFile::set_exclude_scattered_events(bool val) +InputStreamFromROOTFile::set_maximum_order_of_scatter(int val) { - exclude_scattered = val; + maximum_order_of_scatter = val; } void @@ -137,15 +152,17 @@ InputStreamFromROOTFile::set_detectors_offset(int val) } void -InputStreamFromROOTFile::set_low_energy_window(float val) +InputStreamFromROOTFile::set_low_energy_window(const std::vector &val) { - low_energy_window = val; + low_energy_window_1 = val[0]; + low_energy_window_2 = val[1]; } void -InputStreamFromROOTFile::set_upper_energy_window(float val) +InputStreamFromROOTFile::set_upper_energy_window(const std::vector &val) { - up_energy_window = val; + up_energy_window_1 = val[0]; + up_energy_window_1 = val[1]; } void diff --git a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h index 0ac72fdc9c..31afa005e6 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForCylindricalPET.h @@ -100,8 +100,9 @@ class InputStreamFromROOTFileForCylindricalPET : public int submodule_repeater_x, int submodule_repeater_y, int submodule_repeater_z, int module_repeater_x, int module_repeater_y, int module_repeater_z, int rsector_repeater, - bool exclude_scattered, bool exclude_randoms, - float low_energy_window, float up_energy_window, + int maximum_order_of_scatter, bool exclude_randoms, + float low_energy_window_1, float up_energy_window_1, + float low_energy_window_2, float up_energy_window_2, int offset_dets); virtual ~InputStreamFromROOTFileForCylindricalPET() {} diff --git a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h index e4700b5450..270f749b9f 100644 --- a/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h +++ b/src/include/stir/IO/InputStreamFromROOTFileForECATPET.h @@ -94,8 +94,9 @@ class InputStreamFromROOTFileForECATPET : public std::string chain_name, int crystal_repeater_x, int crystal_repeater_y, int crystal_repeater_z, int blocks_repeater_y, int blocks_repeater_z, - bool exclude_scattered, bool exclude_randoms, - float low_energy_window, float up_energy_window, + int maximum_order_of_scatter, bool exclude_randoms, + float low_energy_window_1, float up_energy_window_1, + float low_energy_window_2, float up_energy_window_2, int offset_dets); virtual ~InputStreamFromROOTFileForECATPET() {} diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index dd5e5b45c8..8d878a40e0 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -77,8 +77,8 @@ CListModeDataROOT(const std::string& hroot_filename) // Only PET scanners supported _exam_info_sptr->imaging_modality = ImagingModality::PT; _exam_info_sptr->originating_system = this->originating_system; - _exam_info_sptr->set_low_energy_thres(this->root_file_sptr->get_low_energy_thres()); - _exam_info_sptr->set_high_energy_thres(this->root_file_sptr->get_up_energy_thres()); + //_exam_info_sptr->set_low_energy_thres(this->root_file_sptr->get_low_energy_thres()); + //_exam_info_sptr->set_high_energy_thres(this->root_file_sptr->get_up_energy_thres()); this->exam_info_sptr = _exam_info_sptr; From 0d3389c13a65de9431a42871b52a7d3068dcd7be Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 19 Oct 2020 15:32:47 -0400 Subject: [PATCH 264/274] test --- src/include/stir/listmode/ListEvent.h | 2 +- src/include/stir/listmode/LmToProjData.h | 4 +++- src/listmode_buildblock/ListEvent.cxx | 4 ++-- src/listmode_buildblock/LmToProjData.cxx | 24 ++++++++++++++++-------- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/include/stir/listmode/ListEvent.h b/src/include/stir/listmode/ListEvent.h index 4829b1f3f5..68243c1b9f 100644 --- a/src/include/stir/listmode/ListEvent.h +++ b/src/include/stir/listmode/ListEvent.h @@ -92,7 +92,7 @@ class ListEvent */ virtual void - get_bin(Bin& bin, const ProjDataInfo&) const; + get_bin(Bin& bin, const ProjDataInfo&, const std::pair &energy_window_pair = std::pair(1,1)) const; //! This method checks if the template is valid for LmToProjData /*! Used before the actual processing of the data (see issue #61), before calling get_bin() diff --git a/src/include/stir/listmode/LmToProjData.h b/src/include/stir/listmode/LmToProjData.h index c2b3e1327b..ed7b4376ba 100644 --- a/src/include/stir/listmode/LmToProjData.h +++ b/src/include/stir/listmode/LmToProjData.h @@ -197,7 +197,7 @@ class LmToProjData : public LmToProjDataAbstract (on top of anything done by normalisation_ptr). \todo Would need timing info or so for e.g. time dependent normalisation or angle info for a rotating scanner.*/ - virtual void get_bin_from_event(Bin& bin, const ListEvent&) const; + virtual void get_bin_from_event(Bin& bin, const ListEvent&, const std::pair &energy_window_pair = std::pair(1,1)) const; //! A function that should return the number of uncompressed bins in the current bin /*! \todo it is not compatiable with e.g. HiDAC doesn't belong here anyway @@ -238,6 +238,8 @@ class LmToProjData : public LmToProjDataAbstract bool interactive; shared_ptr template_proj_data_info_ptr; + + //shared_ptr template_exam_info_sptr; //! This will be used for pre-normalisation shared_ptr normalisation_ptr; //! This will be used for post-normalisation diff --git a/src/listmode_buildblock/ListEvent.cxx b/src/listmode_buildblock/ListEvent.cxx index b0d29651f9..42886a0b92 100644 --- a/src/listmode_buildblock/ListEvent.cxx +++ b/src/listmode_buildblock/ListEvent.cxx @@ -38,9 +38,9 @@ START_NAMESPACE_STIR void ListEvent:: -get_bin(Bin& bin, const ProjDataInfo& proj_data_info) const +get_bin(Bin& bin, const ProjDataInfo& proj_data_info, const std::pair &energy_window_pair) const { - bin = proj_data_info.get_bin(get_LOR()); + bin = proj_data_info.get_bin(get_LOR(),energy_window_pair); } END_NAMESPACE_STIR diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index ede5ae287a..fc7d528cf2 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -218,6 +218,13 @@ post_processing() template_proj_data_info_ptr.reset(template_proj_data_ptr->get_proj_data_info_sptr()->clone()); + /*shared_ptr template_exam_info_sptr = template_proj_data_ptr->get_exam_info().create_shared_clone(); + template_exam_info_sptr->set_num_energy_windows(template_proj_data_ptr->get_exam_info().get_num_energy_windows()); + for (int i=0; iget_num_energy_windows(); i++) + { + template_exam_info_sptr->set_high_energy_thres(template_proj_data_ptr->get_exam_info().get_high_energy_thres(i),i); + template_exam_info_sptr->set_low_energy_thres(template_proj_data_ptr->get_exam_info().get_low_energy_thres(i),i); + }*/ // propagate relevant metadata template_proj_data_info_ptr->set_bed_position_horizontal (lm_data_ptr->get_proj_data_info_sptr()->get_bed_position_horizontal()); @@ -388,12 +395,12 @@ LmToProjData(const char * const par_filename) ***************************************************************/ void LmToProjData:: -get_bin_from_event(Bin& bin, const ListEvent& event) const +get_bin_from_event(Bin& bin, const ListEvent& event, const std::pair &energy_window_pair) const { if (do_pre_normalisation) { Bin uncompressed_bin; - event.get_bin(uncompressed_bin, *proj_data_info_cyl_uncompressed_ptr); + event.get_bin(uncompressed_bin, *proj_data_info_cyl_uncompressed_ptr, energy_window_pair); if (uncompressed_bin.get_bin_value()<=0) return; // rejected for some strange reason @@ -427,7 +434,7 @@ get_bin_from_event(Bin& bin, const ListEvent& event) const const float bin_value = 1/bin_efficiency; // TODO wasteful: we decode the event twice. replace by something like // template_proj_data_info_ptr->get_bin_from_uncompressed(bin, uncompressed_bin); - event.get_bin(bin, *template_proj_data_info_ptr); + event.get_bin(bin, *template_proj_data_info_ptr, energy_window_pair); if (bin.get_bin_value()>0) { @@ -437,7 +444,7 @@ get_bin_from_event(Bin& bin, const ListEvent& event) const } else { - event.get_bin(bin, *template_proj_data_info_ptr); + event.get_bin(bin, *template_proj_data_info_ptr, energy_window_pair); } } @@ -527,7 +534,6 @@ process_data() // we have to do this because the first time tag might occur only after a // few coincidence events (as happens with ECAT scanners) current_time = 0; - double time_of_last_stored_event = 0; long num_stored_events = 0; VectorWithOffset @@ -565,7 +571,6 @@ process_data() char rest[50]; sprintf(rest, "_f%dg1d0b0", current_frame_num); const string output_filename = output_filename_prefix + rest; - proj_data_sptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); } @@ -660,8 +665,11 @@ process_data() && bin.tangential_pos_num()>= proj_data_sptr->get_min_tangential_pos_num() && bin.tangential_pos_num()<= proj_data_sptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) - && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) - ) + && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num())) + //&& record.energy().get_energyA_in_keV() >= (low_en_thres[bin.first_energy_window_num()-1]) + //&& record.energy().get_energyA_in_keV() <= (high_en_thres[bin.first_energy_window_num()-1]) + //&& record.energy().get_energyB_in_keV() >= (low_en_thres[bin.second_energy_window_num()-1]) + //&& record.energy().get_energyB_in_keV() <= (high_en_thres[bin.second_energy_window_num()-1])) { std::cout<< "energy A new: " << record.energy().get_energyA_in_keV()<< '\n'; std::cout<< "energy B new: " << record.energy().get_energyB_in_keV() << '\n'; From e20fe98b96cff2a5f1470d44e49f4f78c89c505d Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 19 Oct 2020 15:49:12 -0400 Subject: [PATCH 265/274] stil have to add exam info --- src/listmode_buildblock/CListModeDataROOT.cxx | 4 ++-- src/listmode_buildblock/LmToProjData.cxx | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/listmode_buildblock/CListModeDataROOT.cxx b/src/listmode_buildblock/CListModeDataROOT.cxx index 8d878a40e0..0173de76e1 100644 --- a/src/listmode_buildblock/CListModeDataROOT.cxx +++ b/src/listmode_buildblock/CListModeDataROOT.cxx @@ -77,8 +77,8 @@ CListModeDataROOT(const std::string& hroot_filename) // Only PET scanners supported _exam_info_sptr->imaging_modality = ImagingModality::PT; _exam_info_sptr->originating_system = this->originating_system; - //_exam_info_sptr->set_low_energy_thres(this->root_file_sptr->get_low_energy_thres()); - //_exam_info_sptr->set_high_energy_thres(this->root_file_sptr->get_up_energy_thres()); + _exam_info_sptr->set_high_energy_thres_vect(this->root_file_sptr->get_up_energy_thres_in_keV()); + _exam_info_sptr->set_low_energy_thres_vect(this->root_file_sptr->get_low_energy_thres_in_keV()); this->exam_info_sptr = _exam_info_sptr; diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index fc7d528cf2..b12f4a0dd0 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -665,11 +665,11 @@ process_data() && bin.tangential_pos_num()>= proj_data_sptr->get_min_tangential_pos_num() && bin.tangential_pos_num()<= proj_data_sptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) - && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num())) - //&& record.energy().get_energyA_in_keV() >= (low_en_thres[bin.first_energy_window_num()-1]) - //&& record.energy().get_energyA_in_keV() <= (high_en_thres[bin.first_energy_window_num()-1]) - //&& record.energy().get_energyB_in_keV() >= (low_en_thres[bin.second_energy_window_num()-1]) - //&& record.energy().get_energyB_in_keV() <= (high_en_thres[bin.second_energy_window_num()-1])) + && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) + && record.energy().get_energyA_in_keV() >= lm_data_ptr->get_exam_info_sptr()->get_low_energy_thres(0) + && record.energy().get_energyA_in_keV() <= lm_data_ptr->get_exam_info_sptr()->get_high_energy_thres(0) + && record.energy().get_energyB_in_keV() >= lm_data_ptr->get_exam_info_sptr()->get_low_energy_thres(1) + && record.energy().get_energyB_in_keV() <= lm_data_ptr->get_exam_info_sptr()->get_high_energy_thres(1)) { std::cout<< "energy A new: " << record.energy().get_energyA_in_keV()<< '\n'; std::cout<< "energy B new: " << record.energy().get_energyB_in_keV() << '\n'; From 919a92a321705c75c9b798dacbb04cbe8a59b9f7 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 19 Oct 2020 16:09:43 -0400 Subject: [PATCH 266/274] added template --- src/listmode_buildblock/LmToProjData.cxx | 29 +++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index b12f4a0dd0..1dd8e501a5 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -218,13 +218,6 @@ post_processing() template_proj_data_info_ptr.reset(template_proj_data_ptr->get_proj_data_info_sptr()->clone()); - /*shared_ptr template_exam_info_sptr = template_proj_data_ptr->get_exam_info().create_shared_clone(); - template_exam_info_sptr->set_num_energy_windows(template_proj_data_ptr->get_exam_info().get_num_energy_windows()); - for (int i=0; iget_num_energy_windows(); i++) - { - template_exam_info_sptr->set_high_energy_thres(template_proj_data_ptr->get_exam_info().get_high_energy_thres(i),i); - template_exam_info_sptr->set_low_energy_thres(template_proj_data_ptr->get_exam_info().get_low_energy_thres(i),i); - }*/ // propagate relevant metadata template_proj_data_info_ptr->set_bed_position_horizontal (lm_data_ptr->get_proj_data_info_sptr()->get_bed_position_horizontal()); @@ -534,6 +527,9 @@ process_data() // we have to do this because the first time tag might occur only after a // few coincidence events (as happens with ECAT scanners) current_time = 0; + shared_ptr template_proj_data_ptr = + ProjData::read_from_file(template_proj_data_name); + double time_of_last_stored_event = 0; long num_stored_events = 0; VectorWithOffset @@ -571,6 +567,16 @@ process_data() char rest[50]; sprintf(rest, "_f%dg1d0b0", current_frame_num); const string output_filename = output_filename_prefix + rest; + this_frame_exam_info.set_num_energy_windows(template_proj_data_ptr->get_exam_info_sptr()->get_num_energy_windows()); + std::vector energy_window_pair(2); + energy_window_pair.at(0) = template_proj_data_ptr->get_exam_info_sptr()->get_energy_window_pair().first; + energy_window_pair.at(1) = template_proj_data_ptr->get_exam_info_sptr()->get_energy_window_pair().second; + this_frame_exam_info.set_energy_window_pair(energy_window_pair); + for (int i = 0; i < template_proj_data_ptr->get_exam_info_sptr()->get_num_energy_windows(); ++i ) + { + this_frame_exam_info.set_high_energy_thres(template_proj_data_ptr->get_exam_info_sptr()->get_low_energy_thres(i),i); + this_frame_exam_info.set_low_energy_thres(template_proj_data_ptr->get_exam_info_sptr()->get_high_energy_thres(i),i); + } proj_data_sptr = construct_proj_data(output, output_filename, this_frame_exam_info, template_proj_data_info_ptr); } @@ -666,11 +672,12 @@ process_data() && bin.tangential_pos_num()<= proj_data_sptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) - && record.energy().get_energyA_in_keV() >= lm_data_ptr->get_exam_info_sptr()->get_low_energy_thres(0) - && record.energy().get_energyA_in_keV() <= lm_data_ptr->get_exam_info_sptr()->get_high_energy_thres(0) - && record.energy().get_energyB_in_keV() >= lm_data_ptr->get_exam_info_sptr()->get_low_energy_thres(1) - && record.energy().get_energyB_in_keV() <= lm_data_ptr->get_exam_info_sptr()->get_high_energy_thres(1)) + && record.energy().get_energyA_in_keV() >= template_proj_data_ptr->get_exam_info_sptr()->get_low_energy_thres(0) + && record.energy().get_energyA_in_keV() <= template_proj_data_ptr->get_exam_info_sptr()->get_high_energy_thres(0) + && record.energy().get_energyB_in_keV() >= template_proj_data_ptr->get_exam_info_sptr()->get_low_energy_thres(1) + && record.energy().get_energyB_in_keV() <= template_proj_data_ptr->get_exam_info_sptr()->get_high_energy_thres(1)) { + std::cout<< "energy A new: " << record.energy().get_energyA_in_keV()<< '\n'; std::cout<< "energy B new: " << record.energy().get_energyB_in_keV() << '\n'; assert(bin.view_num()>=proj_data_sptr->get_min_view_num()); From e4e785783f086a4c263661c60bd9f58749099fdd Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Mon, 19 Oct 2020 16:26:26 -0400 Subject: [PATCH 267/274] listmode correct --- src/listmode_buildblock/LmToProjData.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/listmode_buildblock/LmToProjData.cxx b/src/listmode_buildblock/LmToProjData.cxx index 1dd8e501a5..4e14bd6daa 100644 --- a/src/listmode_buildblock/LmToProjData.cxx +++ b/src/listmode_buildblock/LmToProjData.cxx @@ -664,7 +664,7 @@ process_data() // set value in case the event decoder doesn't touch it // otherwise it would be 0 and all events will be ignored bin.set_bin_value(1); - get_bin_from_event(bin, record.event()); + get_bin_from_event(bin, record.event(), template_proj_data_ptr->get_exam_info_sptr()->get_energy_window_pair()); // check if it's inside the range we want to store if (bin.get_bin_value()>0 @@ -672,10 +672,10 @@ process_data() && bin.tangential_pos_num()<= proj_data_sptr->get_max_tangential_pos_num() && bin.axial_pos_num()>=proj_data_sptr->get_min_axial_pos_num(bin.segment_num()) && bin.axial_pos_num()<=proj_data_sptr->get_max_axial_pos_num(bin.segment_num()) - && record.energy().get_energyA_in_keV() >= template_proj_data_ptr->get_exam_info_sptr()->get_low_energy_thres(0) - && record.energy().get_energyA_in_keV() <= template_proj_data_ptr->get_exam_info_sptr()->get_high_energy_thres(0) - && record.energy().get_energyB_in_keV() >= template_proj_data_ptr->get_exam_info_sptr()->get_low_energy_thres(1) - && record.energy().get_energyB_in_keV() <= template_proj_data_ptr->get_exam_info_sptr()->get_high_energy_thres(1)) + && record.energy().get_energyA_in_keV() >= template_proj_data_ptr->get_exam_info_sptr()->get_low_energy_thres(bin.first_energy_window_num()-1) + && record.energy().get_energyA_in_keV() <= template_proj_data_ptr->get_exam_info_sptr()->get_high_energy_thres(bin.first_energy_window_num()-1) + && record.energy().get_energyB_in_keV() >= template_proj_data_ptr->get_exam_info_sptr()->get_low_energy_thres(bin.second_energy_window_num()-1) + && record.energy().get_energyB_in_keV() <= template_proj_data_ptr->get_exam_info_sptr()->get_high_energy_thres(bin.second_energy_window_num()-1)) { std::cout<< "energy A new: " << record.energy().get_energyA_in_keV()<< '\n'; From 38410b80cd70c8b135cccf4bee7642e1928a8cdb Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 20 Oct 2020 13:30:39 -0400 Subject: [PATCH 268/274] removed dependency on listenergy --- src/include/stir/listmode/CListRecordGEHDF5.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/stir/listmode/CListRecordGEHDF5.h b/src/include/stir/listmode/CListRecordGEHDF5.h index 94033113cf..158f9d99ac 100644 --- a/src/include/stir/listmode/CListRecordGEHDF5.h +++ b/src/include/stir/listmode/CListRecordGEHDF5.h @@ -183,7 +183,7 @@ namespace RDF_HDF5 { This class essentially just forwards the work to the "basic" classes. */ - class CListEnergyDataGEHDF5: public ListEnergy + class CListEnergyDataGEHDF5 { public: bool is_energy() const From 800517e56c3492db5a28a66db0d1ba51071465f3 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Tue, 20 Oct 2020 13:48:28 -0400 Subject: [PATCH 269/274] removed unused variables for Codacy issue --- src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx index 74a75c6823..29cd9a9cca 100644 --- a/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx +++ b/src/scatter_buildblock/SingleScatterLikelihoodAndGradient.cxx @@ -565,7 +565,7 @@ get_jacobian(std::vector > &gradient_image_array,co int bin_counter = 0; int axial_bins = 0 ; - double sum = 0; + //double sum = 0; TODO : return the likelihood rather than estimated projdata // #ifdef STIR_OPENMP // #pragma omp parallel for reduction(+:axial_bins) schedule(dynamic) From 7ac2ab8784fc466f1ad7a3f8cb17874ec73db86f Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 21 Oct 2020 14:10:51 -0400 Subject: [PATCH 270/274] codacy unused variables --- src/buildblock/extend_projdata.cxx | 10 +++++----- src/buildblock/interpolate_projdata.cxx | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index 2e69d83df3..ea39c7c67b 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -137,22 +137,22 @@ namespace detail const float min_view_compression, const float max_view_compression) { //* Check if projdata are from 0 to pi-phi - bool min_is_compressed=false; - bool max_is_compressed=false; + //bool min_is_compressed=false; + //bool max_is_compressed=false; BasicCoordinate<2,int> min_in, max_in; if (!sino_segment.get_regular_range(min_in, max_in)) { warning("input segment 0 should have a regular range"); } - const int org_min_view_num=min_in[1]; - const int org_max_view_num=max_in[1]; + //const int org_min_view_num=min_in[1]; + // const int org_max_view_num=max_in[1]; min_in[1]+=min_view_compression; //here the new min is bigger than the original max_in[1]-=max_view_compression; //here the new max is smaller than the original const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); - const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); + //const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); const float sampling_phi = proj_data_info.get_phi(Bin(0,1,0,0)) - min_phi; diff --git a/src/buildblock/interpolate_projdata.cxx b/src/buildblock/interpolate_projdata.cxx index 476faa4368..bf5e7dee9b 100644 --- a/src/buildblock/interpolate_projdata.cxx +++ b/src/buildblock/interpolate_projdata.cxx @@ -192,7 +192,7 @@ namespace detail_interpolate_projdata if (out_sinogram.get_num_views() != in_sinogram.get_num_views()/2) error("views need to be reduced of a factor 2"); - const int in_num_views = in_sinogram.get_num_views(); + //const int in_num_views = in_sinogram.get_num_views(); const int out_num_views = out_sinogram.get_num_views(); for (int view_num = in_sinogram.get_min_view_num()+1; @@ -589,7 +589,7 @@ interpolate_projdata_push(ProjData& proj_data_out, { - SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; + //SegmentBySinogram sino_3D_out = proj_data_out.get_empty_segment_by_sinogram(0) ; if (use_view_offset) warning("interpolate_projdata with use_view_offset is EXPERIMENTAL and NOT TESTED."); From 0c9dea48be5abd380b4db23518da0ce3c96c9a31 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 21 Oct 2020 14:26:28 -0400 Subject: [PATCH 271/274] removed comment lines --- src/buildblock/extend_projdata.cxx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/buildblock/extend_projdata.cxx b/src/buildblock/extend_projdata.cxx index ea39c7c67b..8124181936 100644 --- a/src/buildblock/extend_projdata.cxx +++ b/src/buildblock/extend_projdata.cxx @@ -137,22 +137,18 @@ namespace detail const float min_view_compression, const float max_view_compression) { //* Check if projdata are from 0 to pi-phi - //bool min_is_compressed=false; - //bool max_is_compressed=false; + BasicCoordinate<2,int> min_in, max_in; if (!sino_segment.get_regular_range(min_in, max_in)) { warning("input segment 0 should have a regular range"); } - //const int org_min_view_num=min_in[1]; - // const int org_max_view_num=max_in[1]; min_in[1]+=min_view_compression; //here the new min is bigger than the original max_in[1]-=max_view_compression; //here the new max is smaller than the original const float min_phi = proj_data_info.get_phi(Bin(0,0,0,0)); - //const float max_phi = proj_data_info.get_phi(Bin(0,max_in[1],0,0)); const float sampling_phi = proj_data_info.get_phi(Bin(0,1,0,0)) - min_phi; From 044b891d487eff2ea43fb04b78a3866a21884f2c Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Wed, 21 Oct 2020 14:47:38 -0400 Subject: [PATCH 272/274] fixed stirextra.py for codicy --- src/swig/stirextra.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/swig/stirextra.py b/src/swig/stirextra.py index e8b0ee3dc1..b6fd41ec13 100644 --- a/src/swig/stirextra.py +++ b/src/swig/stirextra.py @@ -35,7 +35,6 @@ def get_bounding_box_indices(image): maxind=stir.Int3BasicCoordinate() else: raise exceptions.NotImplementedError('need to handle dimensions different from 2 and 3') - image.get_regular_range(minind, maxind); return [minind, maxind] From 33f646e776f6f526991227ddc1d6cca931f94227 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Fri, 23 Oct 2020 22:27:41 -0400 Subject: [PATCH 273/274] hdf5 fix --- src/include/stir/listmode/CListRecordGEHDF5.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/include/stir/listmode/CListRecordGEHDF5.h b/src/include/stir/listmode/CListRecordGEHDF5.h index 158f9d99ac..16b198deaa 100644 --- a/src/include/stir/listmode/CListRecordGEHDF5.h +++ b/src/include/stir/listmode/CListRecordGEHDF5.h @@ -186,12 +186,6 @@ namespace RDF_HDF5 { class CListEnergyDataGEHDF5 { public: - bool is_energy() const - {return true; } - inline double get_energyA_in_keV() const - { return 0.F; } - inline double get_energyB_in_keV() const - { return 0.F; } }; class CListRecordGEHDF5 : public CListRecord, public ListTime, public ListEnergy, // public CListGatingInput, @@ -257,6 +251,12 @@ dynamic_cast(&e2) != 0 && #endif } + // energy + inline double get_energyA_in_keV() const + { return 0.F; } + inline double get_energyB_in_keV() const + { return 0.F; } + // time inline unsigned long get_time_in_millisecs() const { return time_data.get_time_in_millisecs() - first_time_stamp; } From 038caf84abd41e80612a79f40688d78afab72178 Mon Sep 17 00:00:00 2001 From: Ludovica Brusaferri Date: Sat, 24 Oct 2020 16:44:40 -0400 Subject: [PATCH 274/274] _PI --- src/scatter_buildblock/scatter_detection_modelling.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index 47d390c30c..40ef95ff52 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -241,7 +241,7 @@ float ScatterSimulation:: exponential_tail(const float K, const float std_peak, const float x, const float energy, const float beta) const { - const float den1 = 1.4142f*M_PI*std_peak*beta; + const float den1 = 1.4142f*_PI*std_peak*beta; const float den2 = 1.4142f*std_peak; const float den3 = 2*beta; if (x > 210) //i am not sure of the behaviour of the function at too low energies