CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
check_benchmark_pet_dynamic.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <fstream>
3 #include <cstdlib>
4 #include <cstdio>
5 #include <string>
6 #include <cmath>
7 #ifdef _WIN32
8 #include <windows.h>
9 #endif
10 
11 using namespace std;
12 
13 void showHelp(int code)
14 {
15  cout << endl;
16  cout << "Usage: check_benchmark tested_image.hdr" << endl;
17  cout << endl;
18  exit(code);
19 }
20 
21 int main(int argc, char** argv)
22 {
23  // ==========================================================================
24  // Parameters
25  // ==========================================================================
26 
27  if (argc!=3) showHelp(0);
28  string hdr_new = (string)argv[1];
29  string nb_dyn_imgs_str = (string)argv[2];
30 
31  // ==========================================================================
32  // Open header and read useful information
33  // ==========================================================================
34 
35  // Open file
36  ifstream fhdr(hdr_new.c_str());
37  if (!fhdr)
38  {
39  cerr << "***** Input header file '" << hdr_new << "' is missing or corrupted !" << endl;
40  exit(1);
41  }
42 
43  // Info to find
44  string img_new = "";
45  string castor_version = "";
46 
47  // Read line after line
48  char line[1024];
49  fhdr.getline(line,1024);
50  while (!fhdr.eof())
51  {
52  size_t found;
53  // Transform it to string to benefit from useful c++ functions
54  string test = (string)line;
55  // Data file name
56  found = test.find("name of data file");
57  if (found!=string::npos)
58  {
59  // Get the file name
60  found = test.find("=");
61  img_new = test.substr(found+1);
62  // Remove blancks and cariage return
63  while ( (found=img_new.find(" ")) != string::npos) img_new.replace(found,1,"");
64  while ( (found=img_new.find("\r")) != string::npos) img_new.replace(found,1,"");
65  }
66  // CASToR version
67  found = test.find("CASToR version");
68  if (found!=string::npos)
69  {
70  // Get the CASToR version
71  found = test.find("=");
72  castor_version = test.substr(found+1);
73  // Remove blanks and cariage return
74  while ( (found=castor_version.find(" ")) != string::npos) castor_version.replace(found,1,"");
75  while ( (found=castor_version.find("\r")) != string::npos) castor_version.replace(found,1,"");
76  }
77  // Read a new line
78  fhdr.getline(line,1024);
79  }
80 
81  // Close file
82  fhdr.close();
83 
84  // Check data file name
85  if (img_new=="")
86  {
87  cerr << "***** Did not find the data file name in the provided header file !" << endl;
88  exit(1);
89  }
90  // Check CASToR version
91  if (castor_version=="")
92  {
93  cout << " --> Did not find the CASToR version in the provided header file. Assume it to be 1.0." << endl;
94  castor_version = "1.0";
95  }
96  else
97  {
98  cout << " --> Found CASToR version: " << castor_version << endl;
99  }
100  // ---------------
101  // Truncate any third decimal on the CASToR version, e.g. 2.0.1 becomes 2.0, because we do not expect to be
102  // changes in the results between such versions.
103 
104  // Truncated CASToR version
105  string castor_version_trunc = castor_version;
106  // First the position of the first '.'
107  size_t first_point = castor_version_trunc.find_first_of(".");
108  // Then, while we find a last '.' which is not the same as the first, we truncate the version name
109  size_t last_point = string::npos;
110  while ( (last_point=castor_version_trunc.find_last_of(".")) != first_point )
111  {
112  castor_version_trunc = castor_version_trunc.substr(0,last_point);
113  }
114  // Test if the version is different
115  if (castor_version_trunc!=castor_version)
116  {
117  cout << " --> Assume same results as CASToR version " << castor_version_trunc << endl;
118  castor_version = castor_version_trunc;
119  }
120 
121  // ---------------
122  // Build reference image file name (we replace the substring "challenger" by "reference")
123 
124  // First find the position of the key word "challenger"
125  size_t pos_challenger = img_new.find("challenger");
126  if (pos_challenger==string::npos)
127  {
128  cerr << "***** The name of the image file being tested is supposed to contain the key work \"challenger\" in its name !" << endl;
129  exit(1);
130  }
131  // Copy the file name
132  string img_ref = img_new;
133  // Set the sub-string that will replace the word "challenger"
134  string reference = "reference_v" + castor_version;
135  // Then replace "challenger" by the correct reference image and we're done
136  img_ref.replace(pos_challenger,10,reference);
137 
138  // ==========================================================================
139  // Allocate, open and read images
140  // ==========================================================================
141 
142  // Dimensions
143  int nb_dyn_imgs = atoi(nb_dyn_imgs_str.c_str());
144 
145  int dim_x = 256;
146  int dim_y = 256;
147  int dim_z = nb_dyn_imgs;
148  int dim_xy = dim_x * dim_y;
149  int dim_xyz = dim_x * dim_y * dim_z;
150 
151  // Allocations
152  float* image_ref = (float*)malloc(dim_xyz*sizeof(float));
153  float* image_new = (float*)malloc(dim_xyz*sizeof(float));
154 
155  // Open and read reference image
156  FILE* f_ref = fopen(img_ref.c_str(),"rb");
157  if (f_ref==NULL)
158  {
159  cerr << "***** Input reference image file '" << img_ref << "' is missing or corrupted !" << endl;
160  exit(1);
161  }
162  int nb_data_ref = fread(image_ref,sizeof(float),dim_xyz,f_ref);
163  fclose(f_ref);
164  if (nb_data_ref!=dim_xyz)
165  {
166  cerr << "***** Failed to read all data from reference image file '" << img_ref << "' !" << endl;
167  exit(1);
168  }
169 
170  // Open and read test image
171  FILE* f_new = fopen(img_new.c_str(),"rb");
172  if (f_new==NULL)
173  {
174  cerr << "***** Input tested image file '" << img_new << "' is missing or corrupted !" << endl;
175  exit(1);
176  }
177  int nb_data_new = fread(image_new,sizeof(float),dim_xyz,f_new);
178  fclose(f_new);
179  if (nb_data_new!=dim_xyz)
180  {
181  cerr << "***** Failed to read all data from tested image file '" << img_new << "' !" << endl;
182  exit(1);
183  }
184 
185  // ==========================================================================
186  // Compute the difference image
187  // ==========================================================================
188 
189  // Allocation
190  double* image_diff = (double*)malloc(dim_xyz*sizeof(double));
191 
192  // Compute the difference
193  for (int v=0; v<dim_xyz; v++)
194  {
195  image_diff[v] = ((double)image_new[v])-((double)image_ref[v]);
196  }
197 
198  // Number of problems found
199  int problems = 0;
200 
201  // ==========================================================================
202  // Test 1: check that the mean relative difference is below a threshold, for
203  // the entire image, but also slice by slice.
204  // ==========================================================================
205 
206  // Compute the mean difference per slice, as well as the mean of the reference
207  double* mean_difference_per_slice = (double*)calloc(dim_z,sizeof(double));
208  double* mean_reference_per_slice = (double*)calloc(dim_z,sizeof(double));
209  for (int z=0; z<dim_z; z++)
210  {
211  for (int xy=0; xy<dim_xy; xy++)
212  {
213  int v = z * dim_xy + xy;
214  mean_difference_per_slice[z] += image_diff[v];
215  mean_reference_per_slice[z] += ((double)image_ref[v]);
216  }
217  mean_difference_per_slice[z] /= ((double)dim_xy);
218  mean_reference_per_slice[z] /= ((double)dim_xy);
219  }
220 
221  // Compute the global mean difference and reference
222  double global_mean_difference = 0.;
223  double global_mean_reference = 0.;
224  for (int z=0; z<dim_z; z++)
225  {
226  global_mean_difference += mean_difference_per_slice[z];
227  global_mean_reference += mean_reference_per_slice[z];
228  }
229  global_mean_difference /= ((double)dim_z);
230  global_mean_reference /= ((double)dim_z);
231 
232  // Compute the global mean relative difference
233  float global_mean_relative_difference = global_mean_difference / global_mean_reference;
234 
235  // Test the value with a 5 per 100 000 threshold
236  float global_mean_relative_difference_threshold = 5.e-5;
237  if (fabs(global_mean_relative_difference) < global_mean_relative_difference_threshold)
238  {
239  cout << " --> Mean relative difference test over the whole image passed (value: " << global_mean_relative_difference << ")." << endl;
240  }
241  // Test not passed !
242  else
243  {
244  cout << " --> !!!!! The mean relative difference over the whole image is " << global_mean_relative_difference << " !" << endl;
245  cout << " It is supposed to be between -" << global_mean_relative_difference_threshold << " and "
246  << global_mean_relative_difference_threshold << " !" << endl;
247  problems++;
248  }
249 
250  // Test the value of each slice with a 5 per 10 000 threshold
251  float slice_relative_difference_threshold = 5.e-4;
252  float max_mean_relative_difference_over_slices = 0.;
253  int slice_not_passed = 0;
254  for (int z=0; z<dim_z; z++)
255  {
256  float value = fabs(mean_difference_per_slice[z] / mean_reference_per_slice[z]);
257  if (value > max_mean_relative_difference_over_slices) max_mean_relative_difference_over_slices = value;
258  if (value >= slice_relative_difference_threshold) slice_not_passed++;
259  }
260  if (slice_not_passed==0)
261  {
262  cout << " --> Mean relative difference test for all slices passed (maximum absolute value: " << max_mean_relative_difference_over_slices << ")." << endl;
263  }
264  // Test not passed
265  else
266  {
267  cout << " --> !!!!! The mean relative difference for each slice has a maximum absolute value of " << max_mean_relative_difference_over_slices << " !" << endl;
268  cout << " It is supposed to be between -" << slice_relative_difference_threshold << " and " << slice_relative_difference_threshold << " !" << endl;
269  cout << " The test failed for " << slice_not_passed << " slices !" << endl;
270  problems++;
271  }
272 
273  // ==========================================================================
274  // Test 2: check that the absolute relative difference is below a threshold
275  // for any voxels away from the border.
276  // ==========================================================================
277 
278  // Allow some margin around the borders
279  int voxel_margin = 5;
280 
281  // Compute the maximum absolute relative difference
282  float max_abs_relative_difference = 0.;
283  for (int z=0; z<dim_z; z++)
284  {
285  // Skip to next voxel if too close from the border
286  if (z<voxel_margin || z>dim_z-voxel_margin-1) continue;
287  for (int y=0; y<dim_y; y++)
288  {
289  // Skip to next voxel if too close from the border
290  if (y<voxel_margin || y>dim_y-voxel_margin-1) continue;
291  for (int x=0; x<dim_x; x++)
292  {
293  // Compute 1D cumulative voxel index
294  int v = z * dim_y * dim_x + y * dim_x + x;
295  // Skip to next voxel if too close from the border
296  if (x<voxel_margin || x>dim_x-voxel_margin-1) continue;
297  float abs_relative_difference = 0.;
298  if (image_ref[v]!=0.) abs_relative_difference = fabs(image_diff[v]/image_ref[v]);
299  if (abs_relative_difference > max_abs_relative_difference) max_abs_relative_difference = abs_relative_difference;
300  }
301  }
302  }
303 
304  // The the value with a 1 per 1 000 threshold
305  float max_abs_relative_difference_threshold = 1.e-3;
306  if (max_abs_relative_difference < max_abs_relative_difference_threshold)
307  {
308  cout << " --> Maximum absolute relative difference test passed (value: " << max_abs_relative_difference << ")." << endl;
309  }
310  // Test not passed !
311  else
312  {
313  cout << " --> !!!!! The maximum absolute relative difference is " << max_abs_relative_difference << " !" << endl;
314  cout << " It is supposed to be below " << max_abs_relative_difference_threshold << " !" << endl;
315  problems++;
316  }
317 
318  // ==========================================================================
319  // Summary
320  // ==========================================================================
321 
322  // Benchmark passed
323  if (problems==0)
324  {
325  cout << " --> Benchmark successfully passed." << endl;
326  }
327  // Benchmark not passed !
328  else
329  {
330  cout << endl;
331  cout << " --> !!!!! Benchmark tests failed (" << problems << " problems found) !" << endl;
332  cout << " Double check all what you have done first. Then email the mailing list." << endl;
333  }
334 
335  // End
336  return 0;
337 }
338 
339 
int main(int argc, char **argv)
void showHelp(int code)