STIR  6.2.0
ReconstructionTests.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2020, University College London
3  This file is part of STIR.
4  SPDX-License-Identifier: Apache-2.0
5  See STIR/LICENSE.txt for details
6 */
14 #include "stir/RunTests.h"
18 #include "stir/ProjDataInMemory.h"
20 #include "stir/IO/read_from_file.h"
21 #include "stir/IO/write_to_file.h"
22 #include "stir/ArrayFunction.h"
24 #include "stir/Verbosity.h"
25 #include "stir/error.h"
26 
27 START_NAMESPACE_STIR
28 
33 template <class TargetT>
35 {
36 public:
38  explicit inline ReconstructionTests(const std::string& proj_data_filename = "", const std::string& density_filename = "");
39 
40  ~ReconstructionTests() override {}
41 
43  virtual inline std::unique_ptr<ProjDataInfo> construct_default_proj_data_info_uptr() const;
44 
46 
51  virtual inline void construct_input_data();
53 
54  virtual inline void construct_reconstructor() = 0;
56 
59  virtual inline void reconstruct(shared_ptr<TargetT> target_sptr);
61 
62  virtual inline void compare(const shared_ptr<const TargetT> output_sptr);
63 
64 protected:
65  std::string _proj_data_filename;
66  std::string _input_density_filename;
67  shared_ptr<ProjDataInMemory> _proj_data_sptr;
68  shared_ptr<TargetT> _input_density_sptr;
69  shared_ptr<Reconstruction<TargetT>> _recon_sptr;
70 };
71 
72 template <class TargetT>
73 ReconstructionTests<TargetT>::ReconstructionTests(const std::string& proj_data_filename, const std::string& density_filename)
74  : _proj_data_filename(proj_data_filename),
75  _input_density_filename(density_filename)
76 {}
77 
78 template <class TargetT>
79 std::unique_ptr<ProjDataInfo>
81 {
82  // construct a small scanner and sinogram
83  shared_ptr<Scanner> scanner_sptr(new Scanner(Scanner::E953));
84  scanner_sptr->set_num_rings(5);
85  std::unique_ptr<ProjDataInfo> proj_data_info_uptr(ProjDataInfo::ProjDataInfoCTI(scanner_sptr,
86  /*span=*/3,
87  /*max_delta=*/4,
88  /*num_views=*/128,
89  /*num_tang_poss=*/128));
90  return proj_data_info_uptr;
91 }
92 
93 template <class TargetT>
94 void
96 {
97  Verbosity::set(1);
98  if (this->_proj_data_filename.empty())
99  {
100  shared_ptr<ProjDataInfo> proj_data_info_sptr(this->construct_default_proj_data_info_uptr());
101  shared_ptr<ExamInfo> exam_info_sptr(new ExamInfo);
102  exam_info_sptr->imaging_modality = ImagingModality::PT;
103  _proj_data_sptr.reset(new ProjDataInMemory(exam_info_sptr, proj_data_info_sptr));
104 
105  std::cerr << "Will run tests with projection data with the following settings:\n" << proj_data_info_sptr->parameter_info();
106  }
107  else
108  {
109  shared_ptr<ProjData> proj_data_sptr = ProjData::read_from_file(this->_proj_data_filename);
110  _proj_data_sptr.reset(new ProjDataInMemory(*proj_data_sptr));
111  }
112 
113  if (this->_input_density_filename.empty())
114  {
115  CartesianCoordinate3D<float> origin(0, 0, 0);
116  const float zoom = .7F;
117 
118  shared_ptr<VoxelsOnCartesianGrid<float>> vox_sptr(new VoxelsOnCartesianGrid<float>(
119  this->_proj_data_sptr->get_exam_info_sptr(), *this->_proj_data_sptr->get_proj_data_info_sptr(), zoom, origin));
120 
121  // create very long cylinder, such that we don't have to think about origin
122  EllipsoidalCylinder cylinder(/*length_z*/ 1000.F,
123  /*radius_y*/ 100.F,
124  /*radius_x*/ 90.F,
125  CartesianCoordinate3D<float>(0.F, 0.F, 0.F));
126  cylinder.construct_volume(*vox_sptr, CartesianCoordinate3D<int>(2, 2, 2));
127 
128  // filter it a bit to avoid too high frequency stuff creating trouble in the comparison
130  filter.set_fwhms(make_coordinate(10.F, 10.F, 10.F));
131  filter.set_up(*vox_sptr);
132  filter.apply(*vox_sptr);
133  this->_input_density_sptr = vox_sptr;
134  }
135  else
136  {
137  shared_ptr<TargetT> aptr(read_from_file<TargetT>(this->_input_density_filename));
138  this->_input_density_sptr = aptr;
139  }
140 
141  // forward project
142  {
143  shared_ptr<ProjMatrixByBin> PM_sptr(new ProjMatrixByBinUsingRayTracing);
144  shared_ptr<ForwardProjectorByBin> fwd_proj_sptr = MAKE_SHARED<ForwardProjectorByBinUsingProjMatrixByBin>(PM_sptr);
145  fwd_proj_sptr->set_up(this->_proj_data_sptr->get_proj_data_info_sptr(), this->_input_density_sptr);
146  fwd_proj_sptr->set_input(*this->_input_density_sptr);
147  fwd_proj_sptr->forward_project(*this->_proj_data_sptr);
148  }
149 }
150 
151 template <class TargetT>
152 void
153 ReconstructionTests<TargetT>::reconstruct(shared_ptr<TargetT> target_sptr)
154 {
155  this->_recon_sptr->set_input_data(this->_proj_data_sptr);
156  this->_recon_sptr->set_disable_output(true);
157  // set a prefix anyway, as some reconstruction algorithms write some files even with disabled output
158  this->_recon_sptr->set_output_filename_prefix("test_recon_" + this->_recon_sptr->method_info());
159  if (this->_recon_sptr->set_up(target_sptr) == Succeeded::no)
160  error("recon::set_up() failed");
161 
162  if (this->_recon_sptr->reconstruct(target_sptr) == Succeeded::no)
163  error("recon::reconstruct() failed");
164 
165  std::cerr << "\n================================\nReconstruction " << this->_recon_sptr->method_info() << " finished!\n\n";
166 }
167 
168 template <class TargetT>
169 void
170 ReconstructionTests<TargetT>::compare(const shared_ptr<const TargetT> output_sptr)
171 {
172  if (!check(this->_input_density_sptr->has_same_characteristics(*output_sptr), "output image has wrong characteristics"))
173  return;
174 
175  shared_ptr<TargetT> diff_sptr(output_sptr->clone());
176  *diff_sptr -= *this->_input_density_sptr;
177  const float diff_min = diff_sptr->find_min();
178  const float diff_max = diff_sptr->find_max();
179  const float max_input = this->_input_density_sptr->find_max();
180  in_place_abs(*diff_sptr);
181  const float mean_abs_error = diff_sptr->sum() / this->_input_density_sptr->size_all();
182  std::cerr << "Reconstruction diff relative range: "
183  << "[" << diff_min / max_input << ", " << diff_max / max_input << "]\n"
184  << "mean abs diff normalised was " << mean_abs_error / max_input << "\n";
185  if (!check_if_less(-0.3F, diff_min / max_input, "relative diff min")
186  || !check_if_less(diff_max / max_input, .3F, "relative diff max")
187  || !check_if_less(mean_abs_error / max_input, .01F, "relative mean abs diff"))
188  {
189  const std::string prefix = "test_recon_" + this->_recon_sptr->method_info();
190  write_to_file(prefix + "_output.hv", *output_sptr);
191  write_to_file(prefix + "_original.hv", *this->_input_density_sptr);
192  write_to_file(prefix + "_diff.hv", *diff_sptr);
193  }
194 }
195 
196 END_NAMESPACE_STIR
This class is used to represent voxelised densities on a cuboid grid (3D).
Definition: FBP3DRPReconstruction.h:43
A class which reads/writes projection data from/to memory.
Definition: ProjDataInMemory.h:38
virtual void construct_volume(VoxelsOnCartesianGrid< float > &image, const CartesianCoordinate3D< int > &num_samples) const
construct an image representation the shape in a discretised manner
Definition: Shape3D.cxx:100
Succeeded apply(DiscretisedDensity< num_dimensions, elemT > &data)
Calls set_up() (if not already done before) and process data in-place.
Definition: DataProcessor.inl:66
Declaration of class stir::EllipsoidalCylinder.
declares the stir::Reconstruction class
definition of stir::ForwardProjectorByBinUsingProjMatrixByBin
Array< 1, elemT > & in_place_abs(Array< 1, elemT > &v)
Replace elements by their absolute value, 1D version.
Definition: ArrayFunction.inl:82
A class in the DataProcessor hierarchy that implements Gaussian filtering.
Definition: SeparableGaussianImageFilter.h:51
Declaration of class stir::ProjDataInMemory.
This include file provides some additional functionality for stir::Array objects. ...
Declaration of stir::error()
unique_ptr< DataT > read_from_file(const FileSignature &signature, FileT file)
Function that reads data from file using the default InputFileFormatRegistry, using the provided File...
Definition: read_from_file.h:46
Declaration of stir::write_to_file function (providing easy access to the default stir::OutputFileFor...
Base class for simple test on reconstruction.
Definition: ReconstructionTests.h:34
A class for storing some info on the scanner.
Definition: Scanner.h:107
std::string write_to_file(const std::string &filename, const DataT &data)
Function that writes data to file using the default OutputFileFormat.
Definition: write_to_file.h:47
Computes projection matrix elements for VoxelsOnCartesianGrid images by using a Length of Intersectio...
Definition: ProjMatrixByBinUsingRayTracing.h:112
A base class for making test classesWith a derived class, an application could look like...
Definition: RunTests.h:71
Three-dimensional ellipsoidal cylinder.
Definition: EllipsoidalCylinder.h:67
stir::ProjMatrixByBinUsingRayTracing&#39;s definition
Declaration of class stir::Verbosity.
void error(const char *const s,...)
Print error with format string a la printf and throw exception.
Definition: error.cxx:42
a class for storing information about 1 exam (or scan)
Definition: ExamInfo.h:41
Declaration of class stir::SeparableGaussianImageFilter.
Succeeded set_up(const DiscretisedDensity< num_dimensions, elemT > &data)
Initialises any internal data (if necessary) using data as a template for sizes, sampling distances e...
Definition: DataProcessor.inl:32
Declaration of stir::read_from_file functions (providing easy access to class stir::InputFileFormatRe...
defines the stir::RunTests class