STIR 6.4.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"
42#ifdef HAVE_LLN_MATRIX
43# include "stir/IO/ECAT6OutputFileFormat.h" // need this for test on pixel_size
44#endif
45#include <fstream>
46
47START_NAMESPACE_STIR
48
67
68template <class A>
69class IOTests : public RunTests
70{
71public:
72 IOTests(std::istream& in);
73
74 void run_tests() override;
75
76protected:
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
94template <class A>
95IOTests<A>::IOTests(std::istream& in)
96 : _in(in)
97{}
98
99template <class A>
100void
101IOTests<A>::set_up()
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
120template <class A>
121shared_ptr<VoxelsOnCartesianGrid<float>>
122IOTests<A>::create_single_image()
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
179template <class A>
180void
181IOTests<A>::write_image()
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
189template <class A>
190void
191IOTests<A>::read_image()
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
199template <class A>
200void
201IOTests<A>::compare_images(const VoxelsOnCartesianGrid<float>& im_1, const VoxelsOnCartesianGrid<float>& im_2)
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
237template <class A>
238void
239IOTests<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
267template <class A>
268void
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
309END_NAMESPACE_STIR
Declaration of class stir::ecat::ecat7::ECAT6OutputFileFormat.
Declaration of class stir::OutputFileFormat.
defines the stir::RunTests class
Declaration of class stir::Succeeded.
defines the stir::VoxelsOnCartesianGrid class
a templated class for 3-dimensional coordinates.
Definition CartesianCoordinate3D.h:53
a class for storing information about 1 exam (or scan)
Definition ExamInfo.h:42
void run_tests() override
Function (to be overloaded) which does the actual tests.
Definition test_IO.h:269
This class defines ranges which can be 'irregular'.
Definition IndexRange.h:69
A class to parse Interfile headers.
Definition KeyParser.h:162
bool everything_ok
variable storing current status
Definition RunTests.h:270
RunTests(const double tolerance=1E-4)
Default constructor.
Definition RunTests.h:305
a class containing an enumeration type that can be used by functions to signal successful operation o...
Definition Succeeded.h:44
Class used for storing time frame durations.
Definition TimeFrameDefinitions.h:39
This class is used to represent voxelised densities on a cuboid grid (3D).
Definition VoxelsOnCartesianGrid.h:46
Implementation of OutputFileFormat paradigm for the ECAT6 format.
Definition ECAT6OutputFileFormat.h:51
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
#define _PI
The constant pi to high precision.
Definition common.h:141
Definition of stir::is_null_ptr functions.
Declaration of stir::read_from_file functions (providing easy access to class stir::InputFileFormatRe...