STIR  6.2.0
test_IO.h
Go to the documentation of this file.
1 //
2 //
25 /*
26  Copyright (C) 2002- 2011, Hammersmith Imanet Ltd
27  Copyright (C) 2018- , University College London
28 
29  This file is part of STIR.
30 
31  SPDX-License-Identifier: Apache-2.0
32 
33  See STIR/LICENSE.txt for details
34 */
35 
36 #include "stir/RunTests.h"
38 #include "stir/is_null_ptr.h"
39 #include "stir/Succeeded.h"
41 #include "stir/IO/read_from_file.h"
42 #ifdef HAVE_LLN_MATRIX
43 # include "stir/IO/ECAT6OutputFileFormat.h" // need this for test on pixel_size
44 #endif
45 #include <fstream>
46 
47 START_NAMESPACE_STIR
48 
68 template <class A>
69 class IOTests : public RunTests
70 {
71 public:
72  IOTests(std::istream& in);
73 
74  void run_tests() override;
75 
76 protected:
77  void set_up();
78  virtual void create_image() = 0;
79  virtual void write_image();
80  virtual void read_image();
81  virtual void check_result() = 0;
82  shared_ptr<VoxelsOnCartesianGrid<float>> create_single_image();
83  void compare_images(const VoxelsOnCartesianGrid<float>& im_1, const VoxelsOnCartesianGrid<float>& im_2);
84  void check_exam_info(const ExamInfo& exm_inf_1, const ExamInfo& exm_inf_2);
85 
86  std::istream& _in;
87  shared_ptr<OutputFileFormat<A>> _output_file_format_sptr;
88  KeyParser _parser;
89  std::string _filename;
90  shared_ptr<A> _image_to_write_sptr;
91  shared_ptr<A> _image_to_read_sptr;
92 };
93 
94 template <class A>
95 IOTests<A>::IOTests(std::istream& in)
96  : _in(in)
97 {}
98 
99 template <class A>
100 void
102 {
103  _filename = "STIRtmp";
104 
105  _output_file_format_sptr.reset();
106  _parser.add_start_key("Test OutputFileFormat Parameters");
107  _parser.add_parsing_key("output file format type", &_output_file_format_sptr);
108  _parser.add_stop_key("END");
109 
110  std::cerr << "Testing OutputFileFormat parsing function..." << std::endl;
111  std::cerr << "WARNING: will overwite files called STIRtmp*\n";
112 
113  if (!check(_parser.parse(_in), "parsing failed"))
114  return;
115 
116  if (!check(!is_null_ptr(_output_file_format_sptr), "parsing failed to set _output_file_format_sptr"))
117  return;
118 }
119 
120 template <class A>
121 shared_ptr<VoxelsOnCartesianGrid<float>>
123 {
124  // construct density image
125 #ifdef HAVE_LLN_MATRIX
126  USING_NAMESPACE_ECAT
127  USING_NAMESPACE_ECAT6
128  // TODO get next info from OutputFileFormat class instead of hard-wiring
129  // this in here
130  const bool supports_different_xy_pixel_sizes
131  = dynamic_cast<ECAT6OutputFileFormat const* const>(_output_file_format_sptr.get()) == 0 ? true : false;
132  const bool supports_origin_z_shift
133  = dynamic_cast<ECAT6OutputFileFormat const* const>(_output_file_format_sptr.get()) == 0 ? true : false;
134  const bool supports_origin_xy_shift = true;
135 #else
136  const bool supports_different_xy_pixel_sizes = true;
137  const bool supports_origin_z_shift = true;
138  const bool supports_origin_xy_shift = true;
139 #endif
140 
141  CartesianCoordinate3D<float> origin(0.F, 0.F, 0.F);
142  if (supports_origin_xy_shift)
143  {
144  origin.x() = 2.4F;
145  origin.y() = -3.5F;
146  }
147  if (supports_origin_z_shift)
148  {
149  origin.z() = 6.4F;
150  }
151 
152  CartesianCoordinate3D<float> grid_spacing(3.F, 4.F, supports_different_xy_pixel_sizes ? 5.F : 4.F);
153 
155 
156  shared_ptr<ExamInfo> exam_info_sptr(new ExamInfo);
157  exam_info_sptr->time_frame_definitions.set_num_time_frames(1);
158  exam_info_sptr->time_frame_definitions.set_time_frame(1, 10, 100);
159  exam_info_sptr->start_time_in_secs_since_1970 = double(1277478034);
160  exam_info_sptr->set_high_energy_thres(100.);
161  exam_info_sptr->set_low_energy_thres(5.);
162 
163  shared_ptr<VoxelsOnCartesianGrid<float>> single_image_sptr(
164  new VoxelsOnCartesianGrid<float>(exam_info_sptr, range, origin, grid_spacing));
165  // make reference for convenience
166  VoxelsOnCartesianGrid<float>& single_image = *single_image_sptr;
167 
168  // fill with some data
169  for (int z = single_image.get_min_z(); z <= single_image.get_max_z(); ++z)
170  for (int y = single_image.get_min_y(); y <= single_image.get_max_y(); ++y)
171  for (int x = single_image.get_min_x(); x <= single_image.get_max_x(); ++x)
172  single_image[z][y][x] = 3 * sin(static_cast<float>(x * _PI) / single_image.get_max_x())
173  * sin(static_cast<float>(y + 10 * _PI) / single_image.get_max_y())
174  * cos(static_cast<float>(z * _PI / 3) / single_image.get_max_z());
175 
176  return single_image_sptr;
177 }
178 
179 template <class A>
180 void
182 {
183  // write to file
184  const Succeeded success = _output_file_format_sptr->write_to_file(_filename, *_image_to_write_sptr);
185 
186  check(success == Succeeded::yes, "failed writing");
187 }
188 
189 template <class A>
190 void
192 {
193  // now read it back
194  _image_to_read_sptr = read_from_file<A>(_filename);
195 
196  check(!is_null_ptr(_image_to_read_sptr), "failed reading");
197 }
198 
199 template <class A>
200 void
202 {
203  set_tolerance(.000001);
204 
205  if (_output_file_format_sptr->get_type_of_numbers().integer_type())
206  {
207  set_tolerance(10. * im_1.find_max()
208  / pow(2., static_cast<double>(_output_file_format_sptr->get_type_of_numbers().size_in_bits())));
209  }
210 
211  check_if_equal(im_1.get_voxel_size(), im_2.get_voxel_size(), "test on read and written file via image voxel size");
212  check_if_equal(im_1.get_length(), im_2.get_length(), "test on read and written file via image length");
213  check_if_equal(im_1.get_lengths(), im_2.get_lengths(), "test on read and written file via image lengths");
214  check_if_equal(im_1.get_max_index(), im_2.get_max_index(), "test on read and written file via image max index");
215  check_if_equal(im_1.get_max_indices(), im_2.get_max_indices(), "test on read and written file via image max indices");
216  check_if_equal(im_1.get_max_x(), im_2.get_max_x(), "test on read and written file via image max x");
217  check_if_equal(im_1.get_max_y(), im_2.get_max_y(), "test on read and written file via image max y");
218  check_if_equal(im_1.get_max_z(), im_2.get_max_z(), "test on read and written file via image max z");
219  check_if_equal(im_1.get_min_index(), im_2.get_min_index(), "test on read and written file via image min index");
220  check_if_equal(im_1.get_min_indices(), im_2.get_min_indices(), "test on read and written file via image min indices");
221  check_if_equal(im_1.get_min_x(), im_2.get_min_x(), "test on read and written file via image min x");
222  check_if_equal(im_1.get_min_y(), im_2.get_min_y(), "test on read and written file via image min y");
223  check_if_equal(im_1.get_min_z(), im_2.get_min_z(), "test on read and written file via image min z");
224  check_if_equal(im_1.get_x_size(), im_2.get_x_size(), "test on read and written file via image x size");
225  check_if_equal(im_1.get_y_size(), im_2.get_y_size(), "test on read and written file via image y size");
226  check_if_equal(im_1.get_z_size(), im_2.get_z_size(), "test on read and written file via image z size");
227  check_if_equal(im_1.find_max(), im_2.find_max(), "test on read and written file via image max");
228  check_if_equal(im_1.find_min(), im_2.find_min(), "test on read and written file via image min");
229 
230  check_if_equal(im_1, im_2, "test on read and written file");
231 
232  set_tolerance(.00001);
233 
234  check_if_equal(im_1.get_origin(), im_2.get_origin(), "test on read and written file via image origin");
235 }
236 
237 template <class A>
238 void
239 IOTests<A>::check_exam_info(const ExamInfo& exm_inf_1, const ExamInfo& exm_inf_2)
240 {
241  // Start time isn't currently written or read, so can't check it...
242  // check_if_equal(exm_inf_1.get_high_energy_thres(), exm_inf_2.get_high_energy_thres(), "test on read and written file via
243  // ExamInfo::get_high_energy_thresh"); check_if_equal(exm_inf_1.get_low_energy_thres(), exm_inf_2.get_low_energy_thres(), "test
244  // on read and written file via ExamInfo::get_low_energy_thres"); check_if_equal(exm_inf_1.start_time_in_secs_since_1970,
245  // exm_inf_2.start_time_in_secs_since_1970, "test on read and written file via ExamInfo::start_time_in_secs_since_1970");
246 
247  // Check time frames
248  const TimeFrameDefinitions& im_1_time_frames = exm_inf_1.get_time_frame_definitions();
249  const TimeFrameDefinitions& im_2_time_frames = exm_inf_2.get_time_frame_definitions();
250  if (!check_if_equal(im_1_time_frames.get_num_time_frames(),
251  im_2_time_frames.get_num_time_frames(),
252  "test on read and written file via TimeFrameDefinitions::get_num_time_frames"))
253  return;
254 
255  // Loop over each one and compare them
256  for (unsigned i = 1; i <= im_1_time_frames.get_num_frames(); i++)
257  {
258  check_if_equal(im_1_time_frames.get_end_time(i),
259  im_2_time_frames.get_end_time(i),
260  "test on read and written file via TimeFrameDefinitions::get_end_time");
261  check_if_equal(im_1_time_frames.get_start_time(i),
262  im_2_time_frames.get_start_time(i),
263  "test on read and written file via TimeFrameDefinitions::get_start_time");
264  }
265 }
266 
267 template <class A>
268 void
270 {
271  try
272  {
273  this->set_up();
274  if (!everything_ok)
275  return;
276 
277  this->create_single_image();
278  if (!everything_ok)
279  return;
280 
281  this->create_image();
282  if (!everything_ok)
283  return;
284 
285  std::cerr << "\nAbout to write the image to disk...\n";
286  this->write_image();
287  if (!everything_ok)
288  return;
289  std::cerr << "OK!\n";
290 
291  std::cerr << "\nAbout to read the image back from disk...\n";
292  this->read_image();
293  if (!everything_ok)
294  return;
295  std::cerr << "OK!\n";
296 
297  std::cerr << "\nAbout to check the consistency between the two images...\n";
298  this->check_result();
299  if (!everything_ok)
300  return;
301  std::cerr << "OK!\n";
302  }
303  catch (...)
304  {
305  everything_ok = false;
306  }
307 }
308 
309 END_NAMESPACE_STIR
int get_length() const
return number of elements in this vector
Definition: VectorWithOffset.inl:534
This class is used to represent voxelised densities on a cuboid grid (3D).
Definition: FBP3DRPReconstruction.h:43
Class used for storing time frame durations.
Definition: TimeFrameDefinitions.h:38
unsigned int get_num_time_frames() const
Get number of frames.
Definition: TimeFrameDefinitions.cxx:92
Declaration of class stir::Succeeded.
#define _PI
The constant pi to high precision.
Definition: common.h:134
A class to parse Interfile headers.
Definition: KeyParser.h:161
elemT find_max() const
return maximum of all the elements
Definition: Array.inl:364
int get_min_index() const
get value of first valid index
Definition: VectorWithOffset.inl:116
CartesianCoordinate3D< float > get_voxel_size() const
is the same as get_grid_spacing(), but now returns CartesianCoordinate3D for convenience ...
Definition: VoxelsOnCartesianGrid.inl:27
Declaration of class stir::OutputFileFormat.
int get_x_size() const
Definition: VoxelsOnCartesianGrid.inl:55
Definition of stir::is_null_ptr functions.
A simple class to test the OutputFileFormat function.
Definition: test_IO.h:69
A base class for making test classesWith a derived class, an application could look like...
Definition: RunTests.h:71
Declaration of class stir::ecat::ecat7::ECAT6OutputFileFormat.
elemT find_min() const
return minimum of all the elements
Definition: Array.inl:390
a class for storing information about 1 exam (or scan)
Definition: ExamInfo.h:41
int get_max_index() const
get value of last valid index
Definition: VectorWithOffset.inl:123
const CartesianCoordinate3D< float > & get_origin() const
Return the origin.
Definition: DiscretisedDensity.inl:64
defines the stir::VoxelsOnCartesianGrid class
unsigned int get_num_frames() const
Get number of frames.
Definition: TimeFrameDefinitions.cxx:86
a class containing an enumeration type that can be used by functions to signal successful operation o...
Definition: Succeeded.h:43
Declaration of stir::read_from_file functions (providing easy access to class stir::InputFileFormatRe...
defines the stir::RunTests class