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