SIRF  3.6.0
stir_x.h
Go to the documentation of this file.
1 /*
2 SyneRBI Synergistic Image Reconstruction Framework (SIRF)
3 Copyright 2015 - 2021 Rutherford Appleton Laboratory STFC
4 Copyright 2019 - 2021 University College London
5 
6 This is software developed for the Collaborative Computational
7 Project in Synergistic Reconstruction for Biomedical Imaging (formerly CCP PETMR)
8 (http://www.ccpsynerbi.ac.uk/).
9 
10 Licensed under the Apache License, Version 2.0 (the "License");
11 you may not use this file except in compliance with the License.
12 You may obtain a copy of the License at
13 http://www.apache.org/licenses/LICENSE-2.0
14 Unless required by applicable law or agreed to in writing, software
15 distributed under the License is distributed on an "AS IS" BASIS,
16 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 See the License for the specific language governing permissions and
18 limitations under the License.
19 
20 */
21 
22 #ifndef EXTRA_STIR_TYPES
23 #define EXTRA_STIR_TYPES
24 
25 #define WIN32_LEAN_AND_MEAN
26 
36 #include <cmath>
37 #include <stdlib.h>
38 
39 #include "sirf/common/iequals.h"
40 #include "sirf/common/JacobiCG.h"
42 #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndProjData.h"
43 
44 #define MIN_BIN_EFFICIENCY 1.0e-20f
45 //#define MIN_BIN_EFFICIENCY 1.0e-6f
46 #define SIRF_DYNAMIC_CAST(T, X, Y) T& X = dynamic_cast<T&>(Y)
47 
48 namespace sirf {
49 
83  class ListmodeToSinograms : public stir::LmToProjData {
84  public:
86 
95  //ListmodeToSinograms(const char* const par) : stir::LmToProjData(par) {}
96  ListmodeToSinograms(const char* par) : stir::LmToProjData(par) {}
97  ListmodeToSinograms() : stir::LmToProjData()
98  {
99  set_defaults();
100  fan_size = -1;
101  store_prompts = true;
102  store_delayeds = false;
103  delayed_increment = 0;
104  num_iterations = 10;
105  display_interval = 1;
106  KL_interval = 1;
107  save_interval = -1;
108  //num_events_to_store = -1;
109  }
110  void set_input(std::string lm_file)
111  {
112  input_filename = lm_file;
113  lm_data_ptr = stir::read_from_file<ListModeData>(input_filename);
114  exam_info_sptr_.reset(new ExamInfo(lm_data_ptr->get_exam_info()));
115  proj_data_info_sptr_.reset(lm_data_ptr->get_proj_data_info_sptr()->clone());
116  }
118 
120  void set_output(std::string proj_data_file)
121  {
122  output_filename_prefix = proj_data_file;
123  }
124  void set_template(std::string proj_data_file)
125  {
126  STIRAcquisitionDataInFile acq_data_template(proj_data_file.c_str());
127  set_template(acq_data_template);
128  }
129  void set_template(const STIRAcquisitionData& acq_data_template)
130  {
131  template_proj_data_info_ptr =
132  acq_data_template.get_proj_data_info_sptr()->create_shared_clone();
133  }
134  void set_time_interval(double start, double stop)
135  {
136  std::pair<double, double> interval(start, stop);
137  std::vector < std::pair<double, double> > intervals;
138  intervals.push_back(interval);
139  frame_defs = stir::TimeFrameDefinitions(intervals);
140  do_time_frame = true;
141  }
142  int set_flag(const char* flag, bool value)
143  {
144  if (sirf::iequals(flag, "store_prompts"))
145  store_prompts = value;
146  else if (sirf::iequals(flag, "store_delayeds"))
147  store_delayeds = value;
148 #if 0
149  else if (sirf::iequals(flag, "do_pre_normalisation"))
150  do_pre_normalisation = value;
151  else if (sirf::iequals(flag, "do_time_frame"))
152  do_time_frame = value;
153 #endif
154  else if (sirf::iequals(flag, "interactive"))
155  interactive = value;
156  else
157  return -1;
158  return 0;
159  }
160  bool get_store_prompts() const
161  {
162  return store_prompts;
163  }
164  bool get_store_delayeds() const
165  {
166  return store_delayeds;
167  }
168  virtual stir::Succeeded set_up()
169  {
170  if (LmToProjData::set_up() == Succeeded::no)
171  THROW("LmToProjData setup failed");
172  fan_size = -1;
173 #if STIR_VERSION < 060000
174  const auto max_fan_size =
175  lm_data_ptr->get_scanner_ptr()->get_max_num_non_arccorrected_bins();
176 #else
177  const auto max_fan_size =
178  lm_data_ptr->get_scanner().get_max_num_non_arccorrected_bins();
179 #endif
180  if (fan_size == -1)
181  fan_size = max_fan_size;
182  else
183  fan_size =
184  std::min(fan_size, max_fan_size);
185  half_fan_size = fan_size / 2;
186  fan_size = 2 * half_fan_size + 1;
187 
188  exam_info_sptr_->set_time_frame_definitions(frame_defs);
189  const float h = proj_data_info_sptr_->get_bed_position_horizontal();
190  const float v = proj_data_info_sptr_->get_bed_position_vertical();
191  stir::shared_ptr<ProjDataInfo> temp_proj_data_info_sptr(template_proj_data_info_ptr->clone());
192  temp_proj_data_info_sptr->set_bed_position_horizontal(h);
193  temp_proj_data_info_sptr->set_bed_position_vertical(v);
194  randoms_sptr.reset(new STIRAcquisitionDataInMemory(exam_info_sptr_, temp_proj_data_info_sptr));
195 
196  return stir::Succeeded::yes;
197  }
198  int estimate_randoms();
199  void save_randoms()
200  {
201  std::string filename = output_filename_prefix + "_randoms" + "_f1g1d0b0.hs";
202  randoms_sptr->write(filename.c_str());
203  }
204  std::shared_ptr<STIRAcquisitionData> get_output()
205  {
206  std::string filename = output_filename_prefix + "_f1g1d0b0.hs";
207  return std::shared_ptr<STIRAcquisitionData>
208  (new STIRAcquisitionDataInFile(filename.c_str()));
209  }
210  std::shared_ptr<STIRAcquisitionData> get_randoms_sptr()
211  {
212  return randoms_sptr;
213  }
216  float get_time_at_which_num_prompts_exceeds_threshold(const unsigned long threshold) const;
217 
218  protected:
219  // variables for ML estimation of singles/randoms
220  int fan_size;
221  int half_fan_size;
222  int max_ring_diff_for_fansums;
223  int num_iterations;
224  int display_interval;
225  int KL_interval;
226  int save_interval;
227  stir::shared_ptr<ExamInfo> exam_info_sptr_;
228  stir::shared_ptr<ProjDataInfo> proj_data_info_sptr_;
229  stir::shared_ptr<std::vector<stir::Array<2, float> > > fan_sums_sptr;
230  stir::shared_ptr<stir::DetectorEfficiencies> det_eff_sptr;
231  std::shared_ptr<STIRAcquisitionData> randoms_sptr;
232  void compute_fan_sums_(bool prompt_fansum = false);
233  int compute_singles_();
234 // void estimate_randoms_();
235  static unsigned long compute_num_bins_(const int num_rings,
236  const int num_detectors_per_ring,
237  const int max_ring_diff, const int half_fan_size);
238  };
239 
247  public:
249  // create from bin (detector pair) efficiencies sinograms
251  // create from ECAT8
252  PETAcquisitionSensitivityModel(std::string filename);
253  // chain two normalizations
256  {
257  norm_.reset(new stir::ChainedBinNormalisation(mod1.data(), mod2.data()));
258  }
259 
260  void set_up(const stir::shared_ptr<const stir::ExamInfo>& exam_info_sptr,
261  const stir::shared_ptr<stir::ProjDataInfo>&);
262 
263  // multiply by bin efficiencies
264  virtual void unnormalise(STIRAcquisitionData& ad) const;
265  // divide by bin efficiencies
266  virtual void normalise(STIRAcquisitionData& ad) const;
267  // same as apply, but returns new data rather than changes old one
268  std::shared_ptr<STIRAcquisitionData> forward(const STIRAcquisitionData& ad) const
269  {
270  std::shared_ptr<STIRAcquisitionData> sptr_ad = ad.new_acquisition_data();
271  sptr_ad->fill(ad);
272  this->unnormalise(*sptr_ad);
273  return sptr_ad;
274  }
275  // same as undo, but returns new data rather than changes old one
276  std::shared_ptr<STIRAcquisitionData> invert(const STIRAcquisitionData& ad) const
277  {
278  std::shared_ptr<STIRAcquisitionData> sptr_ad = ad.new_acquisition_data();
279  sptr_ad->fill(ad);
280  this->normalise(*sptr_ad);
281  return sptr_ad;
282  }
283 
284  stir::shared_ptr<stir::BinNormalisation> data()
285  {
286  return norm_;
287  //return std::dynamic_pointer_cast<stir::BinNormalisation>(norm_);
288  }
289 
290  protected:
291  stir::shared_ptr<stir::BinNormalisation> norm_;
292  //shared_ptr<stir::ChainedBinNormalisation> norm_;
293  };
294 
295 
302  typedef DataProcessor3DF ImageDataProcessor;
303 
350  public:
358  class BFOperator : public Operator<STIRImageData> {
359  public:
360  BFOperator(const PETAcquisitionModel& am) : sptr_am_(am.linear_acq_mod_sptr()) {}
361  void set_subset(int sub_num)
362  {
363  sub_num_ = sub_num;
364  }
365  void set_num_subsets(int num_sub)
366  {
367  num_sub_ = num_sub;
368  }
369  virtual std::shared_ptr<STIRImageData> apply(const STIRImageData& image_data)
370  {
371  std::shared_ptr<STIRAcquisitionData> sptr_fwd =
372  sptr_am_->forward(image_data, sub_num_, num_sub_); // , true);
373  std::shared_ptr<STIRImageData> sptr_bwd =
374  sptr_am_->backward(*sptr_fwd, sub_num_, num_sub_);
375  return sptr_bwd;
376  }
377  private:
378  std::shared_ptr<const PETAcquisitionModel> sptr_am_;
379  int sub_num_ = 0;
380  int num_sub_ = 1;
381  };
382 
391  float norm(int subset_num = 0, int num_subsets = 1, int num_iter = 2, int verb = 0) const
392  {
393  BFOperator bf(*this);
394  bf.set_subset(subset_num);
395  bf.set_num_subsets(num_subsets);
396  JacobiCG<float> jcg;
397  jcg.set_num_iterations(num_iter);
398  STIRImageData image_data = *sptr_image_template_->clone();
399  image_data.fill(1.0);
400  float lmd = jcg.largest(bf, image_data, verb);
401  return std::sqrt(lmd);
402  }
403 
404  void set_projectors(stir::shared_ptr<stir::ProjectorByBinPair> sptr_projectors)
405  {
406  sptr_projectors_ = sptr_projectors;
407  }
408  const stir::shared_ptr<stir::ProjectorByBinPair> projectors_sptr() const
409  {
410  return sptr_projectors_;
411  }
412  void set_additive_term(std::shared_ptr<STIRAcquisitionData> sptr)
413  {
414  sptr_add_ = sptr;
415  }
416  std::shared_ptr<const STIRAcquisitionData> additive_term_sptr() const
417  {
418  return sptr_add_;
419  }
420  void set_background_term(std::shared_ptr<STIRAcquisitionData> sptr)
421  {
422  sptr_background_ = sptr;
423  }
424  std::shared_ptr<const STIRAcquisitionData> background_term_sptr() const
425  {
426  return sptr_background_;
427  }
428  std::shared_ptr<const STIRAcquisitionData> acq_template_sptr() const
429  {
430  return sptr_acq_template_;
431  }
432  std::shared_ptr<const STIRImageData> image_template_sptr() const
433  {
434  return sptr_image_template_;
435  }
436  //void set_normalisation(shared_ptr<stir::BinNormalisation> sptr)
437  //{
438  // sptr_normalisation_ = sptr;
439  //}
440  const stir::shared_ptr<stir::BinNormalisation> normalisation_sptr() const
441  {
442  if (sptr_asm_.get())
443  return sptr_asm_->data();
444  stir::shared_ptr<stir::BinNormalisation> sptr;
445  return sptr;
446  //return sptr_normalisation_;
447  }
448  //void set_bin_efficiency(shared_ptr<STIRAcquisitionData> sptr_data);
449  //void set_normalisation(shared_ptr<STIRAcquisitionData> sptr_data)
450  //{
451  // sptr_normalisation_.reset(new stir::BinNormalisationFromProjData(*sptr_data));
452  //}
453  void set_asm(std::shared_ptr<PETAcquisitionSensitivityModel> sptr_asm)
454  {
455  //sptr_normalisation_ = sptr_asm->data();
456  sptr_asm_ = sptr_asm;
457  }
458  stir::shared_ptr<PETAcquisitionSensitivityModel> asm_sptr() const
459  {
460  return sptr_asm_;
461  }
462 
464 
466  void set_image_data_processor(stir::shared_ptr<ImageDataProcessor> sptr_processor);
467  void cancel_background_term()
468  {
469  sptr_background_.reset();
470  }
471  void cancel_additive_term()
472  {
473  sptr_add_.reset();
474  }
475  void cancel_normalisation()
476  {
477  sptr_asm_.reset();
478  //sptr_normalisation_.reset();
479  }
480  std::shared_ptr<const PETAcquisitionModel> linear_acq_mod_sptr() const
481  {
482  std::shared_ptr<PETAcquisitionModel> sptr_am(new PETAcquisitionModel);
483  sptr_am->set_projectors(sptr_projectors_);
484  sptr_am->set_asm(sptr_asm_);
485  sptr_am->sptr_acq_template_ = sptr_acq_template_;
486  sptr_am->sptr_image_template_ = sptr_image_template_;
487  return sptr_am;
488  }
489 
490  virtual void set_up(
491  std::shared_ptr<STIRAcquisitionData> sptr_acq,
492  std::shared_ptr<STIRImageData> sptr_image);
493 
497  std::shared_ptr<STIRAcquisitionData>
498  forward(const STIRImageData& image,
499  int subset_num = 0, int num_subsets = 1, bool do_linear_only = false) const;
510  void forward(STIRAcquisitionData& acq_data, const STIRImageData& image,
511  int subset_num, int num_subsets, bool zero = false, bool do_linear_only = false) const;
512 
513  // computes and returns back-projected subset of acquisition data
514  std::shared_ptr<STIRImageData> backward(const STIRAcquisitionData& ad,
515  int subset_num = 0, int num_subsets = 1) const;
516  // puts back-projected subset of acquisition data into image
517  void backward(STIRImageData& image, const STIRAcquisitionData& ad,
518  int subset_num = 0, int num_subsets = 1) const;
519 
520  protected:
521  stir::shared_ptr<stir::ProjectorByBinPair> sptr_projectors_;
522  std::shared_ptr<STIRAcquisitionData> sptr_acq_template_;
523  std::shared_ptr<STIRImageData> sptr_image_template_;
524  std::shared_ptr<STIRAcquisitionData> sptr_add_;
525  std::shared_ptr<STIRAcquisitionData> sptr_background_;
526  std::shared_ptr<PETAcquisitionSensitivityModel> sptr_asm_;
527  //shared_ptr<stir::BinNormalisation> sptr_normalisation_;
528  };
529 
542  class PETSingleScatterSimulator : public stir::SingleScatterSimulation
543  {
544  public:
546  PETSingleScatterSimulator() : stir::SingleScatterSimulation()
547  {}
549  PETSingleScatterSimulator(std::string filename) :
550  stir::SingleScatterSimulation(filename)
551  {}
552 
553  void set_up(std::shared_ptr<const STIRAcquisitionData> sptr_acq_template,
554  std::shared_ptr<const STIRImageData> sptr_act_image_template)
555  {
556  this->sptr_acq_template_ = sptr_acq_template;
557 
558  stir::SingleScatterSimulation::set_template_proj_data_info(
559  *sptr_acq_template_->get_proj_data_info_sptr());
560  stir::SingleScatterSimulation::set_exam_info(
561  *sptr_acq_template_->get_exam_info_sptr());
562  // check if attenuation image is set
563  try
564  {
565  auto& tmp = stir::SingleScatterSimulation::get_attenuation_image();
566  }
567  catch (...)
568  {
569  THROW("Fatal error in PETSingleScatterSimulator::set_up: attenuation_image has not been set");
570  }
571  this->set_activity_image_sptr(sptr_act_image_template);
572 
573  if (stir::SingleScatterSimulation::set_up() == Succeeded::no)
574  THROW("Fatal error in PETSingleScatterSimulator::set_up() failed.");
575  }
576 
577  void set_activity_image_sptr(std::shared_ptr<const STIRImageData> arg)
578  {
579 #if STIR_VERSION < 050000
580  // need to make a copy as the function doesn't accept a const
581  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
582  stir::SingleScatterSimulation::set_activity_image_sptr(sptr_image_copy);
583 #else
584  stir::SingleScatterSimulation::set_activity_image_sptr(arg->data_sptr());
585 #endif
586  }
587 
588  void set_attenuation_image_sptr(std::shared_ptr<const STIRImageData> arg)
589  {
590 #if STIR_VERSION < 050000
591  // need to make a copy as the function doesn't accept a const
592  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
593  stir::SingleScatterSimulation::set_density_image_sptr(sptr_image_copy);
594 #else
595  stir::SingleScatterSimulation::set_density_image_sptr(arg->data_sptr());
596 #endif
597  }
598 
599  std::shared_ptr<STIRAcquisitionData> forward(const STIRImageData& activity_img) /*TODO CONST*/
600  {
601  if (!sptr_acq_template_.get())
602  THROW("Fatal error in PETSingleScatterSimulator::forward: acquisition template not set");
603  std::shared_ptr<STIRAcquisitionData> sptr_ad =
604  sptr_acq_template_->new_acquisition_data();
605  this->forward( *sptr_ad, activity_img);
606  return sptr_ad;
607  }
608 
609  void forward(STIRAcquisitionData& ad, const STIRImageData& activity_img) /* TODO CONST*/
610  {
611  stir::shared_ptr<ProjData> sptr_fd = ad.data();
612  this->set_output_proj_data_sptr(sptr_fd);
613  // hopefully STIR checks if template consistent with input data
614  this->process_data();
615  }
616 
617  protected:
618  std::shared_ptr<const STIRAcquisitionData> sptr_acq_template_;
619 
620  };
621 
634  class PETScatterEstimator : private stir::ScatterEstimation
635  {
636  using recon_type = stir::OSMAPOSLReconstruction<DiscretisedDensity<3,float>>;
637  public:
639 
644  PETScatterEstimator() : stir::ScatterEstimation()
645  {
646  auto obj_sptr = std::make_shared<PoissonLogLikelihoodWithLinearModelForMeanAndProjData<DiscretisedDensity<3,float>>>();
647  auto recon_sptr = std::make_shared<recon_type>();
648  recon_sptr->set_num_subiterations(8);
649  recon_sptr->set_num_subsets(7); // this works for the mMR. TODO
650  recon_sptr->set_disable_output(true);
651  recon_sptr->set_objective_function_sptr(obj_sptr);
652  stir::shared_ptr<stir::SeparableGaussianImageFilter<float> >
653  filter_sptr(new stir::SeparableGaussianImageFilter<float>);
654  filter_sptr->set_fwhms(stir::make_coordinate(15.F,15.F,15.F));
655  recon_sptr->set_post_processor_sptr(filter_sptr);
656  stir::ScatterEstimation::set_reconstruction_method_sptr(recon_sptr);
657  }
659  PETScatterEstimator(std::string filename) :
660  stir::ScatterEstimation(filename)
661  {}
662 
664  void set_input_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
665  {
666  stir::ScatterEstimation::set_input_proj_data_sptr(arg->data());
667  }
669  void set_attenuation_correction_factors_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
670  {
671  stir::ScatterEstimation::set_attenuation_correction_proj_data_sptr(arg->data());
672  }
674  void set_asm(std::shared_ptr<PETAcquisitionSensitivityModel> arg)
675  {
676  stir::ScatterEstimation::set_normalisation_sptr(arg->data());
677  }
679  void set_background_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
680  {
681  stir::ScatterEstimation::set_background_proj_data_sptr(arg->data());
682  }
683 
684  void set_attenuation_image_sptr(std::shared_ptr<const STIRImageData> arg)
685  {
686 #if STIR_VERSION < 050000
687  // need to make a copy as the function doesn't accept a const
688  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
689  stir::ScatterEstimation::set_attenuation_image_sptr(sptr_image_copy);
690 #else
691  stir::ScatterEstimation::set_attenuation_image_sptr(arg->data_sptr());
692 #endif
693  }
694 
696 
702  void set_output_prefix(std::string prefix)
703  {
704  stir::ScatterEstimation::set_export_scatter_estimates_of_each_iteration(!prefix.empty());
705  stir::ScatterEstimation::set_output_scatter_estimate_prefix(prefix);
706  }
707 
708  void set_num_iterations(int arg)
709  {
710  stir::ScatterEstimation::set_num_iterations(arg);
711  }
712 
713  int get_num_iterations() const
714  {
715  return stir::ScatterEstimation::get_num_iterations();
716  }
717 
718  void set_OSEM_num_subiterations(int arg)
719  {
720  this->get_reconstruction_method().set_num_subiterations(arg);
721  }
722 
723  int get_OSEM_num_subiterations() const
724  {
725  return this->get_reconstruction_method().get_num_subiterations();
726  }
727 
728  void set_OSEM_num_subsets(int arg)
729  {
730  this->get_reconstruction_method().set_num_subsets(arg);
731  this->_already_set_up_sirf = false;
732  }
733 
734  int get_OSEM_num_subsets() const
735  {
736  return this->get_reconstruction_method().get_num_subsets();
737  }
738 
739  std::shared_ptr<STIRAcquisitionData> get_scatter_estimate(int est_num = -1) const
740  {
741  if (est_num == -1) // Get the last one
742  est_num = num_scatter_iterations;
743  if (est_num == num_scatter_iterations)
744  return get_output();
745  // try to read from file
746  if (output_scatter_estimate_prefix.empty())
747  THROW("output_scatter_estimate_prefix not set, so scatter estimates were not saved to file.");
748  const std::string filename = output_scatter_estimate_prefix + "_" + std::to_string(est_num) + ".hs";
749  return std::make_shared<STIRAcquisitionDataInFile>(filename.c_str());
750  }
751 
753  std::shared_ptr<STIRAcquisitionData> get_output() const
754  {
755  auto stir_proj_data_sptr = stir::ScatterEstimation::get_output();
756  if (!stir_proj_data_sptr)
757  THROW("output not yet computed");
758  std::shared_ptr<STIRAcquisitionData> sptr_acq_data
759  (STIRAcquisitionData::storage_template()->same_acquisition_data(stir_proj_data_sptr->get_exam_info_sptr(),
760  stir_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone()));
761  sptr_acq_data->data()->fill(*stir_proj_data_sptr);
762  return sptr_acq_data;
763  }
764 
766 
772  Succeeded set_up()
773  {
774  // reconstruct an smooth image with a large voxel size
775  const float zoom = 0.2F;
776  stir::shared_ptr<Voxels3DF>
777  image_sptr(new Voxels3DF(MAKE_SHARED<stir::ExamInfo>(*this->get_input_data()->get_exam_info_sptr()),
778  *this->get_input_data()->get_proj_data_info_sptr(),
779  zoom));
780  image_sptr->fill(1.F);
781  stir::ScatterEstimation::set_initial_activity_image_sptr(image_sptr);
782  if (stir::ScatterEstimation::set_up() == Succeeded::no)
783  THROW("scatter estimation set_up failed");
784  this->_already_set_up_sirf = true;
785  return Succeeded::yes;
786  }
787  void process()
788  {
789  if (!this->_already_set_up_sirf)
790  THROW("scatter estimation needs to be set-up first");
791  if (!stir::ScatterEstimation::already_setup())
792  THROW("scatter estimation needs to be set-up first");
793  if (stir::ScatterEstimation::process_data() == Succeeded::no)
794  THROW("scatter estimation failed");
795  }
796  private:
798  bool _already_set_up_sirf;
799 
801  recon_type& get_reconstruction_method() const
802  {
803  return dynamic_cast<recon_type&>(*this->reconstruction_template_sptr);
804  }
805  };
806 
822  public:
824  {
825  this->sptr_projectors_.reset(new ProjectorPairUsingMatrix);
826  }
827  void set_matrix(stir::shared_ptr<stir::ProjMatrixByBin> sptr_matrix)
828  {
829  sptr_matrix_ = sptr_matrix;
830  ((ProjectorPairUsingMatrix*)this->sptr_projectors_.get())->
831  set_proj_matrix_sptr(sptr_matrix);
832  }
833  stir::shared_ptr<stir::ProjMatrixByBin> matrix_sptr()
834  {
835  return sptr_matrix_;
836  //return ((ProjectorPairUsingMatrix*)this->sptr_projectors_.get())->
837  // get_proj_matrix_sptr();
838  }
839  virtual void set_up(
840  std::shared_ptr<STIRAcquisitionData> sptr_acq,
841  std::shared_ptr<STIRImageData> sptr_image)
842  {
843  if (!sptr_matrix_.get())
844  THROW("PETAcquisitionModelUsingMatrix setup failed - matrix not set");
845  PETAcquisitionModel::set_up(sptr_acq, sptr_image);
846  }
847 
849  void enable_cache(bool v = true)
850  {
851  sptr_matrix_->enable_cache(v);
852  }
853 
854  private:
855  stir::shared_ptr<stir::ProjMatrixByBin> sptr_matrix_;
856  };
857 
860  public:
861  PETAcquisitionModelUsingRayTracingMatrix(int num_LORs = 2) :
863  {
864  stir::shared_ptr<RayTracingMatrix> matrix_sptr(new RayTracingMatrix);
865  matrix_sptr->set_num_tangential_LORs(num_LORs);
866  set_matrix(matrix_sptr);
867  }
868  void set_num_tangential_LORs(int num_LORs)
869  {
870  //RayTracingMatrix& matrix = (RayTracingMatrix&)*matrix_sptr();
871  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
872  //std::cout << matrix.get_num_tangential_LORs() << '\n';
873  matrix.set_num_tangential_LORs(num_LORs);
874  //std::cout << get_num_tangential_LORs() << '\n';
875  }
878  {
879  auto matrix = dynamic_cast<const RayTracingMatrix&>(*matrix_sptr());
880  return matrix.get_num_tangential_LORs();
881  }
884  {
885  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
886  matrix.set_restrict_to_cylindrical_FOV(v);
887  }
890  //bool get_do_symmetry_90degrees_min_phi() const;
891  void set_do_symmetry_90degrees_min_phi(bool v = true)
892  {
893  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
894  matrix.set_do_symmetry_90degrees_min_phi(v);
895  }
896  //bool get_do_symmetry_180degrees_min_phi() const;
897  void set_do_symmetry_180degrees_min_phi(bool v = true)
898  {
899  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
900  matrix.set_do_symmetry_180degrees_min_phi(v);
901  }
902  //bool get_do_symmetry_swap_segment() const;
903  void set_do_symmetry_swap_segment(bool v = true)
904  {
905  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
906  matrix.set_do_symmetry_swap_segment(v);
907  }
908  //bool get_do_symmetry_swap_s() const;
909  void set_do_symmetry_swap_s(bool v = true)
910  {
911  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
912  matrix.set_do_symmetry_swap_s(v);
913  }
914  //bool get_do_symmetry_shift_z() const;
915  void set_do_symmetry_shift_z(bool v = true)
916  {
917  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
918  matrix.set_do_symmetry_shift_z(v);
919  }
920  };
921 
922  typedef PETAcquisitionModel AcqMod3DF;
923  typedef PETAcquisitionModelUsingMatrix AcqModUsingMatrix3DF;
924  typedef std::shared_ptr<AcqMod3DF> sptrAcqMod3DF;
925 
926 #ifdef STIR_WITH_NiftyPET_PROJECTOR
932  class PETAcquisitionModelUsingNiftyPET : public PETAcquisitionModel {
933  public:
934  PETAcquisitionModelUsingNiftyPET()
935  {
936  _NiftyPET_projector_pair_sptr.reset(new ProjectorPairUsingNiftyPET);
937  this->sptr_projectors_ = _NiftyPET_projector_pair_sptr;
938  // Set verbosity to 0 by default
939  _NiftyPET_projector_pair_sptr->set_verbosity(0);
940  }
941  void set_cuda_verbosity(const bool verbosity) const
942  {
943  _NiftyPET_projector_pair_sptr->set_verbosity(verbosity);
944  }
945  void set_use_truncation(const bool use_truncation) const
946  {
947  _NiftyPET_projector_pair_sptr->set_use_truncation(use_truncation);
948  }
949  protected:
950  stir::shared_ptr<stir::ProjectorPairUsingNiftyPET> _NiftyPET_projector_pair_sptr;
951  };
952  typedef PETAcquisitionModelUsingNiftyPET AcqModUsingNiftyPET3DF;
953 #endif
954 
955 #ifdef STIR_WITH_Parallelproj_PROJECTOR
961  class PETAcquisitionModelUsingParallelproj : public PETAcquisitionModel {
962  public:
963  PETAcquisitionModelUsingParallelproj()
964  {
965  this->sptr_projectors_.reset(new ProjectorByBinPairUsingParallelproj);
966  }
967  };
968  typedef PETAcquisitionModelUsingParallelproj AcqModUsingParallelproj;
969 #endif
970 
978  public:
980  // multiply by bin efficiencies
981  virtual void unnormalise(STIRAcquisitionData& ad) const;
982  // divide by bin efficiencies
983  virtual void normalise(STIRAcquisitionData& ad) const;
984  protected:
985  stir::shared_ptr<stir::ForwardProjectorByBin> sptr_forw_projector_;
986  };
987 
997  class xSTIR_Box3D : public stir::Box3D {
998  public:
999  void set_length_x(float v)
1000  {
1001  length_x = v;
1002  }
1003  void set_length_y(float v)
1004  {
1005  length_y = v;
1006  }
1007  void set_length_z(float v)
1008  {
1009  length_z = v;
1010  }
1011  float get_length_x() const
1012  {
1013  return length_x;
1014  }
1015  float get_length_y() const
1016  {
1017  return length_y;
1018  }
1019  float get_length_z() const
1020  {
1021  return length_z;
1022  }
1023  };
1024 
1025  class xSTIR_GeneralisedPrior3DF : public stir::GeneralisedPrior < Image3DF > {
1026  public:
1027 // bool post_process() {
1028 // return post_processing();
1029 // }
1030  };
1031 
1032  class xSTIR_QuadraticPrior3DF : public stir::QuadraticPrior < float > {
1033  public:
1034  void only2D(int only) {
1035  only_2D = only != 0;
1036  }
1037  };
1038 
1039  class xSTIR_LogcoshPrior3DF : public stir::LogcoshPrior < float > {
1040  public:
1041  void only2D(int only) {
1042  only_2D = only != 0;
1043  }
1044  };
1045 
1046  class xSTIR_RelativeDifferencePrior3DF : public stir::RelativeDifferencePrior < float > {
1047  public:
1048  void only2D(int only) {
1049  only_2D = only != 0;
1050  }
1051  };
1052 
1053  class xSTIR_PLSPrior3DF : public stir::PLSPrior < float > {
1054  public:
1055  void only2D(int only) {
1056  only_2D = only != 0;
1057  }
1058  };
1059 
1061  public stir::GeneralisedObjectiveFunction < Image3DF > {
1062  public:
1063 // bool post_process() {
1064 // return post_processing();
1065 // }
1066  };
1067 
1068  //typedef xSTIR_GeneralisedObjectiveFunction3DF ObjectiveFunction3DF;
1069 
1071  public stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData < Image3DF > {
1072  public:
1073  void set_input_file(const char* filename) {
1074  input_filename = filename;
1075  }
1076  void set_acquisition_data(std::shared_ptr<STIRAcquisitionData> sptr)
1077  {
1078  sptr_ad_ = sptr;
1079  set_proj_data_sptr(sptr->data());
1080  }
1081  void set_acquisition_model(std::shared_ptr<AcqMod3DF> sptr_am)
1082  {
1083  sptr_am_ = sptr_am;
1084  AcqMod3DF& am = *sptr_am;
1085  auto sptr_asm = am.asm_sptr();
1086  set_projector_pair_sptr(am.projectors_sptr());
1087  bool have_a = am.additive_term_sptr().get();
1088  bool have_b = am.background_term_sptr().get();
1089  bool have_asm = sptr_asm.get();
1090  if (!have_b) {
1091  if (have_a)
1092  set_additive_proj_data_sptr(am.additive_term_sptr()->data());
1093  }
1094  else {
1095  auto sptr_b = am.background_term_sptr();
1096  stir::shared_ptr<STIRAcquisitionData> sptr;
1097  if (have_asm)
1098  sptr = sptr_asm->invert(*sptr_b);
1099  else
1100  sptr = sptr_b->clone();
1101  if (have_a) {
1102  auto sptr_a = am.additive_term_sptr();
1103  float a = 1.0f;
1104  sptr->axpby(&a, *sptr, &a, *sptr_a);
1105  }
1106  set_additive_proj_data_sptr(sptr->data());
1107  }
1108  if (am.normalisation_sptr().get())
1109  set_normalisation_sptr(am.normalisation_sptr());
1110  }
1111  std::shared_ptr<AcqMod3DF> acquisition_model_sptr()
1112  {
1113  return sptr_am_;
1114  }
1115  private:
1116  std::shared_ptr<STIRAcquisitionData> sptr_ad_;
1117  std::shared_ptr<AcqMod3DF> sptr_am_;
1118  };
1119 
1122 
1124  public stir::IterativeReconstruction < Image3DF > {
1125  public:
1126 /* bool post_process() {
1127  //std::cout << "in xSTIR_IterativeReconstruction3DF.post_process...\n";
1128  if (this->output_filename_prefix.length() < 1)
1129  this->set_output_filename_prefix("reconstructed_image");
1130  return post_processing();
1131  }*/
1132  void update(Image3DF &image) {
1133  update_estimate(image);
1134  end_of_iteration_processing(image);
1135  subiteration_num++;
1136  }
1137  void update(STIRImageData& id)
1138  {
1139  update(id.data());
1140  }
1141  void update(stir::shared_ptr<STIRImageData> sptr_id)
1142  {
1143  update(*sptr_id);
1144  }
1145  int& subiteration() {
1146  return subiteration_num;
1147  }
1148  int subiteration() const {
1149  return subiteration_num;
1150  }
1151  void set_initial_estimate_file(const char* filename) {
1152  initial_data_filename = filename;
1153  }
1154  };
1155 
1156  class xSTIR_OSMAPOSLReconstruction3DF : public stir::OSMAPOSLReconstruction< Image3DF > {
1157  public:
1158  int& subiteration() {
1159  return subiteration_num;
1160  }
1161  int subiteration() const {
1162  return subiteration_num;
1163  }
1164  };
1165 
1166  class xSTIR_KOSMAPOSLReconstruction3DF : public stir::KOSMAPOSLReconstruction< Image3DF > {
1167  public:
1168  void compute_kernelised_image_x(
1169  Image3DF& kernelised_image_out,
1170  const Image3DF& image_to_kernelise,
1171  const Image3DF& current_alpha_estimate)
1172  {
1173  compute_kernelised_image(
1174  kernelised_image_out,
1175  image_to_kernelise,
1176  current_alpha_estimate);
1177  }
1178  };
1179 
1180  class xSTIR_OSSPSReconstruction3DF : public stir::OSSPSReconstruction < Image3DF > {
1181  public:
1182  float& relaxation_parameter_value() {
1183  return relaxation_parameter;
1184  }
1185  float& relaxation_gamma_value() {
1186  return relaxation_gamma;
1187  }
1188  double& upper_bound_value() {
1189  return upper_bound;
1190  }
1191  };
1192 
1193  class xSTIR_FBP2DReconstruction : public stir::FBP2DReconstruction {
1194  public:
1196  {
1197  _is_set_up = false;
1198  }
1199  void set_input(const STIRAcquisitionData& acq)
1200  {
1201  set_input_data(acq.data());
1202  }
1203  void set_zoom(float v)
1204  {
1205  set_zoom_xy(v);
1206  _is_set_up = false;
1207  }
1208  void set_alpha_ramp(double alpha)
1209  {
1210  // does not work!
1211  //assert(alpha > 0 && alpha <= 1.0);
1212  if (!(alpha > 0 && alpha <= 1.0))
1213  throw LocalisedException
1214  ("wrong ramp filter parameter alpha", __FILE__, __LINE__);
1215  alpha_ramp = alpha;
1216  }
1217  void set_frequency_cut_off(double fc)
1218  {
1219  if (!(fc > 0 && fc <= 0.5))
1220  throw LocalisedException
1221  ("wrong frequency cut-off", __FILE__, __LINE__);
1222  fc_ramp = fc;
1223  }
1224  void set_up(std::shared_ptr<STIRImageData> sptr_id)
1225  {
1226  _sptr_image_data.reset(new STIRImageData(*sptr_id));
1227  stir::Succeeded s = stir::Reconstruction<Image3DF>::set_up(_sptr_image_data->data_sptr());
1228  if (s != stir::Succeeded::yes)
1229  THROW("stir::Reconstruction setup failed");
1230  _is_set_up = true;
1231  }
1232  void cancel_setup()
1233  {
1234  _is_set_up = false;
1235  }
1236  void process()
1237  {
1238  stir::Succeeded s = stir::Succeeded::no;
1239  if (!_is_set_up) {
1240  stir::shared_ptr<Image3DF> sptr_image(construct_target_image_ptr());
1241  _sptr_image_data.reset(new STIRImageData(sptr_image));
1242  stir::Reconstruction<Image3DF>::set_up(sptr_image);
1243  s = reconstruct(sptr_image);
1244  }
1245  else
1246  s = reconstruct(_sptr_image_data->data_sptr());
1247  if (s != stir::Succeeded::yes)
1248  THROW("stir::AnalyticReconstruction::reconstruct failed");
1249  }
1250  std::shared_ptr<STIRImageData> get_output()
1251  {
1252  return _sptr_image_data;
1253  }
1254  protected:
1255  bool _is_set_up;
1256  std::shared_ptr<STIRImageData> _sptr_image_data;
1257  };
1258 
1260  public stir::SeparableGaussianImageFilter<float> {
1261  public:
1262  //stir::Succeeded set_up(const STIRImageData& id)
1263  //{
1264  // return virtual_set_up(id.data());
1265  //}
1266  //void apply(STIRImageData& id)
1267  //{
1268  // virtual_apply(id.data());
1269  //}
1270  void set_fwhms_xyz(char xyz, float f)
1271  {
1272  stir::BasicCoordinate<3, float> v = get_fwhms();
1273  switch (xyz) {
1274  case 'z':
1275  v[1] = f;
1276  break;
1277  case 'y':
1278  v[2] = f;
1279  break;
1280  case 'x':
1281  v[3] = f;
1282  }
1283  set_fwhms(v);
1284  }
1285  void set_max_kernel_sizes_xyz(char xyz, int s)
1286  {
1287  stir::BasicCoordinate<3, int> v = get_max_kernel_sizes();
1288  switch (xyz) {
1289  case 'z':
1290  v[1] = s;
1291  break;
1292  case 'y':
1293  v[2] = s;
1294  break;
1295  case 'x':
1296  v[3] = s;
1297  }
1298  set_max_kernel_sizes(v);
1299  }
1300  };
1301 }
1302 
1303 #endif
Definition: LocalisedException.h:32
Definition: JacobiCG.h:37
Listmode-to-sinograms converter.
Definition: stir_x.h:83
void set_output(std::string proj_data_file)
Specifies the prefix for the output file(s),.
Definition: stir_x.h:120
float get_time_at_which_num_prompts_exceeds_threshold(const unsigned long threshold) const
Definition: stir_x.cpp:53
ListmodeToSinograms(const char *par)
Constructor.
Definition: stir_x.h:96
Definition: Operator.h:7
Class for the product of backward and forward projectors of a PET acquisition model.
Definition: stir_x.h:358
Class for a PET acquisition model.
Definition: stir_x.h:349
void set_image_data_processor(stir::shared_ptr< ImageDataProcessor > sptr_processor)
sets data processor to use on the image before forward projection and after back projection
Definition: stir_x.cpp:510
std::shared_ptr< STIRAcquisitionData > forward(const STIRImageData &image, int subset_num=0, int num_subsets=1, bool do_linear_only=false) const
computes and returns a subset of forward-projected data
Definition: stir_x.cpp:558
float norm(int subset_num=0, int num_subsets=1, int num_iter=2, int verb=0) const
Method computing the norm of the linear part S G of the PET acquisition model operator F.
Definition: stir_x.h:391
Ray tracing matrix implementation of the PET acquisition model.
Definition: stir_x.h:821
void enable_cache(bool v=true)
Enables or disables the caching mechanism.
Definition: stir_x.h:849
int get_num_tangential_LORs()
@
Definition: stir_x.h:877
void set_restrict_to_cylindrical_FOV(bool v=true)
Enables or disables using a circular axial FOV (vs rectangular)
Definition: stir_x.h:883
Class for PET scanner detector efficiencies model.
Definition: stir_x.h:246
Attenuation model.
Definition: stir_x.h:977
Class for estimating the scatter contribution in PET projection data.
Definition: stir_x.h:635
void set_attenuation_correction_factors_sptr(std::shared_ptr< const STIRAcquisitionData > arg)
Set attenuation correction factors as acq_data.
Definition: stir_x.h:669
PETScatterEstimator()
constructor.
Definition: stir_x.h:644
void set_input_sptr(std::shared_ptr< const STIRAcquisitionData > arg)
Set the input data.
Definition: stir_x.h:664
std::shared_ptr< STIRAcquisitionData > get_output() const
get last scatter estimate
Definition: stir_x.h:753
void set_background_sptr(std::shared_ptr< const STIRAcquisitionData > arg)
Set the background data (normally equal to the randoms in PET)
Definition: stir_x.h:679
Succeeded set_up()
set up the object and performs checks
Definition: stir_x.h:772
void set_asm(std::shared_ptr< PETAcquisitionSensitivityModel > arg)
Set acquisition sensitivity model specifying detection efficiencies (without attenuation)
Definition: stir_x.h:674
void set_output_prefix(std::string prefix)
Set prefix for filenames with scatter estimates.
Definition: stir_x.h:702
PETScatterEstimator(std::string filename)
Overloaded constructor which takes the parameter file.
Definition: stir_x.h:659
Class for simulating the scatter contribution to PET data.
Definition: stir_x.h:543
PETSingleScatterSimulator(std::string filename)
Overloaded constructor which takes the parameter file.
Definition: stir_x.h:549
PETSingleScatterSimulator()
Default constructor.
Definition: stir_x.h:546
STIR ProjData wrapper with added functionality.
Definition: stir_data_containers.h:148
In-file implementation of STIRAcquisitionData.
Definition: stir_data_containers.h:503
STIR DiscretisedDensity<3, float> wrapper with added functionality.
Definition: stir_data_containers.h:875
Accessor classes.
Definition: stir_x.h:997
Definition: stir_x.h:1193
Definition: stir_x.h:1025
Definition: stir_x.h:1039
Definition: stir_x.h:1156
Definition: stir_x.h:1180
Definition: stir_x.h:1053
Definition: stir_x.h:1032
Defines sirf::iequals.
Abstract data container.
Definition: GeometricalInfo.cpp:141
bool iequals(const std::string &a, const std::string &b)
Case insensitive string comparison, replaces boost::iequals.
Definition: iequals.cpp:7
DataProcessor3DF ImageDataProcessor
A typedef to use SIRF terminology for DataProcessors.
Definition: stir_x.h:302
Specification file for data handling types not present in STIR.