SIRF  3.8.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 
90  public:
92  // create from bin (detector pair) efficiencies sinograms
94  // create from ECAT8
95  PETAcquisitionSensitivityModel(std::string filename);
96  // chain two normalizations
99  {
100  norm_.reset(new stir::ChainedBinNormalisation(mod1.data(), mod2.data()));
101  }
102 
103  void set_up(const stir::shared_ptr<const stir::ExamInfo>& exam_info_sptr,
104  const stir::shared_ptr<stir::ProjDataInfo>&);
105 
106  void set_up(const STIRAcquisitionData& ad)
107  {
108  set_up(ad.get_exam_info_sptr(), ad.get_proj_data_info_sptr()->create_shared_clone());
109  }
110 
111  // multiply by bin efficiencies
112  virtual void unnormalise(STIRAcquisitionData& ad) const;
113  // divide by bin efficiencies
114  virtual void normalise(STIRAcquisitionData& ad) const;
115  // same as apply, but returns new data rather than changes old one
116  std::shared_ptr<STIRAcquisitionData> forward(const STIRAcquisitionData& ad) const
117  {
118  std::shared_ptr<STIRAcquisitionData> sptr_ad = ad.new_acquisition_data();
119  sptr_ad->fill(ad);
120  this->unnormalise(*sptr_ad);
121  return sptr_ad;
122  }
123  // same as undo, but returns new data rather than changes old one
124  std::shared_ptr<STIRAcquisitionData> invert(const STIRAcquisitionData& ad) const
125  {
126  std::shared_ptr<STIRAcquisitionData> sptr_ad = ad.new_acquisition_data();
127  sptr_ad->fill(ad);
128  this->normalise(*sptr_ad);
129  return sptr_ad;
130  }
131 
132  stir::shared_ptr<stir::BinNormalisation> data()
133  {
134  return norm_;
135  //return std::dynamic_pointer_cast<stir::BinNormalisation>(norm_);
136  }
137 
138  protected:
139  stir::shared_ptr<stir::BinNormalisation> norm_;
140  //shared_ptr<stir::ChainedBinNormalisation> norm_;
141  };
142 
143 
150  typedef DataProcessor3DF ImageDataProcessor;
151 
198  public:
206  class BFOperator : public Operator<STIRImageData> {
207  public:
208  BFOperator(const PETAcquisitionModel& am) : sptr_am_(am.linear_acq_mod_sptr()) {}
209  void set_subset(int sub_num)
210  {
211  sub_num_ = sub_num;
212  }
213  void set_num_subsets(int num_sub)
214  {
215  num_sub_ = num_sub;
216  }
217  virtual std::shared_ptr<STIRImageData> apply(const STIRImageData& image_data)
218  {
219  std::shared_ptr<STIRAcquisitionData> sptr_fwd =
220  sptr_am_->forward(image_data, sub_num_, num_sub_); // , true);
221  std::shared_ptr<STIRImageData> sptr_bwd =
222  sptr_am_->backward(*sptr_fwd, sub_num_, num_sub_);
223  return sptr_bwd;
224  }
225  private:
226  std::shared_ptr<const PETAcquisitionModel> sptr_am_;
227  int sub_num_ = 0;
228  int num_sub_ = 1;
229  };
230 
239  float norm(int subset_num = 0, int num_subsets = 1, int num_iter = 2, int verb = 0) const
240  {
241  BFOperator bf(*this);
242  bf.set_subset(subset_num);
243  bf.set_num_subsets(num_subsets);
244  JacobiCG<float> jcg;
245  jcg.set_num_iterations(num_iter);
246  STIRImageData image_data = *sptr_image_template_->clone();
247  image_data.fill(1.0);
248  float lmd = jcg.largest(bf, image_data, verb);
249  return std::sqrt(lmd);
250  }
251 
252  void set_projectors(stir::shared_ptr<stir::ProjectorByBinPair> sptr_projectors)
253  {
254  sptr_projectors_ = sptr_projectors;
255  }
256  const stir::shared_ptr<stir::ProjectorByBinPair> projectors_sptr() const
257  {
258  return sptr_projectors_;
259  }
260  void set_additive_term(std::shared_ptr<STIRAcquisitionData> sptr)
261  {
262  sptr_add_ = sptr;
263  }
264  std::shared_ptr<const STIRAcquisitionData> additive_term_sptr() const
265  {
266  return sptr_add_;
267  }
268  void set_background_term(std::shared_ptr<STIRAcquisitionData> sptr)
269  {
270  sptr_background_ = sptr;
271  }
272  std::shared_ptr<const STIRAcquisitionData> background_term_sptr() const
273  {
274  return sptr_background_;
275  }
276  std::shared_ptr<const STIRAcquisitionData> acq_template_sptr() const
277  {
278  return sptr_acq_template_;
279  }
280  std::shared_ptr<const STIRImageData> image_template_sptr() const
281  {
282  return sptr_image_template_;
283  }
284  //void set_normalisation(shared_ptr<stir::BinNormalisation> sptr)
285  //{
286  // sptr_normalisation_ = sptr;
287  //}
288  const stir::shared_ptr<stir::BinNormalisation> normalisation_sptr() const
289  {
290  if (sptr_asm_.get())
291  return sptr_asm_->data();
292  stir::shared_ptr<stir::BinNormalisation> sptr;
293  return sptr;
294  //return sptr_normalisation_;
295  }
296  //void set_bin_efficiency(shared_ptr<STIRAcquisitionData> sptr_data);
297  //void set_normalisation(shared_ptr<STIRAcquisitionData> sptr_data)
298  //{
299  // sptr_normalisation_.reset(new stir::BinNormalisationFromProjData(*sptr_data));
300  //}
301  void set_asm(std::shared_ptr<PETAcquisitionSensitivityModel> sptr_asm)
302  {
303  //sptr_normalisation_ = sptr_asm->data();
304  sptr_asm_ = sptr_asm;
305  }
306  stir::shared_ptr<PETAcquisitionSensitivityModel> asm_sptr() const
307  {
308  return sptr_asm_;
309  }
310 
312 
314  void set_image_data_processor(stir::shared_ptr<ImageDataProcessor> sptr_processor);
315  void cancel_background_term()
316  {
317  sptr_background_.reset();
318  }
319  void cancel_additive_term()
320  {
321  sptr_add_.reset();
322  }
323  void cancel_normalisation()
324  {
325  sptr_asm_.reset();
326  //sptr_normalisation_.reset();
327  }
328  std::shared_ptr<const PETAcquisitionModel> linear_acq_mod_sptr() const
329  {
330  std::shared_ptr<PETAcquisitionModel> sptr_am(new PETAcquisitionModel);
331  sptr_am->set_projectors(sptr_projectors_);
332  sptr_am->set_asm(sptr_asm_);
333  sptr_am->sptr_acq_template_ = sptr_acq_template_;
334  sptr_am->sptr_image_template_ = sptr_image_template_;
335  return sptr_am;
336  }
337 
338  virtual void set_up(
339  std::shared_ptr<STIRAcquisitionData> sptr_acq,
340  std::shared_ptr<STIRImageData> sptr_image);
341 
345  std::shared_ptr<STIRAcquisitionData>
346  forward(const STIRImageData& image,
347  int subset_num = 0, int num_subsets = 1, bool do_linear_only = false) const;
358  void forward(STIRAcquisitionData& acq_data, const STIRImageData& image,
359  int subset_num, int num_subsets, bool zero = false, bool do_linear_only = false) const;
360 
361  // computes and returns back-projected subset of acquisition data
362  std::shared_ptr<STIRImageData> backward(const STIRAcquisitionData& ad,
363  int subset_num = 0, int num_subsets = 1) const;
364  // puts back-projected subset of acquisition data into image
365  void backward(STIRImageData& image, const STIRAcquisitionData& ad,
366  int subset_num = 0, int num_subsets = 1) const;
367 
368  protected:
369  stir::shared_ptr<stir::ProjectorByBinPair> sptr_projectors_;
370  std::shared_ptr<STIRAcquisitionData> sptr_acq_template_;
371  std::shared_ptr<STIRImageData> sptr_image_template_;
372  std::shared_ptr<STIRAcquisitionData> sptr_add_;
373  std::shared_ptr<STIRAcquisitionData> sptr_background_;
374  std::shared_ptr<PETAcquisitionSensitivityModel> sptr_asm_;
375  //shared_ptr<stir::BinNormalisation> sptr_normalisation_;
376  };
377 
393  public:
395  {
396  this->sptr_projectors_.reset(new ProjectorPairUsingMatrix);
397  }
398  void set_matrix(stir::shared_ptr<stir::ProjMatrixByBin> sptr_matrix)
399  {
400  sptr_matrix_ = sptr_matrix;
401  ((ProjectorPairUsingMatrix*)this->sptr_projectors_.get())->
402  set_proj_matrix_sptr(sptr_matrix);
403  }
404  stir::shared_ptr<stir::ProjMatrixByBin> matrix_sptr()
405  {
406  return sptr_matrix_;
407  //return ((ProjectorPairUsingMatrix*)this->sptr_projectors_.get())->
408  // get_proj_matrix_sptr();
409  }
410  virtual void set_up(
411  std::shared_ptr<STIRAcquisitionData> sptr_acq,
412  std::shared_ptr<STIRImageData> sptr_image)
413  {
414  if (!sptr_matrix_.get())
415  THROW("PETAcquisitionModelUsingMatrix setup failed - matrix not set");
416  PETAcquisitionModel::set_up(sptr_acq, sptr_image);
417  }
418 
420  void enable_cache(bool v = true)
421  {
422  sptr_matrix_->enable_cache(v);
423  }
424 
425  private:
426  stir::shared_ptr<stir::ProjMatrixByBin> sptr_matrix_;
427  };
428 
431  public:
432  PETAcquisitionModelUsingRayTracingMatrix(int num_LORs = 2) :
434  {
435  stir::shared_ptr<RayTracingMatrix> matrix_sptr(new RayTracingMatrix);
436  matrix_sptr->set_num_tangential_LORs(num_LORs);
437  set_matrix(matrix_sptr);
438  }
439  void set_num_tangential_LORs(int num_LORs)
440  {
441  //RayTracingMatrix& matrix = (RayTracingMatrix&)*matrix_sptr();
442  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
443  //std::cout << matrix.get_num_tangential_LORs() << '\n';
444  matrix.set_num_tangential_LORs(num_LORs);
445  //std::cout << get_num_tangential_LORs() << '\n';
446  }
449  {
450  auto matrix = dynamic_cast<const RayTracingMatrix&>(*matrix_sptr());
451  return matrix.get_num_tangential_LORs();
452  }
455  {
456  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
457  matrix.set_restrict_to_cylindrical_FOV(v);
458  }
461  //bool get_do_symmetry_90degrees_min_phi() const;
462  void set_do_symmetry_90degrees_min_phi(bool v = true)
463  {
464  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
465  matrix.set_do_symmetry_90degrees_min_phi(v);
466  }
467  //bool get_do_symmetry_180degrees_min_phi() const;
468  void set_do_symmetry_180degrees_min_phi(bool v = true)
469  {
470  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
471  matrix.set_do_symmetry_180degrees_min_phi(v);
472  }
473  //bool get_do_symmetry_swap_segment() const;
474  void set_do_symmetry_swap_segment(bool v = true)
475  {
476  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
477  matrix.set_do_symmetry_swap_segment(v);
478  }
479  //bool get_do_symmetry_swap_s() const;
480  void set_do_symmetry_swap_s(bool v = true)
481  {
482  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
483  matrix.set_do_symmetry_swap_s(v);
484  }
485  //bool get_do_symmetry_shift_z() const;
486  void set_do_symmetry_shift_z(bool v = true)
487  {
488  auto matrix = dynamic_cast<RayTracingMatrix&>(*matrix_sptr());
489  matrix.set_do_symmetry_shift_z(v);
490  }
491  };
492 
493  typedef PETAcquisitionModel AcqMod3DF;
494  typedef PETAcquisitionModelUsingMatrix AcqModUsingMatrix3DF;
495  typedef std::shared_ptr<AcqMod3DF> sptrAcqMod3DF;
496 
497 #ifdef STIR_WITH_NiftyPET_PROJECTOR
503  class PETAcquisitionModelUsingNiftyPET : public PETAcquisitionModel {
504  public:
505  PETAcquisitionModelUsingNiftyPET()
506  {
507  _NiftyPET_projector_pair_sptr.reset(new ProjectorPairUsingNiftyPET);
508  this->sptr_projectors_ = _NiftyPET_projector_pair_sptr;
509  // Set verbosity to 0 by default
510  _NiftyPET_projector_pair_sptr->set_verbosity(0);
511  }
512  void set_cuda_verbosity(const bool verbosity) const
513  {
514  _NiftyPET_projector_pair_sptr->set_verbosity(verbosity);
515  }
516  void set_use_truncation(const bool use_truncation) const
517  {
518  _NiftyPET_projector_pair_sptr->set_use_truncation(use_truncation);
519  }
520  protected:
521  stir::shared_ptr<stir::ProjectorPairUsingNiftyPET> _NiftyPET_projector_pair_sptr;
522  };
523  typedef PETAcquisitionModelUsingNiftyPET AcqModUsingNiftyPET3DF;
524 #endif
525 
526 #ifdef STIR_WITH_Parallelproj_PROJECTOR
532  class PETAcquisitionModelUsingParallelproj : public PETAcquisitionModel {
533  public:
534  PETAcquisitionModelUsingParallelproj()
535  {
536  this->sptr_projectors_.reset(new ProjectorByBinPairUsingParallelproj);
537  }
538  };
539  typedef PETAcquisitionModelUsingParallelproj AcqModUsingParallelproj;
540 #endif
541 
549  public:
552  virtual void unnormalise(STIRAcquisitionData& ad) const;
553  // divide by bin efficiencies (here attenuation factors), i.e. correct data in \a ad for attenuatio
554  virtual void normalise(STIRAcquisitionData& ad) const;
558  static void compute_ac_factors(
559  // input arguments
560  const STIRAcquisitionData& acq_templ,
561  const PETAttenuationModel& acq_sens_mod,
562  // output arguments
563  std::shared_ptr<STIRAcquisitionData>& af_sptr,
564  std::shared_ptr<STIRAcquisitionData>& acf_sptr)
565  {
566  af_sptr = acq_templ.clone();
567  af_sptr->fill(1.0);
568  acf_sptr = af_sptr->clone();
569  acq_sens_mod.unnormalise(*af_sptr);
570  acf_sptr->inv(0, *af_sptr);
571  }
572 
573  protected:
574  stir::shared_ptr<stir::ForwardProjectorByBin> sptr_forw_projector_;
575  };
576 
577 
578  class ListmodeToSinograms : public stir::LmToProjData {
579  public:
581 
590  //ListmodeToSinograms(const char* const par) : stir::LmToProjData(par) {}
591  ListmodeToSinograms(const char* par) : stir::LmToProjData(par) {}
592  ListmodeToSinograms() : stir::LmToProjData()
593  {
594  set_defaults();
595  fan_size = -1;
596  store_prompts = true;
597  store_delayeds = false;
598  delayed_increment = 0;
599  num_iterations = 10;
600  display_interval = 1;
601  KL_interval = 1;
602  save_interval = -1;
603  //num_events_to_store = -1;
604  }
605  void set_input(const STIRListmodeData& lm_data_v)
606  {
607  input_filename = "UNKNOWN";
608  // call stir::LmToProjData::set_input_data
609  this->set_input_data(lm_data_v.data());
610  exam_info_sptr_.reset(new ExamInfo(lm_data_ptr->get_exam_info()));
611  proj_data_info_sptr_.reset(lm_data_ptr->get_proj_data_info_sptr()->clone());
612  }
613  void set_input(std::string lm_file)
614  {
615  this->set_input(STIRListmodeData(lm_file));
616  this->input_filename = lm_file;
617  }
619 
621  void set_output(std::string proj_data_file)
622  {
623  output_filename_prefix = proj_data_file;
624  }
625  void set_template(std::string proj_data_file)
626  {
627  STIRAcquisitionDataInFile acq_data_template(proj_data_file.c_str());
628  set_template(acq_data_template);
629  }
630  void set_template(const STIRAcquisitionData& acq_data_template)
631  {
632  template_proj_data_info_ptr =
633  acq_data_template.get_proj_data_info_sptr()->create_shared_clone();
634  }
635  void set_time_interval(double start, double stop)
636  {
637  std::pair<double, double> interval(start, stop);
638  std::vector < std::pair<double, double> > intervals;
639  intervals.push_back(interval);
640  frame_defs = stir::TimeFrameDefinitions(intervals);
641  do_time_frame = true;
642  }
643  int set_flag(const char* flag, bool value)
644  {
645  if (sirf::iequals(flag, "store_prompts"))
646  store_prompts = value;
647  else if (sirf::iequals(flag, "store_delayeds"))
648  store_delayeds = value;
649 #if 0
650  else if (sirf::iequals(flag, "do_pre_normalisation"))
651  do_pre_normalisation = value;
652  else if (sirf::iequals(flag, "do_time_frame"))
653  do_time_frame = value;
654 #endif
655  else if (sirf::iequals(flag, "interactive"))
656  interactive = value;
657  else
658  return -1;
659  return 0;
660  }
661  bool get_store_prompts() const
662  {
663  return store_prompts;
664  }
665  bool get_store_delayeds() const
666  {
667  return store_delayeds;
668  }
669  virtual stir::Succeeded set_up()
670  {
671  if (LmToProjData::set_up() == Succeeded::no)
672  THROW("LmToProjData setup failed");
673  fan_size = -1;
674 #if STIR_VERSION < 060000
675  const auto max_fan_size =
676  lm_data_ptr->get_scanner_ptr()->get_max_num_non_arccorrected_bins();
677 #else
678  const auto max_fan_size =
679  lm_data_ptr->get_scanner().get_max_num_non_arccorrected_bins();
680 #endif
681  if (fan_size == -1)
682  fan_size = max_fan_size;
683  else
684  fan_size =
685  std::min(fan_size, max_fan_size);
686  half_fan_size = fan_size / 2;
687  fan_size = 2 * half_fan_size + 1;
688 
689  exam_info_sptr_->set_time_frame_definitions(frame_defs);
690  const float h = proj_data_info_sptr_->get_bed_position_horizontal();
691  const float v = proj_data_info_sptr_->get_bed_position_vertical();
692  stir::shared_ptr<ProjDataInfo> temp_proj_data_info_sptr(template_proj_data_info_ptr->clone());
693  temp_proj_data_info_sptr->set_bed_position_horizontal(h);
694  temp_proj_data_info_sptr->set_bed_position_vertical(v);
695  randoms_sptr.reset(new STIRAcquisitionDataInMemory(exam_info_sptr_, temp_proj_data_info_sptr));
696 
697  return stir::Succeeded::yes;
698  }
699  int estimate_randoms();
700  void save_randoms()
701  {
702  std::string filename = "randoms_f1g1d0b0.hs";
703  randoms_sptr->write(filename.c_str());
704  }
705  std::shared_ptr<STIRAcquisitionData> get_output()
706  {
707  std::string filename = output_filename_prefix + "_f1g1d0b0.hs";
708  return std::shared_ptr<STIRAcquisitionData>
709  (new STIRAcquisitionDataInFile(filename.c_str()));
710  }
711  std::shared_ptr<STIRAcquisitionData> get_randoms_sptr()
712  {
713  return randoms_sptr;
714  }
717  float get_time_at_which_num_prompts_exceeds_threshold(const unsigned long threshold) const;
718 
719  protected:
720  // variables for ML estimation of singles/randoms
721  int fan_size;
722  int half_fan_size;
723  int max_ring_diff_for_fansums;
724  int num_iterations;
725  int display_interval;
726  int KL_interval;
727  int save_interval;
728  stir::shared_ptr<ExamInfo> exam_info_sptr_;
729  stir::shared_ptr<ProjDataInfo> proj_data_info_sptr_;
730  stir::shared_ptr<std::vector<stir::Array<2, float> > > fan_sums_sptr;
731  stir::shared_ptr<stir::DetectorEfficiencies> det_eff_sptr;
732  std::shared_ptr<STIRAcquisitionData> randoms_sptr;
733  void compute_fan_sums_(bool prompt_fansum = false);
734  int compute_singles_();
735 // void estimate_randoms_();
736  static unsigned long compute_num_bins_(const int num_rings,
737  const int num_detectors_per_ring,
738  const int max_ring_diff, const int half_fan_size);
739  };
740 
753  class PETSingleScatterSimulator : public stir::SingleScatterSimulation
754  {
755  public:
757  PETSingleScatterSimulator() : stir::SingleScatterSimulation()
758  {}
760  PETSingleScatterSimulator(std::string filename) :
761  stir::SingleScatterSimulation(filename)
762  {}
763 
764  void set_up(std::shared_ptr<const STIRAcquisitionData> sptr_acq_template,
765  std::shared_ptr<const STIRImageData> sptr_act_image_template)
766  {
767  this->sptr_acq_template_ = sptr_acq_template;
768 
769  stir::SingleScatterSimulation::set_template_proj_data_info(
770  *sptr_acq_template_->get_proj_data_info_sptr());
771  stir::SingleScatterSimulation::set_exam_info(
772  *sptr_acq_template_->get_exam_info_sptr());
773  // check if attenuation image is set
774  try
775  {
776  auto& tmp = stir::SingleScatterSimulation::get_attenuation_image();
777  }
778  catch (...)
779  {
780  THROW("Fatal error in PETSingleScatterSimulator::set_up: attenuation_image has not been set");
781  }
782  this->set_activity_image_sptr(sptr_act_image_template);
783 
784  if (stir::SingleScatterSimulation::set_up() == Succeeded::no)
785  THROW("Fatal error in PETSingleScatterSimulator::set_up() failed.");
786  }
787 
788  void set_activity_image_sptr(std::shared_ptr<const STIRImageData> arg)
789  {
790 #if STIR_VERSION < 050000
791  // need to make a copy as the function doesn't accept a const
792  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
793  stir::SingleScatterSimulation::set_activity_image_sptr(sptr_image_copy);
794 #else
795  stir::SingleScatterSimulation::set_activity_image_sptr(arg->data_sptr());
796 #endif
797  }
798 
799  void set_attenuation_image_sptr(std::shared_ptr<const STIRImageData> arg)
800  {
801 #if STIR_VERSION < 050000
802  // need to make a copy as the function doesn't accept a const
803  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
804  stir::SingleScatterSimulation::set_density_image_sptr(sptr_image_copy);
805 #else
806  stir::SingleScatterSimulation::set_density_image_sptr(arg->data_sptr());
807 #endif
808  }
809 
810  std::shared_ptr<STIRAcquisitionData> forward(const STIRImageData& activity_img) /*TODO CONST*/
811  {
812  if (!sptr_acq_template_.get())
813  THROW("Fatal error in PETSingleScatterSimulator::forward: acquisition template not set");
814  std::shared_ptr<STIRAcquisitionData> sptr_ad =
815  sptr_acq_template_->new_acquisition_data();
816  this->forward( *sptr_ad, activity_img);
817  return sptr_ad;
818  }
819 
820  void forward(STIRAcquisitionData& ad, const STIRImageData& activity_img) /* TODO CONST*/
821  {
822  stir::shared_ptr<ProjData> sptr_fd = ad.data();
823  this->set_output_proj_data_sptr(sptr_fd);
824  // hopefully STIR checks if template consistent with input data
825  this->process_data();
826  }
827 
828  protected:
829  std::shared_ptr<const STIRAcquisitionData> sptr_acq_template_;
830 
831  };
832 
845  class PETScatterEstimator : private stir::ScatterEstimation
846  {
847  using recon_type = stir::OSMAPOSLReconstruction<DiscretisedDensity<3,float>>;
848  public:
850 
855  PETScatterEstimator() : stir::ScatterEstimation()
856  {
857  auto obj_sptr = std::make_shared<PoissonLogLikelihoodWithLinearModelForMeanAndProjData<DiscretisedDensity<3,float>>>();
858  auto recon_sptr = std::make_shared<recon_type>();
859  recon_sptr->set_num_subiterations(8);
860  recon_sptr->set_num_subsets(7); // this works for the mMR. TODO
861  recon_sptr->set_disable_output(true);
862  recon_sptr->set_objective_function_sptr(obj_sptr);
863  stir::shared_ptr<stir::SeparableGaussianImageFilter<float> >
864  filter_sptr(new stir::SeparableGaussianImageFilter<float>);
865  filter_sptr->set_fwhms(stir::make_coordinate(15.F,15.F,15.F));
866  recon_sptr->set_post_processor_sptr(filter_sptr);
867  stir::ScatterEstimation::set_reconstruction_method_sptr(recon_sptr);
868  }
870  PETScatterEstimator(std::string filename) :
871  stir::ScatterEstimation(filename)
872  {}
873 
875  void set_input_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
876  {
877  stir::ScatterEstimation::set_input_proj_data_sptr(arg->data());
878  }
880  void set_attenuation_correction_factors_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
881  {
882  stir::ScatterEstimation::set_attenuation_correction_proj_data_sptr(arg->data());
883  }
885  void set_asm(std::shared_ptr<PETAcquisitionSensitivityModel> arg)
886  {
887  stir::ScatterEstimation::set_normalisation_sptr(arg->data());
888  }
890  void set_background_sptr(std::shared_ptr<const STIRAcquisitionData> arg)
891  {
892  stir::ScatterEstimation::set_background_proj_data_sptr(arg->data());
893  }
894 
895  void set_attenuation_image_sptr(std::shared_ptr<const STIRImageData> arg)
896  {
897 #if STIR_VERSION < 050000
898  // need to make a copy as the function doesn't accept a const
899  stir::shared_ptr<Image3DF> sptr_image_copy(arg->data_sptr()->clone());
900  stir::ScatterEstimation::set_attenuation_image_sptr(sptr_image_copy);
901 #else
902  stir::ScatterEstimation::set_attenuation_image_sptr(arg->data_sptr());
903 #endif
904  }
905 
907 
913  void set_output_prefix(std::string prefix)
914  {
915  stir::ScatterEstimation::set_export_scatter_estimates_of_each_iteration(!prefix.empty());
916  stir::ScatterEstimation::set_output_scatter_estimate_prefix(prefix);
917  }
918 
919  void set_num_iterations(int arg)
920  {
921  stir::ScatterEstimation::set_num_iterations(arg);
922  }
923 
924  int get_num_iterations() const
925  {
926  return stir::ScatterEstimation::get_num_iterations();
927  }
928 
929  void set_OSEM_num_subiterations(int arg)
930  {
931  this->get_reconstruction_method().set_num_subiterations(arg);
932  }
933 
934  int get_OSEM_num_subiterations() const
935  {
936  return this->get_reconstruction_method().get_num_subiterations();
937  }
938 
939  void set_OSEM_num_subsets(int arg)
940  {
941  this->get_reconstruction_method().set_num_subsets(arg);
942  this->_already_set_up_sirf = false;
943  }
944 
945  int get_OSEM_num_subsets() const
946  {
947  return this->get_reconstruction_method().get_num_subsets();
948  }
949 
951  void set_max_scale_value(float v)
952  {
953  stir::ScatterEstimation::set_max_scale_value(v);
954  }
955 
957  void set_min_scale_value(float v)
958  {
959  stir::ScatterEstimation::set_min_scale_value(v);
960  }
961 
962  std::shared_ptr<STIRAcquisitionData> get_scatter_estimate(int est_num = -1) const
963  {
964  if (est_num == -1) // Get the last one
965  est_num = num_scatter_iterations;
966  if (est_num == num_scatter_iterations)
967  return get_output();
968  // try to read from file
969  if (output_scatter_estimate_prefix.empty())
970  THROW("output_scatter_estimate_prefix not set, so scatter estimates were not saved to file.");
971  const std::string filename = output_scatter_estimate_prefix + "_" + std::to_string(est_num) + ".hs";
972  return std::make_shared<STIRAcquisitionDataInFile>(filename.c_str());
973  }
974 
976  std::shared_ptr<STIRAcquisitionData> get_output() const
977  {
978  auto stir_proj_data_sptr = stir::ScatterEstimation::get_output();
979  if (!stir_proj_data_sptr)
980  THROW("output not yet computed");
981  std::shared_ptr<STIRAcquisitionData> sptr_acq_data
982  (STIRAcquisitionData::storage_template()->same_acquisition_data(stir_proj_data_sptr->get_exam_info_sptr(),
983  stir_proj_data_sptr->get_proj_data_info_sptr()->create_shared_clone()));
984  sptr_acq_data->data()->fill(*stir_proj_data_sptr);
985  return sptr_acq_data;
986  }
987 
989 
995  Succeeded set_up()
996  {
997  // reconstruct an smooth image with a large voxel size
998  const float zoom = 0.2F;
999  stir::shared_ptr<Voxels3DF>
1000  image_sptr(new Voxels3DF(MAKE_SHARED<stir::ExamInfo>(*this->get_input_data()->get_exam_info_sptr()),
1001  *this->get_input_data()->get_proj_data_info_sptr(),
1002  zoom));
1003  image_sptr->fill(1.F);
1004  stir::ScatterEstimation::set_initial_activity_image_sptr(image_sptr);
1005  if (stir::ScatterEstimation::set_up() == Succeeded::no)
1006  THROW("scatter estimation set_up failed");
1007  this->_already_set_up_sirf = true;
1008  return Succeeded::yes;
1009  }
1010  void process()
1011  {
1012  if (!this->_already_set_up_sirf)
1013  THROW("scatter estimation needs to be set-up first");
1014  if (!stir::ScatterEstimation::already_setup())
1015  THROW("scatter estimation needs to be set-up first");
1016  if (stir::ScatterEstimation::process_data() == Succeeded::no)
1017  THROW("scatter estimation failed");
1018  }
1019  private:
1021  bool _already_set_up_sirf;
1022 
1024  recon_type& get_reconstruction_method() const
1025  {
1026  return dynamic_cast<recon_type&>(*this->reconstruction_template_sptr);
1027  }
1028  };
1029 
1039  class xSTIR_Box3D : public stir::Box3D {
1040  public:
1041  void set_length_x(float v)
1042  {
1043  length_x = v;
1044  }
1045  void set_length_y(float v)
1046  {
1047  length_y = v;
1048  }
1049  void set_length_z(float v)
1050  {
1051  length_z = v;
1052  }
1053  float get_length_x() const
1054  {
1055  return length_x;
1056  }
1057  float get_length_y() const
1058  {
1059  return length_y;
1060  }
1061  float get_length_z() const
1062  {
1063  return length_z;
1064  }
1065  };
1066 
1067  class xSTIR_GeneralisedPrior3DF : public stir::GeneralisedPrior < Image3DF > {
1068  public:
1069  void multiply_with_Hessian(Image3DF& output, const Image3DF& curr_image_est,
1070  const Image3DF& input) const
1071  {
1072  output.fill(0.0);
1073  accumulate_Hessian_times_input(output, curr_image_est, input);
1074  }
1075 // bool post_process() {
1076 // return post_processing();
1077 // }
1078  };
1079 
1080  class xSTIR_QuadraticPrior3DF : public stir::QuadraticPrior < float > {
1081  public:
1082  void only2D(int only) {
1083  only_2D = only != 0;
1084  }
1085  };
1086 
1087  class xSTIR_LogcoshPrior3DF : public stir::LogcoshPrior < float > {
1088  public:
1089  void only2D(int only) {
1090  only_2D = only != 0;
1091  }
1092  };
1093 
1094  class xSTIR_RelativeDifferencePrior3DF : public stir::RelativeDifferencePrior < float > {
1095  public:
1096  void only2D(int only) {
1097  only_2D = only != 0;
1098  }
1099  };
1100 
1101  class xSTIR_PLSPrior3DF : public stir::PLSPrior < float > {
1102  public:
1103  void only2D(int only) {
1104  only_2D = only != 0;
1105  }
1106  };
1107 
1109  public stir::GeneralisedObjectiveFunction < Image3DF > {
1110  public:
1111  void multiply_with_Hessian(Image3DF& output, const Image3DF& curr_image_est,
1112  const Image3DF& input, const int subset) const
1113  {
1114  output.fill(0.0);
1115  if (subset >= 0)
1116  accumulate_sub_Hessian_times_input(output, curr_image_est, input, subset);
1117  else {
1118  for (int s = 0; s < get_num_subsets(); s++) {
1119  accumulate_sub_Hessian_times_input(output, curr_image_est, input, s);
1120  }
1121  }
1122  }
1123 
1124 // bool post_process() {
1125 // return post_processing();
1126 // }
1127  };
1128 
1129  //typedef xSTIR_GeneralisedObjectiveFunction3DF ObjectiveFunction3DF;
1130 
1132  public stir::PoissonLogLikelihoodWithLinearModelForMeanAndProjData < Image3DF > {
1133  public:
1134  void set_input_file(const char* filename) {
1135  input_filename = filename;
1136  }
1137  void set_acquisition_data(std::shared_ptr<STIRAcquisitionData> sptr)
1138  {
1139  sptr_ad_ = sptr;
1140  set_proj_data_sptr(sptr->data());
1141  }
1142  void set_acquisition_model(std::shared_ptr<AcqMod3DF> sptr_am);
1143 
1144  std::shared_ptr<AcqMod3DF> acquisition_model_sptr()
1145  {
1146  return sptr_am_;
1147  }
1148  private:
1149  std::shared_ptr<STIRAcquisitionData> sptr_ad_;
1150  std::shared_ptr<AcqMod3DF> sptr_am_;
1151  };
1152 
1155 
1157  public stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin<Image3DF> {
1158  public:
1159 #if 0
1160  // this functionality was for skip_lm_input_file, but this is disabled for now
1161  void set_acquisition_data(std::shared_ptr<PETAcquisitionData> sptr)
1162  {
1163  sptr_ad_ = sptr;
1164  set_proj_data_info(*sptr->data());
1165  }
1166 #endif
1167  void set_acquisition_model(std::shared_ptr<AcqMod3DF> sptr_am);
1168 
1169  void set_cache_path(const std::string filepath)
1170  {
1171  stir::PoissonLogLikelihoodWithLinearModelForMeanAndListModeDataWithProjMatrixByBin<Image3DF>::
1172  set_cache_path(filepath);
1173  }
1174 
1175  void set_time_interval(double start, double stop)
1176  {
1177  std::pair<double, double> interval(start, stop);
1178  std::vector < std::pair<double, double> > intervals;
1179  intervals.push_back(interval);
1180  frame_defs = stir::TimeFrameDefinitions(intervals);
1181  do_time_frame = true;
1182  }
1183 
1184  private:
1185  //std::shared_ptr<PETAcquisitionData> sptr_ad_;
1186  std::shared_ptr<PETAcquisitionModelUsingMatrix> sptr_am_;
1187  };
1188 
1190 
1192  public stir::IterativeReconstruction < Image3DF > {
1193  public:
1194 /* bool post_process() {
1195  //std::cout << "in xSTIR_IterativeReconstruction3DF.post_process...\n";
1196  if (this->output_filename_prefix.length() < 1)
1197  this->set_output_filename_prefix("reconstructed_image");
1198  return post_processing();
1199  }*/
1200  void update(Image3DF &image) {
1201  update_estimate(image);
1202  end_of_iteration_processing(image);
1203  subiteration_num++;
1204  }
1205  void update(STIRImageData& id)
1206  {
1207  update(id.data());
1208  }
1209  void update(stir::shared_ptr<STIRImageData> sptr_id)
1210  {
1211  update(*sptr_id);
1212  }
1213  int& subiteration() {
1214  return subiteration_num;
1215  }
1216  int subiteration() const {
1217  return subiteration_num;
1218  }
1219  void set_initial_estimate_file(const char* filename) {
1220  initial_data_filename = filename;
1221  }
1222  };
1223 
1224  class xSTIR_OSMAPOSLReconstruction3DF : public stir::OSMAPOSLReconstruction< Image3DF > {
1225  public:
1226  int& subiteration() {
1227  return subiteration_num;
1228  }
1229  int subiteration() const {
1230  return subiteration_num;
1231  }
1232  };
1233 
1234  class xSTIR_KOSMAPOSLReconstruction3DF : public stir::KOSMAPOSLReconstruction< Image3DF > {
1235  public:
1236  void compute_kernelised_image_x(
1237  Image3DF& kernelised_image_out,
1238  const Image3DF& image_to_kernelise,
1239  const Image3DF& current_alpha_estimate)
1240  {
1241  compute_kernelised_image(
1242  kernelised_image_out,
1243  image_to_kernelise,
1244  current_alpha_estimate);
1245  }
1246  };
1247 
1248  class xSTIR_OSSPSReconstruction3DF : public stir::OSSPSReconstruction < Image3DF > {
1249  public:
1250  float& relaxation_parameter_value() {
1251  return relaxation_parameter;
1252  }
1253  float& relaxation_gamma_value() {
1254  return relaxation_gamma;
1255  }
1256  double& upper_bound_value() {
1257  return upper_bound;
1258  }
1259  };
1260 
1261  class xSTIR_FBP2DReconstruction : public stir::FBP2DReconstruction {
1262  public:
1264  {
1265  _is_set_up = false;
1266  }
1267  void set_input(const STIRAcquisitionData& acq)
1268  {
1269  set_input_data(acq.data());
1270  }
1271  void set_zoom(float v)
1272  {
1273  set_zoom_xy(v);
1274  _is_set_up = false;
1275  }
1276  void set_alpha_ramp(double alpha)
1277  {
1278  // does not work!
1279  //assert(alpha > 0 && alpha <= 1.0);
1280  if (!(alpha > 0 && alpha <= 1.0))
1281  throw LocalisedException
1282  ("wrong ramp filter parameter alpha", __FILE__, __LINE__);
1283  alpha_ramp = alpha;
1284  }
1285  void set_frequency_cut_off(double fc)
1286  {
1287  if (!(fc > 0 && fc <= 0.5))
1288  throw LocalisedException
1289  ("wrong frequency cut-off", __FILE__, __LINE__);
1290  fc_ramp = fc;
1291  }
1292  void set_up(std::shared_ptr<STIRImageData> sptr_id)
1293  {
1294  _sptr_image_data.reset(new STIRImageData(*sptr_id));
1295  stir::Succeeded s = stir::Reconstruction<Image3DF>::set_up(_sptr_image_data->data_sptr());
1296  if (s != stir::Succeeded::yes)
1297  THROW("stir::Reconstruction setup failed");
1298  _is_set_up = true;
1299  }
1300  void cancel_setup()
1301  {
1302  _is_set_up = false;
1303  }
1304  void process()
1305  {
1306  stir::Succeeded s = stir::Succeeded::no;
1307  if (!_is_set_up) {
1308  stir::shared_ptr<Image3DF> sptr_image(construct_target_image_ptr());
1309  _sptr_image_data.reset(new STIRImageData(sptr_image));
1310  stir::Reconstruction<Image3DF>::set_up(sptr_image);
1311  s = reconstruct(sptr_image);
1312  }
1313  else
1314  s = reconstruct(_sptr_image_data->data_sptr());
1315  if (s != stir::Succeeded::yes)
1316  THROW("stir::AnalyticReconstruction::reconstruct failed");
1317  }
1318  std::shared_ptr<STIRImageData> get_output()
1319  {
1320  return _sptr_image_data;
1321  }
1322  protected:
1323  bool _is_set_up;
1324  std::shared_ptr<STIRImageData> _sptr_image_data;
1325  };
1326 
1328  public stir::SeparableGaussianImageFilter<float> {
1329  public:
1330  //stir::Succeeded set_up(const STIRImageData& id)
1331  //{
1332  // return virtual_set_up(id.data());
1333  //}
1334  //void apply(STIRImageData& id)
1335  //{
1336  // virtual_apply(id.data());
1337  //}
1338  void set_fwhms_xyz(char xyz, float f)
1339  {
1340  stir::BasicCoordinate<3, float> v = get_fwhms();
1341  switch (xyz) {
1342  case 'z':
1343  v[1] = f;
1344  break;
1345  case 'y':
1346  v[2] = f;
1347  break;
1348  case 'x':
1349  v[3] = f;
1350  }
1351  set_fwhms(v);
1352  }
1353  void set_max_kernel_sizes_xyz(char xyz, int s)
1354  {
1355  stir::BasicCoordinate<3, int> v = get_max_kernel_sizes();
1356  switch (xyz) {
1357  case 'z':
1358  v[1] = s;
1359  break;
1360  case 'y':
1361  v[2] = s;
1362  break;
1363  case 'x':
1364  v[3] = s;
1365  }
1366  set_max_kernel_sizes(v);
1367  }
1368  };
1369 }
1370 
1371 #endif
Definition: LocalisedException.h:32
Definition: JacobiCG.h:37
Definition: stir_x.h:578
void set_output(std::string proj_data_file)
Specifies the prefix for the output file(s),.
Definition: stir_x.h:621
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:591
Definition: Operator.h:7
Class for the product of backward and forward projectors of a PET acquisition model.
Definition: stir_x.h:206
Class for a PET acquisition model.
Definition: stir_x.h:197
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:239
Ray tracing matrix implementation of the PET acquisition model.
Definition: stir_x.h:392
void enable_cache(bool v=true)
Enables or disables the caching mechanism.
Definition: stir_x.h:420
int get_num_tangential_LORs()
@
Definition: stir_x.h:448
void set_restrict_to_cylindrical_FOV(bool v=true)
Enables or disables using a circular axial FOV (vs rectangular)
Definition: stir_x.h:454
Listmode-to-sinograms converter.
Definition: stir_x.h:89
Attenuation model.
Definition: stir_x.h:548
virtual void unnormalise(STIRAcquisitionData &ad) const
multiply by bin efficiencies (here attenuation factors), i.e. attenuate data in ad
Definition: stir_x.cpp:449
static void compute_ac_factors(const STIRAcquisitionData &acq_templ, const PETAttenuationModel &acq_sens_mod, std::shared_ptr< STIRAcquisitionData > &af_sptr, std::shared_ptr< STIRAcquisitionData > &acf_sptr)
Definition: stir_x.h:558
Class for estimating the scatter contribution in PET projection data.
Definition: stir_x.h:846
void set_attenuation_correction_factors_sptr(std::shared_ptr< const STIRAcquisitionData > arg)
Set attenuation correction factors as acq_data.
Definition: stir_x.h:880
void set_max_scale_value(float v)
Set maximal scale factor value of the SSS algorithm to use.
Definition: stir_x.h:951
PETScatterEstimator()
constructor.
Definition: stir_x.h:855
void set_min_scale_value(float v)
Set minimal scale factor value of the SSS algorithm to use.
Definition: stir_x.h:957
void set_input_sptr(std::shared_ptr< const STIRAcquisitionData > arg)
Set the input data.
Definition: stir_x.h:875
std::shared_ptr< STIRAcquisitionData > get_output() const
get last scatter estimate
Definition: stir_x.h:976
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:890
Succeeded set_up()
set up the object and performs checks
Definition: stir_x.h:995
void set_asm(std::shared_ptr< PETAcquisitionSensitivityModel > arg)
Set acquisition sensitivity model specifying detection efficiencies (without attenuation)
Definition: stir_x.h:885
void set_output_prefix(std::string prefix)
Set prefix for filenames with scatter estimates.
Definition: stir_x.h:913
PETScatterEstimator(std::string filename)
Overloaded constructor which takes the parameter file.
Definition: stir_x.h:870
Class for simulating the scatter contribution to PET data.
Definition: stir_x.h:754
PETSingleScatterSimulator(std::string filename)
Overloaded constructor which takes the parameter file.
Definition: stir_x.h:760
PETSingleScatterSimulator()
Default constructor.
Definition: stir_x.h:757
STIR ProjData wrapper with added functionality.
Definition: stir_data_containers.h:161
In-file implementation of STIRAcquisitionData.
Definition: stir_data_containers.h:541
STIR DiscretisedDensity<3, float> wrapper with added functionality.
Definition: stir_data_containers.h:965
Accessor classes.
Definition: stir_x.h:1039
Definition: stir_x.h:1261
Definition: stir_x.h:1067
Definition: stir_x.h:1087
Definition: stir_x.h:1224
Definition: stir_x.h:1248
Definition: stir_x.h:1101
Definition: stir_x.h:1080
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:150
Specification file for data handling types not present in STIR.