SIRF  3.7.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, 2024 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 #include "stir/recon_buildblock/PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin.h"
44 
45 #define MIN_BIN_EFFICIENCY 1.0e-20f
46 //#define MIN_BIN_EFFICIENCY 1.0e-6f
47 #define SIRF_DYNAMIC_CAST(T, X, Y) T& X = dynamic_cast<T&>(Y)
48 
49 namespace sirf {
50 
84  class ListmodeToSinograms : public stir::LmToProjData {
85  public:
87 
96  //ListmodeToSinograms(const char* const par) : stir::LmToProjData(par) {}
97  ListmodeToSinograms(const char* par) : stir::LmToProjData(par) {}
98  ListmodeToSinograms() : stir::LmToProjData()
99  {
100  set_defaults();
101  fan_size = -1;
102  store_prompts = true;
103  store_delayeds = false;
104  delayed_increment = 0;
105  num_iterations = 10;
106  display_interval = 1;
107  KL_interval = 1;
108  save_interval = -1;
109  //num_events_to_store = -1;
110  }
111  void set_input(const STIRListmodeData& lm_data_v)
112  {
113  input_filename = "UNKNOWN";
114  // call stir::LmToProjData::set_input_data
115  this->set_input_data(lm_data_v.data());
116  exam_info_sptr_.reset(new ExamInfo(lm_data_ptr->get_exam_info()));
117  proj_data_info_sptr_.reset(lm_data_ptr->get_proj_data_info_sptr()->clone());
118  }
119  void set_input(std::string lm_file)
120  {
121  this->set_input(STIRListmodeData(lm_file));
122  this->input_filename = lm_file;
123  }
125 
127  void set_output(std::string proj_data_file)
128  {
129  output_filename_prefix = proj_data_file;
130  }
131  void set_template(std::string proj_data_file)
132  {
133  STIRAcquisitionDataInFile acq_data_template(proj_data_file.c_str());
134  set_template(acq_data_template);
135  }
136  void set_template(const STIRAcquisitionData& acq_data_template)
137  {
138  template_proj_data_info_ptr =
139  acq_data_template.get_proj_data_info_sptr()->create_shared_clone();
140  }
141  void set_time_interval(double start, double stop)
142  {
143  std::pair<double, double> interval(start, stop);
144  std::vector < std::pair<double, double> > intervals;
145  intervals.push_back(interval);
146  frame_defs = stir::TimeFrameDefinitions(intervals);
147  do_time_frame = true;
148  }
149  int set_flag(const char* flag, bool value)
150  {
151  if (sirf::iequals(flag, "store_prompts"))
152  store_prompts = value;
153  else if (sirf::iequals(flag, "store_delayeds"))
154  store_delayeds = value;
155 #if 0
156  else if (sirf::iequals(flag, "do_pre_normalisation"))
157  do_pre_normalisation = value;
158  else if (sirf::iequals(flag, "do_time_frame"))
159  do_time_frame = value;
160 #endif
161  else if (sirf::iequals(flag, "interactive"))
162  interactive = value;
163  else
164  return -1;
165  return 0;
166  }
167  bool get_store_prompts() const
168  {
169  return store_prompts;
170  }
171  bool get_store_delayeds() const
172  {
173  return store_delayeds;
174  }
175  virtual stir::Succeeded set_up()
176  {
177  if (LmToProjData::set_up() == Succeeded::no)
178  THROW("LmToProjData setup failed");
179  fan_size = -1;
180 #if STIR_VERSION < 060000
181  const auto max_fan_size =
182  lm_data_ptr->get_scanner_ptr()->get_max_num_non_arccorrected_bins();
183 #else
184  const auto max_fan_size =
185  lm_data_ptr->get_scanner().get_max_num_non_arccorrected_bins();
186 #endif
187  if (fan_size == -1)
188  fan_size = max_fan_size;
189  else
190  fan_size =
191  std::min(fan_size, max_fan_size);
192  half_fan_size = fan_size / 2;
193  fan_size = 2 * half_fan_size + 1;
194 
195  exam_info_sptr_->set_time_frame_definitions(frame_defs);
196  const float h = proj_data_info_sptr_->get_bed_position_horizontal();
197  const float v = proj_data_info_sptr_->get_bed_position_vertical();
198  stir::shared_ptr<ProjDataInfo> temp_proj_data_info_sptr(template_proj_data_info_ptr->clone());
199  temp_proj_data_info_sptr->set_bed_position_horizontal(h);
200  temp_proj_data_info_sptr->set_bed_position_vertical(v);
201  randoms_sptr.reset(new STIRAcquisitionDataInMemory(exam_info_sptr_, temp_proj_data_info_sptr));
202 
203  return stir::Succeeded::yes;
204  }
205  int estimate_randoms();
206  void save_randoms()
207  {
208  std::string filename = output_filename_prefix + "_randoms" + "_f1g1d0b0.hs";
209  randoms_sptr->write(filename.c_str());
210  }
211  std::shared_ptr<STIRAcquisitionData> get_output()
212  {
213  std::string filename = output_filename_prefix + "_f1g1d0b0.hs";
214  return std::shared_ptr<STIRAcquisitionData>
215  (new STIRAcquisitionDataInFile(filename.c_str()));
216  }
217  std::shared_ptr<STIRAcquisitionData> get_randoms_sptr()
218  {
219  return randoms_sptr;
220  }
223  float get_time_at_which_num_prompts_exceeds_threshold(const unsigned long threshold) const;
224 
225  protected:
226  // variables for ML estimation of singles/randoms
227  int fan_size;
228  int half_fan_size;
229  int max_ring_diff_for_fansums;
230  int num_iterations;
231  int display_interval;
232  int KL_interval;
233  int save_interval;
234  stir::shared_ptr<ExamInfo> exam_info_sptr_;
235  stir::shared_ptr<ProjDataInfo> proj_data_info_sptr_;
236  stir::shared_ptr<std::vector<stir::Array<2, float> > > fan_sums_sptr;
237  stir::shared_ptr<stir::DetectorEfficiencies> det_eff_sptr;
238  std::shared_ptr<STIRAcquisitionData> randoms_sptr;
239  void compute_fan_sums_(bool prompt_fansum = false);
240  int compute_singles_();
241 // void estimate_randoms_();
242  static unsigned long compute_num_bins_(const int num_rings,
243  const int num_detectors_per_ring,
244  const int max_ring_diff, const int half_fan_size);
245  };
246 
254  public:
256  // create from bin (detector pair) efficiencies sinograms
258  // create from ECAT8
259  PETAcquisitionSensitivityModel(std::string filename);
260  // chain two normalizations
263  {
264  norm_.reset(new stir::ChainedBinNormalisation(mod1.data(), mod2.data()));
265  }
266 
267  void set_up(const stir::shared_ptr<const stir::ExamInfo>& exam_info_sptr,
268  const stir::shared_ptr<stir::ProjDataInfo>&);
269 
270  // multiply by bin efficiencies
271  virtual void unnormalise(STIRAcquisitionData& ad) const;
272  // divide by bin efficiencies
273  virtual void normalise(STIRAcquisitionData& ad) const;
274  // same as apply, but returns new data rather than changes old one
275  std::shared_ptr<STIRAcquisitionData> forward(const STIRAcquisitionData& ad) const
276  {
277  std::shared_ptr<STIRAcquisitionData> sptr_ad = ad.new_acquisition_data();
278  sptr_ad->fill(ad);
279  this->unnormalise(*sptr_ad);
280  return sptr_ad;
281  }
282  // same as undo, but returns new data rather than changes old one
283  std::shared_ptr<STIRAcquisitionData> invert(const STIRAcquisitionData& ad) const
284  {
285  std::shared_ptr<STIRAcquisitionData> sptr_ad = ad.new_acquisition_data();
286  sptr_ad->fill(ad);
287  this->normalise(*sptr_ad);
288  return sptr_ad;
289  }
290 
291  stir::shared_ptr<stir::BinNormalisation> data()
292  {
293  return norm_;
294  //return std::dynamic_pointer_cast<stir::BinNormalisation>(norm_);
295  }
296 
297  protected:
298  stir::shared_ptr<stir::BinNormalisation> norm_;
299  //shared_ptr<stir::ChainedBinNormalisation> norm_;
300  };
301 
302 
309  typedef DataProcessor3DF ImageDataProcessor;
310 
357  public:
365  class BFOperator : public Operator<STIRImageData> {
366  public:
367  BFOperator(const PETAcquisitionModel& am) : sptr_am_(am.linear_acq_mod_sptr()) {}
368  void set_subset(int sub_num)
369  {
370  sub_num_ = sub_num;
371  }
372  void set_num_subsets(int num_sub)
373  {
374  num_sub_ = num_sub;
375  }
376  virtual std::shared_ptr<STIRImageData> apply(const STIRImageData& image_data)
377  {
378  std::shared_ptr<STIRAcquisitionData> sptr_fwd =
379  sptr_am_->forward(image_data, sub_num_, num_sub_); // , true);
380  std::shared_ptr<STIRImageData> sptr_bwd =
381  sptr_am_->backward(*sptr_fwd, sub_num_, num_sub_);
382  return sptr_bwd;
383  }
384  private:
385  std::shared_ptr<const PETAcquisitionModel> sptr_am_;
386  int sub_num_ = 0;
387  int num_sub_ = 1;
388  };
389 
398  float norm(int subset_num = 0, int num_subsets = 1, int num_iter = 2, int verb = 0) const
399  {
400  BFOperator bf(*this);
401  bf.set_subset(subset_num);
402  bf.set_num_subsets(num_subsets);
403  JacobiCG<float> jcg;
404  jcg.set_num_iterations(num_iter);
405  STIRImageData image_data = *sptr_image_template_->clone();
406  image_data.fill(1.0);
407  float lmd = jcg.largest(bf, image_data, verb);
408  return std::sqrt(lmd);
409  }
410 
411  void set_projectors(stir::shared_ptr<stir::ProjectorByBinPair> sptr_projectors)
412  {
413  sptr_projectors_ = sptr_projectors;
414  }
415  const stir::shared_ptr<stir::ProjectorByBinPair> projectors_sptr() const
416  {
417  return sptr_projectors_;
418  }
419  void set_additive_term(std::shared_ptr<STIRAcquisitionData> sptr)
420  {
421  sptr_add_ = sptr;
422  }
423  std::shared_ptr<const STIRAcquisitionData> additive_term_sptr() const
424  {
425  return sptr_add_;
426  }
427  void set_background_term(std::shared_ptr<STIRAcquisitionData> sptr)
428  {
429  sptr_background_ = sptr;
430  }
431  std::shared_ptr<const STIRAcquisitionData> background_term_sptr() const
432  {
433  return sptr_background_;
434  }
435  std::shared_ptr<const STIRAcquisitionData> acq_template_sptr() const
436  {
437  return sptr_acq_template_;
438  }
439  std::shared_ptr<const STIRImageData> image_template_sptr() const
440  {
441  return sptr_image_template_;
442  }
443  //void set_normalisation(shared_ptr<stir::BinNormalisation> sptr)
444  //{
445  // sptr_normalisation_ = sptr;
446  //}
447  const stir::shared_ptr<stir::BinNormalisation> normalisation_sptr() const
448  {
449  if (sptr_asm_.get())
450  return sptr_asm_->data();
451  stir::shared_ptr<stir::BinNormalisation> sptr;
452  return sptr;
453  //return sptr_normalisation_;
454  }
455  //void set_bin_efficiency(shared_ptr<STIRAcquisitionData> sptr_data);
456  //void set_normalisation(shared_ptr<STIRAcquisitionData> sptr_data)
457  //{
458  // sptr_normalisation_.reset(new stir::BinNormalisationFromProjData(*sptr_data));
459  //}
460  void set_asm(std::shared_ptr<PETAcquisitionSensitivityModel> sptr_asm)
461  {
462  //sptr_normalisation_ = sptr_asm->data();
463  sptr_asm_ = sptr_asm;
464  }
465  stir::shared_ptr<PETAcquisitionSensitivityModel> asm_sptr() const
466  {
467  return sptr_asm_;
468  }
469 
471 
473  void set_image_data_processor(stir::shared_ptr<ImageDataProcessor> sptr_processor);
474  void cancel_background_term()
475  {
476  sptr_background_.reset();
477  }
478  void cancel_additive_term()
479  {
480  sptr_add_.reset();
481  }
482  void cancel_normalisation()
483  {
484  sptr_asm_.reset();
485  //sptr_normalisation_.reset();
486  }
487  std::shared_ptr<const PETAcquisitionModel> linear_acq_mod_sptr() const
488  {
489  std::shared_ptr<PETAcquisitionModel> sptr_am(new PETAcquisitionModel);
490  sptr_am->set_projectors(sptr_projectors_);
491  sptr_am->set_asm(sptr_asm_);
492  sptr_am->sptr_acq_template_ = sptr_acq_template_;
493  sptr_am->sptr_image_template_ = sptr_image_template_;
494  return sptr_am;
495  }
496 
497  virtual void set_up(
498  std::shared_ptr<STIRAcquisitionData> sptr_acq,
499  std::shared_ptr<STIRImageData> sptr_image);
500 
504  std::shared_ptr<STIRAcquisitionData>
505  forward(const STIRImageData& image,
506  int subset_num = 0, int num_subsets = 1, bool do_linear_only = false) const;
517  void forward(STIRAcquisitionData& acq_data, const STIRImageData& image,
518  int subset_num, int num_subsets, bool zero = false, bool do_linear_only = false) const;
519 
520  // computes and returns back-projected subset of acquisition data
521  std::shared_ptr<STIRImageData> backward(const STIRAcquisitionData& ad,
522  int subset_num = 0, int num_subsets = 1) const;
523  // puts back-projected subset of acquisition data into image
524  void backward(STIRImageData& image, const STIRAcquisitionData& ad,
525  int subset_num = 0, int num_subsets = 1) const;
526 
527  protected:
528  stir::shared_ptr<stir::ProjectorByBinPair> sptr_projectors_;
529  std::shared_ptr<STIRAcquisitionData> sptr_acq_template_;
530  std::shared_ptr<STIRImageData> sptr_image_template_;
531  std::shared_ptr<STIRAcquisitionData> sptr_add_;
532  std::shared_ptr<STIRAcquisitionData> sptr_background_;
533  std::shared_ptr<PETAcquisitionSensitivityModel> sptr_asm_;
534  //shared_ptr<stir::BinNormalisation> sptr_normalisation_;
535  };
536 
549  class PETSingleScatterSimulator : public stir::SingleScatterSimulation
550  {
551  public:
553  PETSingleScatterSimulator() : stir::SingleScatterSimulation()
554  {}
556  PETSingleScatterSimulator(std::string filename) :
557  stir::SingleScatterSimulation(filename)
558  {}
559 
560  void set_up(std::shared_ptr<const STIRAcquisitionData> sptr_acq_template,
561  std::shared_ptr<const STIRImageData> sptr_act_image_template)
562  {
563  this->sptr_acq_template_ = sptr_acq_template;
564 
565  stir::SingleScatterSimulation::set_template_proj_data_info(
566  *sptr_acq_template_->get_proj_data_info_sptr());
567  stir::SingleScatterSimulation::set_exam_info(
568  *sptr_acq_template_->get_exam_info_sptr());
569  // check if attenuation image is set
570  try
571  {
572  auto& tmp = stir::SingleScatterSimulation::get_attenuation_image();
573  }
574  catch (...)
575  {
576  THROW("Fatal error in PETSingleScatterSimulator::set_up: attenuation_image has not been set");
577  }
578  this->set_activity_image_sptr(sptr_act_image_template);
579 
580  if (stir::SingleScatterSimulation::set_up() == Succeeded::no)
581  THROW("Fatal error in PETSingleScatterSimulator::set_up() failed.");
582  }
583 
584  void set_activity_image_sptr(std::shared_ptr<const STIRImageData> arg)
585  {
586 #if STIR_VERSION < 050000
587  // need to make a copy as the function doesn't accept a const
588  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
589  stir::SingleScatterSimulation::set_activity_image_sptr(sptr_image_copy);
590 #else
591  stir::SingleScatterSimulation::set_activity_image_sptr(arg->data_sptr());
592 #endif
593  }
594 
595  void set_attenuation_image_sptr(std::shared_ptr<const STIRImageData> arg)
596  {
597 #if STIR_VERSION < 050000
598  // need to make a copy as the function doesn't accept a const
599  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
600  stir::SingleScatterSimulation::set_density_image_sptr(sptr_image_copy);
601 #else
602  stir::SingleScatterSimulation::set_density_image_sptr(arg->data_sptr());
603 #endif
604  }
605 
606  std::shared_ptr<STIRAcquisitionData> forward(const STIRImageData& activity_img) /*TODO CONST*/
607  {
608  if (!sptr_acq_template_.get())
609  THROW("Fatal error in PETSingleScatterSimulator::forward: acquisition template not set");
610  std::shared_ptr<STIRAcquisitionData> sptr_ad =
611  sptr_acq_template_->new_acquisition_data();
612  this->forward( *sptr_ad, activity_img);
613  return sptr_ad;
614  }
615 
616  void forward(STIRAcquisitionData& ad, const STIRImageData& activity_img) /* TODO CONST*/
617  {
618  stir::shared_ptr<ProjData> sptr_fd = ad.data();
619  this->set_output_proj_data_sptr(sptr_fd);
620  // hopefully STIR checks if template consistent with input data
621  this->process_data();
622  }
623 
624  protected:
625  std::shared_ptr<const STIRAcquisitionData> sptr_acq_template_;
626 
627  };
628 
641  class PETScatterEstimator : private stir::ScatterEstimation
642  {
643  using recon_type = stir::OSMAPOSLReconstruction<DiscretisedDensity<3,float>>;
644  public:
646 
651  PETScatterEstimator() : stir::ScatterEstimation()
652  {
653  auto obj_sptr = std::make_shared<PoissonLogLikelihoodWithLinearModelForMeanAndProjData<DiscretisedDensity<3,float>>>();
654  auto recon_sptr = std::make_shared<recon_type>();
655  recon_sptr->set_num_subiterations(8);
656  recon_sptr->set_num_subsets(7); // this works for the mMR. TODO
657  recon_sptr->set_disable_output(true);
658  recon_sptr->set_objective_function_sptr(obj_sptr);
659  stir::shared_ptr<stir::SeparableGaussianImageFilter<float> >
660  filter_sptr(new stir::SeparableGaussianImageFilter<float>);
661  filter_sptr->set_fwhms(stir::make_coordinate(15.F,15.F,15.F));
662  recon_sptr->set_post_processor_sptr(filter_sptr);
663  stir::ScatterEstimation::set_reconstruction_method_sptr(recon_sptr);
664  }
666  PETScatterEstimator(std::string filename) :
667  stir::ScatterEstimation(filename)
668  {}
669 
671  void set_input_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
672  {
673  stir::ScatterEstimation::set_input_proj_data_sptr(arg->data());
674  }
676  void set_attenuation_correction_factors_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
677  {
678  stir::ScatterEstimation::set_attenuation_correction_proj_data_sptr(arg->data());
679  }
681  void set_asm(std::shared_ptr<PETAcquisitionSensitivityModel> arg)
682  {
683  stir::ScatterEstimation::set_normalisation_sptr(arg->data());
684  }
686  void set_background_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
687  {
688  stir::ScatterEstimation::set_background_proj_data_sptr(arg->data());
689  }
690 
691  void set_attenuation_image_sptr(std::shared_ptr<const STIRImageData> arg)
692  {
693 #if STIR_VERSION < 050000
694  // need to make a copy as the function doesn't accept a const
695  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
696  stir::ScatterEstimation::set_attenuation_image_sptr(sptr_image_copy);
697 #else
698  stir::ScatterEstimation::set_attenuation_image_sptr(arg->data_sptr());
699 #endif
700  }
701 
703 
709  void set_output_prefix(std::string prefix)
710  {
711  stir::ScatterEstimation::set_export_scatter_estimates_of_each_iteration(!prefix.empty());
712  stir::ScatterEstimation::set_output_scatter_estimate_prefix(prefix);
713  }
714 
715  void set_num_iterations(int arg)
716  {
717  stir::ScatterEstimation::set_num_iterations(arg);
718  }
719 
720  int get_num_iterations() const
721  {
722  return stir::ScatterEstimation::get_num_iterations();
723  }
724 
725  void set_OSEM_num_subiterations(int arg)
726  {
727  this->get_reconstruction_method().set_num_subiterations(arg);
728  }
729 
730  int get_OSEM_num_subiterations() const
731  {
732  return this->get_reconstruction_method().get_num_subiterations();
733  }
734 
735  void set_OSEM_num_subsets(int arg)
736  {
737  this->get_reconstruction_method().set_num_subsets(arg);
738  this->_already_set_up_sirf = false;
739  }
740 
741  int get_OSEM_num_subsets() const
742  {
743  return this->get_reconstruction_method().get_num_subsets();
744  }
745 
746  std::shared_ptr<STIRAcquisitionData> get_scatter_estimate(int est_num = -1) const
747  {
748  if (est_num == -1) // Get the last one
749  est_num = num_scatter_iterations;
750  if (est_num == num_scatter_iterations)
751  return get_output();
752  // try to read from file
753  if (output_scatter_estimate_prefix.empty())
754  THROW("output_scatter_estimate_prefix not set, so scatter estimates were not saved to file.");
755  const std::string filename = output_scatter_estimate_prefix + "_" + std::to_string(est_num) + ".hs";
756  return std::make_shared<STIRAcquisitionDataInFile>(filename.c_str());
757  }
758 
760  std::shared_ptr<STIRAcquisitionData> get_output() const
761  {
762  auto stir_proj_data_sptr = stir::ScatterEstimation::get_output();
763  if (!stir_proj_data_sptr)
764  THROW("output not yet computed");
765  std::shared_ptr<STIRAcquisitionData> sptr_acq_data
766  (STIRAcquisitionData::storage_template()->same_acquisition_data(stir_proj_data_sptr->get_exam_info_sptr(),
767  stir_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone()));
768  sptr_acq_data->data()->fill(*stir_proj_data_sptr);
769  return sptr_acq_data;
770  }
771 
773 
779  Succeeded set_up()
780  {
781  // reconstruct an smooth image with a large voxel size
782  const float zoom = 0.2F;
783  stir::shared_ptr<Voxels3DF>
784  image_sptr(new Voxels3DF(MAKE_SHARED<stir::ExamInfo>(*this->get_input_data()->get_exam_info_sptr()),
785  *this->get_input_data()->get_proj_data_info_sptr(),
786  zoom));
787  image_sptr->fill(1.F);
788  stir::ScatterEstimation::set_initial_activity_image_sptr(image_sptr);
789  if (stir::ScatterEstimation::set_up() == Succeeded::no)
790  THROW("scatter estimation set_up failed");
791  this->_already_set_up_sirf = true;
792  return Succeeded::yes;
793  }
794  void process()
795  {
796  if (!this->_already_set_up_sirf)
797  THROW("scatter estimation needs to be set-up first");
798  if (!stir::ScatterEstimation::already_setup())
799  THROW("scatter estimation needs to be set-up first");
800  if (stir::ScatterEstimation::process_data() == Succeeded::no)
801  THROW("scatter estimation failed");
802  }
803  private:
805  bool _already_set_up_sirf;
806 
808  recon_type& get_reconstruction_method() const
809  {
810  return dynamic_cast<recon_type&>(*this->reconstruction_template_sptr);
811  }
812  };
813 
829  public:
831  {
832  this->sptr_projectors_.reset(new ProjectorPairUsingMatrix);
833  }
834  void set_matrix(stir::shared_ptr<stir::ProjMatrixByBin> sptr_matrix)
835  {
836  sptr_matrix_ = sptr_matrix;
837  ((ProjectorPairUsingMatrix*)this->sptr_projectors_.get())->
838  set_proj_matrix_sptr(sptr_matrix);
839  }
840  stir::shared_ptr<stir::ProjMatrixByBin> matrix_sptr()
841  {
842  return sptr_matrix_;
843  //return ((ProjectorPairUsingMatrix*)this->sptr_projectors_.get())->
844  // get_proj_matrix_sptr();
845  }
846  virtual void set_up(
847  std::shared_ptr<STIRAcquisitionData> sptr_acq,
848  std::shared_ptr<STIRImageData> sptr_image)
849  {
850  if (!sptr_matrix_.get())
851  THROW("PETAcquisitionModelUsingMatrix setup failed - matrix not set");
852  PETAcquisitionModel::set_up(sptr_acq, sptr_image);
853  }
854 
856  void enable_cache(bool v = true)
857  {
858  sptr_matrix_->enable_cache(v);
859  }
860 
861  private:
862  stir::shared_ptr<stir::ProjMatrixByBin> sptr_matrix_;
863  };
864 
867  public:
868  PETAcquisitionModelUsingRayTracingMatrix(int num_LORs = 2) :
870  {
871  stir::shared_ptr<RayTracingMatrix> matrix_sptr(new RayTracingMatrix);
872  matrix_sptr->set_num_tangential_LORs(num_LORs);
873  set_matrix(matrix_sptr);
874  }
875  void set_num_tangential_LORs(int num_LORs)
876  {
877  //RayTracingMatrix& matrix = (RayTracingMatrix&)*matrix_sptr();
878  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
879  //std::cout << matrix.get_num_tangential_LORs() << '\n';
880  matrix.set_num_tangential_LORs(num_LORs);
881  //std::cout << get_num_tangential_LORs() << '\n';
882  }
885  {
886  auto matrix = dynamic_cast<const RayTracingMatrix&>(*matrix_sptr());
887  return matrix.get_num_tangential_LORs();
888  }
891  {
892  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
893  matrix.set_restrict_to_cylindrical_FOV(v);
894  }
897  //bool get_do_symmetry_90degrees_min_phi() const;
898  void set_do_symmetry_90degrees_min_phi(bool v = true)
899  {
900  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
901  matrix.set_do_symmetry_90degrees_min_phi(v);
902  }
903  //bool get_do_symmetry_180degrees_min_phi() const;
904  void set_do_symmetry_180degrees_min_phi(bool v = true)
905  {
906  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
907  matrix.set_do_symmetry_180degrees_min_phi(v);
908  }
909  //bool get_do_symmetry_swap_segment() const;
910  void set_do_symmetry_swap_segment(bool v = true)
911  {
912  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
913  matrix.set_do_symmetry_swap_segment(v);
914  }
915  //bool get_do_symmetry_swap_s() const;
916  void set_do_symmetry_swap_s(bool v = true)
917  {
918  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
919  matrix.set_do_symmetry_swap_s(v);
920  }
921  //bool get_do_symmetry_shift_z() const;
922  void set_do_symmetry_shift_z(bool v = true)
923  {
924  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
925  matrix.set_do_symmetry_shift_z(v);
926  }
927  };
928 
929  typedef PETAcquisitionModel AcqMod3DF;
930  typedef PETAcquisitionModelUsingMatrix AcqModUsingMatrix3DF;
931  typedef std::shared_ptr<AcqMod3DF> sptrAcqMod3DF;
932 
933 #ifdef STIR_WITH_NiftyPET_PROJECTOR
939  class PETAcquisitionModelUsingNiftyPET : public PETAcquisitionModel {
940  public:
941  PETAcquisitionModelUsingNiftyPET()
942  {
943  _NiftyPET_projector_pair_sptr.reset(new ProjectorPairUsingNiftyPET);
944  this->sptr_projectors_ = _NiftyPET_projector_pair_sptr;
945  // Set verbosity to 0 by default
946  _NiftyPET_projector_pair_sptr->set_verbosity(0);
947  }
948  void set_cuda_verbosity(const bool verbosity) const
949  {
950  _NiftyPET_projector_pair_sptr->set_verbosity(verbosity);
951  }
952  void set_use_truncation(const bool use_truncation) const
953  {
954  _NiftyPET_projector_pair_sptr->set_use_truncation(use_truncation);
955  }
956  protected:
957  stir::shared_ptr<stir::ProjectorPairUsingNiftyPET> _NiftyPET_projector_pair_sptr;
958  };
959  typedef PETAcquisitionModelUsingNiftyPET AcqModUsingNiftyPET3DF;
960 #endif
961 
962 #ifdef STIR_WITH_Parallelproj_PROJECTOR
968  class PETAcquisitionModelUsingParallelproj : public PETAcquisitionModel {
969  public:
970  PETAcquisitionModelUsingParallelproj()
971  {
972  this->sptr_projectors_.reset(new ProjectorByBinPairUsingParallelproj);
973  }
974  };
975  typedef PETAcquisitionModelUsingParallelproj AcqModUsingParallelproj;
976 #endif
977 
985  public:
987  // multiply by bin efficiencies
988  virtual void unnormalise(STIRAcquisitionData& ad) const;
989  // divide by bin efficiencies
990  virtual void normalise(STIRAcquisitionData& ad) const;
991  protected:
992  stir::shared_ptr<stir::ForwardProjectorByBin> sptr_forw_projector_;
993  };
994 
1004  class xSTIR_Box3D : public stir::Box3D {
1005  public:
1006  void set_length_x(float v)
1007  {
1008  length_x = v;
1009  }
1010  void set_length_y(float v)
1011  {
1012  length_y = v;
1013  }
1014  void set_length_z(float v)
1015  {
1016  length_z = v;
1017  }
1018  float get_length_x() const
1019  {
1020  return length_x;
1021  }
1022  float get_length_y() const
1023  {
1024  return length_y;
1025  }
1026  float get_length_z() const
1027  {
1028  return length_z;
1029  }
1030  };
1031 
1032  class xSTIR_GeneralisedPrior3DF : public stir::GeneralisedPrior < Image3DF > {
1033  public:
1034  void multiply_with_Hessian(Image3DF& output, const Image3DF& curr_image_est,
1035  const Image3DF& input) const
1036  {
1037  output.fill(0.0);
1038  accumulate_Hessian_times_input(output, curr_image_est, input);
1039  }
1040 // bool post_process() {
1041 // return post_processing();
1042 // }
1043  };
1044 
1045  class xSTIR_QuadraticPrior3DF : public stir::QuadraticPrior < float > {
1046  public:
1047  void only2D(int only) {
1048  only_2D = only != 0;
1049  }
1050  };
1051 
1052  class xSTIR_LogcoshPrior3DF : public stir::LogcoshPrior < float > {
1053  public:
1054  void only2D(int only) {
1055  only_2D = only != 0;
1056  }
1057  };
1058 
1059  class xSTIR_RelativeDifferencePrior3DF : public stir::RelativeDifferencePrior < float > {
1060  public:
1061  void only2D(int only) {
1062  only_2D = only != 0;
1063  }
1064  };
1065 
1066  class xSTIR_PLSPrior3DF : public stir::PLSPrior < float > {
1067  public:
1068  void only2D(int only) {
1069  only_2D = only != 0;
1070  }
1071  };
1072 
1074  public stir::GeneralisedObjectiveFunction < Image3DF > {
1075  public:
1076  void multiply_with_Hessian(Image3DF& output, const Image3DF& curr_image_est,
1077  const Image3DF& input, const int subset) const
1078  {
1079  output.fill(0.0);
1080  if (subset >= 0)
1081  accumulate_sub_Hessian_times_input(output, curr_image_est, input, subset);
1082  else {
1083  for (int s = 0; s < get_num_subsets(); s++) {
1084  accumulate_sub_Hessian_times_input(output, curr_image_est, input, s);
1085  }
1086  }
1087  }
1088 
1089 // bool post_process() {
1090 // return post_processing();
1091 // }
1092  };
1093 
1094  //typedef xSTIR_GeneralisedObjectiveFunction3DF ObjectiveFunction3DF;
1095 
1097  public stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData < Image3DF > {
1098  public:
1099  void set_input_file(const char* filename) {
1100  input_filename = filename;
1101  }
1102  void set_acquisition_data(std::shared_ptr<STIRAcquisitionData> sptr)
1103  {
1104  sptr_ad_ = sptr;
1105  set_proj_data_sptr(sptr->data());
1106  }
1107  void set_acquisition_model(std::shared_ptr<AcqMod3DF> sptr_am);
1108 
1109  std::shared_ptr<AcqMod3DF> acquisition_model_sptr()
1110  {
1111  return sptr_am_;
1112  }
1113  private:
1114  std::shared_ptr<STIRAcquisitionData> sptr_ad_;
1115  std::shared_ptr<AcqMod3DF> sptr_am_;
1116  };
1117 
1120 
1122  public stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin<Image3DF> {
1123  public:
1124 #if 0
1125  // this functionality was for skip_lm_input_file, but this is disabled for now
1126  void set_acquisition_data(std::shared_ptr<PETAcquisitionData> sptr)
1127  {
1128  sptr_ad_ = sptr;
1129  set_proj_data_info(*sptr->data());
1130  }
1131 #endif
1132  void set_acquisition_model(std::shared_ptr<AcqMod3DF> sptr_am);
1133 
1134  void set_cache_path(const std::string filepath)
1135  {
1136  stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin<Image3DF>::
1137  set_cache_path(filepath);
1138  }
1139 
1140  void set_time_interval(double start, double stop)
1141  {
1142  std::pair<double, double> interval(start, stop);
1143  std::vector < std::pair<double, double> > intervals;
1144  intervals.push_back(interval);
1145  frame_defs = stir::TimeFrameDefinitions(intervals);
1146  do_time_frame = true;
1147  }
1148 
1149  private:
1150  //std::shared_ptr<PETAcquisitionData> sptr_ad_;
1151  std::shared_ptr<PETAcquisitionModelUsingMatrix> sptr_am_;
1152  };
1153 
1155 
1157  public stir::IterativeReconstruction < Image3DF > {
1158  public:
1159 /* bool post_process() {
1160  //std::cout << "in xSTIR_IterativeReconstruction3DF.post_process...\n";
1161  if (this->output_filename_prefix.length() < 1)
1162  this->set_output_filename_prefix("reconstructed_image");
1163  return post_processing();
1164  }*/
1165  void update(Image3DF &image) {
1166  update_estimate(image);
1167  end_of_iteration_processing(image);
1168  subiteration_num++;
1169  }
1170  void update(STIRImageData& id)
1171  {
1172  update(id.data());
1173  }
1174  void update(stir::shared_ptr<STIRImageData> sptr_id)
1175  {
1176  update(*sptr_id);
1177  }
1178  int& subiteration() {
1179  return subiteration_num;
1180  }
1181  int subiteration() const {
1182  return subiteration_num;
1183  }
1184  void set_initial_estimate_file(const char* filename) {
1185  initial_data_filename = filename;
1186  }
1187  };
1188 
1189  class xSTIR_OSMAPOSLReconstruction3DF : public stir::OSMAPOSLReconstruction< Image3DF > {
1190  public:
1191  int& subiteration() {
1192  return subiteration_num;
1193  }
1194  int subiteration() const {
1195  return subiteration_num;
1196  }
1197  };
1198 
1199  class xSTIR_KOSMAPOSLReconstruction3DF : public stir::KOSMAPOSLReconstruction< Image3DF > {
1200  public:
1201  void compute_kernelised_image_x(
1202  Image3DF& kernelised_image_out,
1203  const Image3DF& image_to_kernelise,
1204  const Image3DF& current_alpha_estimate)
1205  {
1206  compute_kernelised_image(
1207  kernelised_image_out,
1208  image_to_kernelise,
1209  current_alpha_estimate);
1210  }
1211  };
1212 
1213  class xSTIR_OSSPSReconstruction3DF : public stir::OSSPSReconstruction < Image3DF > {
1214  public:
1215  float& relaxation_parameter_value() {
1216  return relaxation_parameter;
1217  }
1218  float& relaxation_gamma_value() {
1219  return relaxation_gamma;
1220  }
1221  double& upper_bound_value() {
1222  return upper_bound;
1223  }
1224  };
1225 
1226  class xSTIR_FBP2DReconstruction : public stir::FBP2DReconstruction {
1227  public:
1229  {
1230  _is_set_up = false;
1231  }
1232  void set_input(const STIRAcquisitionData& acq)
1233  {
1234  set_input_data(acq.data());
1235  }
1236  void set_zoom(float v)
1237  {
1238  set_zoom_xy(v);
1239  _is_set_up = false;
1240  }
1241  void set_alpha_ramp(double alpha)
1242  {
1243  // does not work!
1244  //assert(alpha > 0 && alpha <= 1.0);
1245  if (!(alpha > 0 && alpha <= 1.0))
1246  throw LocalisedException
1247  ("wrong ramp filter parameter alpha", __FILE__, __LINE__);
1248  alpha_ramp = alpha;
1249  }
1250  void set_frequency_cut_off(double fc)
1251  {
1252  if (!(fc > 0 && fc <= 0.5))
1253  throw LocalisedException
1254  ("wrong frequency cut-off", __FILE__, __LINE__);
1255  fc_ramp = fc;
1256  }
1257  void set_up(std::shared_ptr<STIRImageData> sptr_id)
1258  {
1259  _sptr_image_data.reset(new STIRImageData(*sptr_id));
1260  stir::Succeeded s = stir::Reconstruction<Image3DF>::set_up(_sptr_image_data->data_sptr());
1261  if (s != stir::Succeeded::yes)
1262  THROW("stir::Reconstruction setup failed");
1263  _is_set_up = true;
1264  }
1265  void cancel_setup()
1266  {
1267  _is_set_up = false;
1268  }
1269  void process()
1270  {
1271  stir::Succeeded s = stir::Succeeded::no;
1272  if (!_is_set_up) {
1273  stir::shared_ptr<Image3DF> sptr_image(construct_target_image_ptr());
1274  _sptr_image_data.reset(new STIRImageData(sptr_image));
1275  stir::Reconstruction<Image3DF>::set_up(sptr_image);
1276  s = reconstruct(sptr_image);
1277  }
1278  else
1279  s = reconstruct(_sptr_image_data->data_sptr());
1280  if (s != stir::Succeeded::yes)
1281  THROW("stir::AnalyticReconstruction::reconstruct failed");
1282  }
1283  std::shared_ptr<STIRImageData> get_output()
1284  {
1285  return _sptr_image_data;
1286  }
1287  protected:
1288  bool _is_set_up;
1289  std::shared_ptr<STIRImageData> _sptr_image_data;
1290  };
1291 
1293  public stir::SeparableGaussianImageFilter<float> {
1294  public:
1295  //stir::Succeeded set_up(const STIRImageData& id)
1296  //{
1297  // return virtual_set_up(id.data());
1298  //}
1299  //void apply(STIRImageData& id)
1300  //{
1301  // virtual_apply(id.data());
1302  //}
1303  void set_fwhms_xyz(char xyz, float f)
1304  {
1305  stir::BasicCoordinate<3, float> v = get_fwhms();
1306  switch (xyz) {
1307  case 'z':
1308  v[1] = f;
1309  break;
1310  case 'y':
1311  v[2] = f;
1312  break;
1313  case 'x':
1314  v[3] = f;
1315  }
1316  set_fwhms(v);
1317  }
1318  void set_max_kernel_sizes_xyz(char xyz, int s)
1319  {
1320  stir::BasicCoordinate<3, int> v = get_max_kernel_sizes();
1321  switch (xyz) {
1322  case 'z':
1323  v[1] = s;
1324  break;
1325  case 'y':
1326  v[2] = s;
1327  break;
1328  case 'x':
1329  v[3] = s;
1330  }
1331  set_max_kernel_sizes(v);
1332  }
1333  };
1334 }
1335 
1336 #endif
Definition: LocalisedException.h:32
Definition: JacobiCG.h:37
Listmode-to-sinograms converter.
Definition: stir_x.h:84
void set_output(std::string proj_data_file)
Specifies the prefix for the output file(s),.
Definition: stir_x.h:127
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:97
Definition: Operator.h:7
Class for the product of backward and forward projectors of a PET acquisition model.
Definition: stir_x.h:365
Class for a PET acquisition model.
Definition: stir_x.h:356
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:398
Ray tracing matrix implementation of the PET acquisition model.
Definition: stir_x.h:828
void enable_cache(bool v=true)
Enables or disables the caching mechanism.
Definition: stir_x.h:856
int get_num_tangential_LORs()
@
Definition: stir_x.h:884
void set_restrict_to_cylindrical_FOV(bool v=true)
Enables or disables using a circular axial FOV (vs rectangular)
Definition: stir_x.h:890
Class for PET scanner detector efficiencies model.
Definition: stir_x.h:253
Attenuation model.
Definition: stir_x.h:984
Class for estimating the scatter contribution in PET projection data.
Definition: stir_x.h:642
void set_attenuation_correction_factors_sptr(std::shared_ptr< const STIRAcquisitionData > arg)
Set attenuation correction factors as acq_data.
Definition: stir_x.h:676
PETScatterEstimator()
constructor.
Definition: stir_x.h:651
void set_input_sptr(std::shared_ptr< const STIRAcquisitionData > arg)
Set the input data.
Definition: stir_x.h:671
std::shared_ptr< STIRAcquisitionData > get_output() const
get last scatter estimate
Definition: stir_x.h:760
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:686
Succeeded set_up()
set up the object and performs checks
Definition: stir_x.h:779
void set_asm(std::shared_ptr< PETAcquisitionSensitivityModel > arg)
Set acquisition sensitivity model specifying detection efficiencies (without attenuation)
Definition: stir_x.h:681
void set_output_prefix(std::string prefix)
Set prefix for filenames with scatter estimates.
Definition: stir_x.h:709
PETScatterEstimator(std::string filename)
Overloaded constructor which takes the parameter file.
Definition: stir_x.h:666
Class for simulating the scatter contribution to PET data.
Definition: stir_x.h:550
PETSingleScatterSimulator(std::string filename)
Overloaded constructor which takes the parameter file.
Definition: stir_x.h:556
PETSingleScatterSimulator()
Default constructor.
Definition: stir_x.h:553
STIR ProjData wrapper with added functionality.
Definition: stir_data_containers.h:161
In-file implementation of STIRAcquisitionData.
Definition: stir_data_containers.h:536
STIR DiscretisedDensity<3, float> wrapper with added functionality.
Definition: stir_data_containers.h:956
Accessor classes.
Definition: stir_x.h:1004
Definition: stir_x.h:1226
Definition: stir_x.h:1032
Definition: stir_x.h:1052
Definition: stir_x.h:1189
Definition: stir_x.h:1213
Definition: stir_x.h:1066
Definition: stir_x.h:1045
Defines sirf::iequals.
Abstract base class for SIRF image data.
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:309
Specification file for data handling types not present in STIR.