CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
code/src/projector/vProjector.cc
Go to the documentation of this file.
1 
8 #include "vProjector.hh"
9 #include "vScanner.hh"
10 #include "vDataFile.hh"
11 
12 // =====================================================================
13 // ---------------------------------------------------------------------
14 // ---------------------------------------------------------------------
15 // =====================================================================
16 
18 {
19  // Affect default values
20  mp_Scanner = NULL;
22  mp_sizeVox[0] = -1.;
23  mp_sizeVox[1] = -1.;
24  mp_sizeVox[2] = -1.;
25  mp_nbVox[0] = -1;
26  mp_nbVox[1] = -1;
27  mp_nbVox[2] = -1;
28  m_nbVoxXY = -1;
29  mp_halfFOV[0] = -1.;
30  mp_halfFOV[1] = -1.;
31  mp_halfFOV[2] = -1.;
32  m_sensitivityMode = false;
33  m_TOFMethod = -1;
34  m_TOFNbSigmas = -1.;
37  m_applyPOI = false;
40  m_verbose = 0;
41  m_checked = false;
42  m_initialized = false;
43  mp_mask = NULL;
44  m_hasMask = false;
45  m2p_TOFWeightingFcn = NULL;
48  mp_TOFResolutionInMm = NULL;
49  mp_TOFProbabilities = NULL;
50  mp_TOFOffsetInMm = NULL;
51  m_TOFBinSizeInMm = -1.;
55 }
56 
57 // =====================================================================
58 // ---------------------------------------------------------------------
59 // ---------------------------------------------------------------------
60 // =====================================================================
61 
63 {
64  if ( m2p_TOFWeightingFcn )
65  {
66  for(int r=0 ; r<m_nbTOFResolutions ; r++)
67  if(m2p_TOFWeightingFcn[ r ]) delete[] m2p_TOFWeightingFcn[ r ];
68 
69  delete[] m2p_TOFWeightingFcn;
70  }
71 
74  if( mp_TOFOffsetInMm ) delete[] mp_TOFOffsetInMm;
75 }
76 
77 // =====================================================================
78 // ---------------------------------------------------------------------
79 // ---------------------------------------------------------------------
80 // =====================================================================
81 
83 {
84  // Check that the parameter is not NULL
85  if (ap_ImageDimensionsAndQuantification==NULL)
86  {
87  Cerr("***** vProjector::SetImageDimensionsAndQuantification() -> Input image dimensions object is null !" << endl);
88  return 1;
89  }
90  // Affect image dimensions
91  mp_sizeVox[0] = ap_ImageDimensionsAndQuantification->GetVoxSizeX();
92  mp_sizeVox[1] = ap_ImageDimensionsAndQuantification->GetVoxSizeY();
93  mp_sizeVox[2] = ap_ImageDimensionsAndQuantification->GetVoxSizeZ();
94  mp_nbVox[0] = ap_ImageDimensionsAndQuantification->GetNbVoxX();
95  mp_nbVox[1] = ap_ImageDimensionsAndQuantification->GetNbVoxY();
96  mp_nbVox[2] = ap_ImageDimensionsAndQuantification->GetNbVoxZ();
97  m_nbVoxXY = mp_nbVox[0] * mp_nbVox[1];
98  mp_halfFOV[0] = mp_sizeVox[0] * ((FLTNB)mp_nbVox[0]) / 2.;
99  mp_halfFOV[1] = mp_sizeVox[1] * ((FLTNB)mp_nbVox[1]) / 2.;
100  mp_halfFOV[2] = mp_sizeVox[2] * ((FLTNB)mp_nbVox[2]) / 2.;
101  mp_ImageDimensionsAndQuantification = ap_ImageDimensionsAndQuantification;
102  // Normal end
103  return 0;
104 }
105 
106 // =====================================================================
107 // ---------------------------------------------------------------------
108 // ---------------------------------------------------------------------
109 // =====================================================================
110 
112 {
113  // Return when using MPI and mpi_rank is not 0
114  #ifdef CASTOR_MPI
115  int mpi_rank = 0;
116  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
117  if (mpi_rank!=0) return;
118  #endif
119  // Show help
120  cout << "------------------------------------------------------------------" << endl;
121  cout << "----- Common options for all projectors" << endl;
122  cout << "------------------------------------------------------------------" << endl;
123  cout << "Only options related to TOF implementation are available." << endl;
124  cout << "If used, values for all of the following options must be provided as a list of numbers separated by commas." << endl;
125  cout << "" << endl;
126  cout << " the number of standard deviations for truncating the nominal TOF Gaussian distribution (-1 for no truncation)." << endl;
127  cout << " whether the TOF weighting function is precomputed (1 for yes, 0 for no)" << endl;
128  cout << " whether the TOF weighting function takes properly into account the TOF bin using convolution or integration (1 for yes, 0 for no)." << endl;
129  cout << "" << endl;
130  cout << "The default values are -1,1,1" << endl;
131 
132 }
133 
134 // =====================================================================
135 // ---------------------------------------------------------------------
136 // ---------------------------------------------------------------------
137 // =====================================================================
138 
140 {
141  // Call the specific help function from the children
143  // Then, say if the child projector in use is compatible with SPECT attenuation correction or not
144  if (m_compatibleWithSPECTAttenuationCorrection) cout << "This projector is compatible with SPECT attenuation correction." << endl;
145  else cout << "This projector is NOT compatible with SPECT attenuation correction." << endl;
146 }
147 
148 // =====================================================================
149 // ---------------------------------------------------------------------
150 // ---------------------------------------------------------------------
151 // =====================================================================
152 
153 int vProjector::ReadCommonOptionsList(const string& a_optionsList)
154 {
155  // TODO : make this more explicit, here it is assumed that 3 specific TOF options are provided
156  if (a_optionsList!="")
157  {
158  FLTNB option[3];
159  // Read the options
160  if (ReadStringOption(a_optionsList, option, 3, ",", "Common options"))
161  {
162  Cerr("***** vProjector::ReadCommonOptionsList() -> Failed to correctly read the list of options !" << endl);
163  return 1;
164  }
165  m_TOFNbSigmas = option[0];
166  m_TOFWeightingFcnPrecomputedFlag = option[1]>0.;
167  m_TOFBinProperProcessingFlag = option[2]>0.;
168  }
169  return 0;
170 }
171 
172 // =====================================================================
173 // ---------------------------------------------------------------------
174 // ---------------------------------------------------------------------
175 // =====================================================================
176 
178 {
179  // Check scanner
180  if (mp_Scanner==NULL)
181  {
182  Cerr("***** vProjector::CheckParameters() -> Please provide a valid scanner object !" << endl);
183  return 1;
184  }
185  // Check image dimensions
187  {
188  Cerr("***** vProjector::CheckParameters() -> Please provide a valid image dimensions and quantification object !" << endl);
189  return 1;
190  }
191  if (mp_sizeVox[0]<=0. || mp_sizeVox[1]<=0. || mp_sizeVox[2]<=0.)
192  {
193  Cerr("***** vProjector::CheckParameters() -> One or more voxel sizes is negative or null !" << endl);
194  return 1;
195  }
196  if (mp_nbVox[0]<=0 || mp_nbVox[1]<=0 || mp_nbVox[2]<=0)
197  {
198  Cerr("***** vProjector::CheckParameters() -> One or more number of voxels is negative or null !" << endl);
199  return 1;
200  }
201  // Check TOF
203  {
204  Cerr("***** vProjector::CheckParameters() -> TOF flag is incorrect or not set !" << endl);
205  return 1;
206  }
207  // Check TOF parameters
208  if (m_TOFMethod!=USE_NOTOF)
209  {
211  {
212  Cerr("***** vProjector::CheckParameters() -> Inconsistent TOF related parameters !" << endl);
213  return 1;
214  }
216  {
217  Cout("***** vProjector::CheckParameters() -> Warning: quantization TOF bin size wrong or not provided, so switching to TOF list-mode reconstruction which neglects the quantization TOF bin size!" << endl);
219  }
220  // Per-event TOF is not compatible with precomputed flag, as the kernel has to be computed on the fly
222  {
223  Cerr("***** vProjector::Initialize() -> Per-event TOF resolution can not be used with histogram TOF !" << endl);
224  return 1;
225  }
226  // Per-event TOF is not compatible with precomputed flag, as the kernel has to be computed on the fly
228  {
229  Cerr("***** vProjector::Initialize() -> Per-event TOF resolution can not be used with precomputed TOF weighing estimation !" << endl);
230  return 1;
231  }
232  }
233  // Check verbose level
234  if (m_verbose<0)
235  {
236  Cerr("***** vProjector::CheckParameters() -> Verbose level is negative !" << endl);
237  return 1;
238  }
239  // Check parameters of the child class
241  {
242  Cerr("***** vProjector::CheckParameters() -> An error occurred while checking parameters of the child projector class !" << endl);
243  return 1;
244  }
245 
246  // Normal end
247  m_checked = true;
248  return 0;
249 }
250 
251 // =====================================================================
252 // ---------------------------------------------------------------------
253 // ---------------------------------------------------------------------
254 // =====================================================================
255 
257 {
258  // First check that the parameters have been checked !
259  if (!m_checked)
260  {
261  Cerr("***** vProjector::Initialize() -> Must call the CheckParameters() function before initialization !" << endl);
262  return 1;
263  }
264 
265  // TOF parameters
266  if (m_TOFMethod!=USE_NOTOF)
267  {
268  // Gaussian standard deviation
269  HPFLTNB* tof_resolution_sigma = new HPFLTNB[ m_nbTOFResolutions ];
271  FLTNB smallest_tof_resolution_sigma = 1000000.;
272  for(int r=0 ; r<m_nbTOFResolutions ; r++)
273  {
275  mp_TOFResolutionInMm[ r ] :
277 
278  tof_resolution_sigma[ r ] = mp_TOFResolutionInMm[ r ] / TWO_SQRT_TWO_LN_2;
279  smallest_tof_resolution_sigma = tof_resolution_sigma[ r ] > smallest_tof_resolution_sigma ?
280  smallest_tof_resolution_sigma :
281  tof_resolution_sigma[ r ];
282  // Ideal Gaussian normalization coefficient (integral=1)
283  mp_TOFGaussianNormCoef[ r ] = INV_SQRT_2_PI / tof_resolution_sigma[ r ];
284  }
285  // If the provided number of sigmas is negative, set it to a value large enough
286  // to approximate no truncation of the Gaussian distribution
287  // (the TOF weighting function is in any case limited by the available TOF measurement range)
288 
289  if (m_TOFNbSigmas<0.) m_TOFNbSigmas = m_TOFMeasurementRangeInMm / smallest_tof_resolution_sigma;
290 
291  // Precompute the TOF weighting function if required
292  // TODO TM Integrate multi-kernel TOF in precomputed option
294  {
296  Cout(" TOF weighting function precomputation... " << endl);
297 
298  ChronoTime start_tof_weights_precmp = std::chrono::system_clock::now();
299 
300  // Initialize some variables to default values, TODO make this an optional parameter
301  // Sample the TOF weighting function at 1/m_TOFPrecomputedSamplingFactor of the spatial unit (mm)
303 
304  HPFLTNB largest_tof_half_span = -1.;
305 
306  for(int r=0 ; r<m_nbTOFResolutions ; r++)
307  cout << tof_resolution_sigma[ r ] << " : " << mp_TOFProbabilities[ r ] << endl;
308 
309 
310  for(int r=0 ; r<m_nbTOFResolutions ; r++)
311  largest_tof_half_span = largest_tof_half_span > (tof_resolution_sigma[ r ] * m_TOFNbSigmas) ?
312  largest_tof_half_span :
313  tof_resolution_sigma[ r ] * m_TOFNbSigmas ;
314 
315  // number of samples for the Gaussian function truncated at m_TOFNbSigmas standard deviations
316  INTNB nb_samples_tof_gauss = (INTNB)ceil(largest_tof_half_span*2.*m_TOFPrecomputedSamplingFactor);
317 
318  // make the number of samples odd
319  if (nb_samples_tof_gauss % 2 == 0) nb_samples_tof_gauss += 1;
320 
321  //HPFLTNB sum_tof_gaussian_norm_coef = 0.;
322 
323  //for(int r=0 ; r<m_nbTOFResolutions ; r++)
324  //sum_tof_gaussian_norm_coef += mp_TOFProbabilities[ r ]/mp_TOFGaussianNormCoef[ r ];
325 
327 
328  // normalized Gaussian function for list-mode data (assumption of continuous TOF measurements)
329  // normalized Gaussian function for TOF histogram data multiplied by the size of the TOF bin (assumption of constant Gaussian function over a TOF bin)
331  {
332 
333 
334  for(int r=0 ; r<m_nbTOFResolutions ; r++)
335  {
337  Cout(" -> Process TOF resolution: " << r+1 << "/" << m_nbTOFResolutions << endl);
338 
339  m2p_TOFWeightingFcn[ r ] = new HPFLTNB[nb_samples_tof_gauss];
340 
341  // Gaussian mean at the center
342  INTNB mu = nb_samples_tof_gauss/2;
343 
344  INTNB g;
345  #pragma omp parallel for private(g) schedule(guided)
346  for (g=0;g<nb_samples_tof_gauss;g++)
347  {
348  m2p_TOFWeightingFcn[ r ][g] = 0.; // kept in order to init m2p_TOFWeightingFcn[ 0 ][g]
349  FLTNB tof_weight = 0.;
350 
351  HPFLTNB temp = ((HPFLTNB)(g-mu))/(tof_resolution_sigma[ r ]*m_TOFPrecomputedSamplingFactor);
352 
353  //m2p_TOFWeightingFcn[ r ][g] += mp_TOFProbabilities[ r ] * exp(-0.5*(temp*temp));
354  tof_weight = mp_TOFProbabilities[ r ] * exp(-0.5*(temp*temp));
355 
357  //m2p_TOFWeightingFcn[ r ][g] *= mp_TOFGaussianNormCoef[ r ];
358  tof_weight *= mp_TOFGaussianNormCoef[ r ];
359 
360  m2p_TOFWeightingFcn[ 0 ][g] += tof_weight;
361 
363  }
364  }
365  m_TOFWeightingFcnNbSamples = nb_samples_tof_gauss;
366  }
367  // convolution of the normalized Gaussian with the TOF bin (cumulative or quantization bin)
368  else
369  {
370  Cerr("***** vProjector::Initialize: Implementation of proper bin processins incomplete (need to deal with multi-tof resolution)" << endl);
371  return 1;
372 
373  // number of samples for the TOF bin door function
374  INTNB nb_samples_tof_bin = (INTNB)round(m_TOFBinSizeInMm*m_TOFPrecomputedSamplingFactor);
375  // make the number of samples odd
376  if (nb_samples_tof_bin % 2 == 0) nb_samples_tof_bin += 1;
377 
378  // number of samples for the convolution
379  INTNB nb_samples_conv = nb_samples_tof_gauss+nb_samples_tof_bin-1;
380 
381  for(int r=0 ; r<m_nbTOFResolutions ; r++)
382  {
384  Cout(" -> Process TOF resolution: " << r+1 << "/" << m_nbTOFResolutions << endl);
385 
386  // normalized Gaussian function truncated at m_TOFNbSigmas standard deviations
387  // padded with zeros to the size of the convolved function
388  HPFLTNB* tof_gauss = new HPFLTNB[nb_samples_conv];
389  INTNB mu = nb_samples_conv/2;
390 
391  INTNB sgauss;
392  #pragma omp parallel for private(sgauss) schedule(guided)
393  for (sgauss=0;sgauss<nb_samples_conv;sgauss++)
394  {
395  if (sgauss<mu-nb_samples_tof_gauss/2 || sgauss>mu+nb_samples_tof_gauss/2) tof_gauss[sgauss]=0.;
396  else
397  {
398  HPFLTNB temp = (HPFLTNB)((sgauss-mu))/(tof_resolution_sigma[ r ]*m_TOFPrecomputedSamplingFactor);
399  tof_gauss[sgauss] = mp_TOFProbabilities[ r ] * exp(-0.5*(temp*temp));
400  //tof_gauss[sgauss] /= sum_tof_gaussian_norm_coef;
401  tof_gauss[sgauss] *= mp_TOFGaussianNormCoef[ r ];
402  }
403  }
404 
405  // TOF bin door function (quantization bin for list-mode, cumulative bin for histogram data)
406  HPFLTNB* tof_bin = new HPFLTNB[nb_samples_tof_bin];
407  // intensity = 1 for the cumulative bin, 1/binSize for the quantization bin
408  HPFLTNB tof_bin_value = (m_TOFMethod==USE_TOFLIST)?(1./(m_TOFBinSizeInMm*m_TOFPrecomputedSamplingFactor)):(1./m_TOFPrecomputedSamplingFactor);
409  for (INTNB sbin=0;sbin<nb_samples_tof_bin;sbin++) tof_bin[sbin] = tof_bin_value;
410 
411  // the final TOF weighting function
412  m2p_TOFWeightingFcn[ r ] = new HPFLTNB[nb_samples_conv];
413  for (INTNB s=0;s<nb_samples_conv;s++) m2p_TOFWeightingFcn[ r ][s] = 0.;
414 
415  // convolve the TOF bin with the Gaussian function
416  for (INTNB c=0;c<nb_samples_conv;c++)
417  for (INTNB ib=0;ib<nb_samples_tof_bin;ib++)
418  {
419  INTNB temp = c-nb_samples_tof_bin/2+ib;
420  if (temp>=0 && temp<nb_samples_conv) m2p_TOFWeightingFcn[ r ][c] += tof_gauss[temp]*tof_bin[ib];
421  }
422 
423  m_TOFWeightingFcnNbSamples = nb_samples_conv;
424 
425  // clean
426  delete []tof_bin;
427  delete []tof_gauss;
428  tof_bin = NULL;
429  tof_gauss = NULL;
430  }
431 
432  }
433 
434  DurationNano duration_tof_weights_precmp = chrono::duration<int64_t,nano>::zero();
435  duration_tof_weights_precmp += std::chrono::system_clock::now() - start_tof_weights_precmp;
436 
438  Cout(" --> Profiling of the TOF weights precomputation: " << setfill( '0' )
439  << setw( 2 ) << chrono::duration_cast<Hs> ( duration_tof_weights_precmp ).count() << " hours "
440  << setw( 2 ) << chrono::duration_cast<Mins>( duration_tof_weights_precmp % Hs( 1 ) ).count() << " mins "
441  << setw( 2 ) << chrono::duration_cast<Secs>( duration_tof_weights_precmp % Mins( 1 ) ).count() << " secs "
442  << setw( 3 ) << chrono::duration_cast<Ms> ( duration_tof_weights_precmp % Secs( 1 ) ).count() << " ms" << endl);
443  }
444 
445  // Verbose
447  {
448  Cout(" --> TOF weighting function implementation: " << endl);
449  Cout(" --> Gaussian truncation (number of standard deviations) " << m_TOFNbSigmas << endl);
451  {
452  Cout(" --> Precomputed " << endl);
454  {
455  Cout(" --> Convolved with the "<<((m_TOFMethod==USE_TOFHISTO)?"cumulative":"quantization")<<" TOF bin (size " <<m_TOFBinSizeInMm<<"mm)" <<endl);
456  }
457  else
458  {
459  if (m_TOFMethod==USE_TOFHISTO) Cout(" --> Simple multiplication with the cumulative TOF bin (size " <<m_TOFBinSizeInMm<<"mm)" <<endl);
460  else if (m_TOFMethod==USE_TOFLIST) Cout(" --> Simple normalized Gaussian"<<endl);
461  }
462  }
463  else
464  {
465  Cout(" --> Computation on the fly " << endl);
467  {
468  Cout(" --> Integration of the Gaussian over the "<<((m_TOFMethod==USE_TOFHISTO)?"cumulative":"quantization")<<" TOF bin (size " <<m_TOFBinSizeInMm<<"mm)" <<endl);
469  }
470  else
471  {
472  if (m_TOFMethod==USE_TOFHISTO) Cout(" --> Simple multiplication with the cumulative TOF bin (size " <<m_TOFBinSizeInMm<<"mm)" <<endl);
473  else if (m_TOFMethod==USE_TOFLIST) Cout(" --> Simple normalized Gaussian"<<endl);
474  }
475  }
476  }
477 
478  delete[] tof_resolution_sigma;
479  }
480 
481  // Call the intialize function specific to the children
482  if (InitializeSpecific())
483  {
484  Cerr("***** vProjector::Initialize() -> A problem occurred while calling the specific initialization of the child projector !" << endl);
485  return 1;
486  }
487 
488  if (m_verbose>=3)
489  {
490  Cout("vProjector::Initialize() -> Exit function" << endl);
491  }
492 
493  // Normal end
494  m_initialized = true;
495  return 0;
496 }
497 
498 // =====================================================================
499 // ---------------------------------------------------------------------
500 // ---------------------------------------------------------------------
501 // =====================================================================
502 
504 {
506 }
507 
508 // =====================================================================
509 // ---------------------------------------------------------------------
510 // ---------------------------------------------------------------------
511 // =====================================================================
512 
513 int vProjector::Project(int a_direction, oProjectionLine* ap_ProjectionLine, uint32_t* ap_index1, uint32_t* ap_index2, int a_nbIndices)
514 {
515  #ifdef CASTOR_DEBUG
516  if (!m_initialized)
517  {
518  Cerr("***** vProjector::Project() -> Called while not initialized !" << endl);
519  Exit(EXIT_DEBUG);
520  }
521  #endif
522 
524 
525  // ---------------------------------------------------------------------------------------
526  // First: Get cartesian coordinates from the scanner and average positions if compression.
527  // Here, we differentiate the case with no compression (i.e. a_nbIndices==1) from the
528  // compression case, because it will avoid to perform useless computation without
529  // compression. However, it produces some duplication of code parts as a compromise.
530  // ---------------------------------------------------------------------------------------
531 
532  // ______________________________________________________________________________________
533  // Case1: no compression (i.e. a_nbIndices==1)
534  if (a_nbIndices==1)
535  {
536  // Set indices of the line
537  ap_ProjectionLine->SetIndex1(((int)(ap_index1[0])));
538  ap_ProjectionLine->SetIndex2(((int)(ap_index2[0])));
539  // Get positions and orientations from the scanner (mean depth of interaction intrinsicaly taken into account), taking POI into account if any
540  if (mp_Scanner->GetPositionsAndOrientations( ((int)(ap_index1[0])), ((int)(ap_index2[0])),
541  ap_ProjectionLine->GetPosition1(), ap_ProjectionLine->GetPosition2(),
542  ap_ProjectionLine->GetOrientation1(), ap_ProjectionLine->GetOrientation2(),
543  ap_ProjectionLine->GetPOI1(), ap_ProjectionLine->GetPOI2() ))
544  {
545  Cerr("***** vProjector::Project() -> A problem occurred while getting positions and orientations from scanner !" << endl);
546  return 1;
547  }
548  }
549  // ______________________________________________________________________________________
550  // Case2: compression (i.e. a_nbIndices>1)
551  else
552  {
553  // Set default indices of the line to -1 when compression
554  ap_ProjectionLine->SetIndex1(-1);
555  ap_ProjectionLine->SetIndex2(-1);
556  // Buffer pointers for positions and orientations handled by the projection line
557  FLTNB* position1 = ap_ProjectionLine->GetPosition1();
558  FLTNB* position2 = ap_ProjectionLine->GetPosition2();
559  FLTNB* orientation1 = ap_ProjectionLine->GetOrientation1();
560  FLTNB* orientation2 = ap_ProjectionLine->GetOrientation2();
561  FLTNB* buffer_position1 = ap_ProjectionLine->GetBufferPosition1();
562  FLTNB* buffer_position2 = ap_ProjectionLine->GetBufferPosition2();
563  FLTNB* buffer_orientation1 = ap_ProjectionLine->GetBufferOrientation1();
564  FLTNB* buffer_orientation2 = ap_ProjectionLine->GetBufferOrientation2();
565  // Zero the position and orientation
566  for (int i=0; i<3; i++)
567  {
568  position1[i] = 0.;
569  position2[i] = 0.;
570  orientation1[i] = 0.;
571  orientation2[i] = 0.;
572  }
573  // Loop on provided indices
574  for (int l=0; l<a_nbIndices; l++)
575  {
576  // Get positions and orientations from scanner (mean depth of interaction intrinsicaly taken into account), taking POI into account if any
577  if (mp_Scanner->GetPositionsAndOrientations( ((int)(ap_index1[l])), ((int)(ap_index2[l])),
578  buffer_position1, buffer_position2,
579  buffer_orientation1, buffer_orientation2,
580  ap_ProjectionLine->GetPOI1(), ap_ProjectionLine->GetPOI2() ))
581  {
582  Cerr("***** vProjector::Project() -> A problem occurred while getting positions and orientations from scanner !" << endl);
583  return 1;
584  }
585  // Add those contributions to the mean position and orientation
586  for (int i=0; i<3; i++)
587  {
588  position1[i] += buffer_position1[i];
589  position2[i] += buffer_position2[i];
590  orientation1[i] += buffer_orientation1[i];
591  orientation2[i] += buffer_orientation2[i];
592  }
593  }
594  // Average positions and orientations
595  for (int i=0; i<3; i++)
596  {
597  position1[i] /= ((FLTNB)a_nbIndices);
598  position2[i] /= ((FLTNB)a_nbIndices);
599  orientation1[i] /= ((FLTNB)a_nbIndices);
600  orientation2[i] /= ((FLTNB)a_nbIndices);
601  }
602  }
603 
605  {
606  HPFLTNB tof_resolution_sigma = mp_TOFResolutionInMm[ 0 ] / TWO_SQRT_TWO_LN_2;
607  // If the provided number of sigmas is negative, set it to a value large enough
608  // to approximate no truncation of the Gaussian distribution
609  // (the TOF weighting function is in any case limited by the available TOF measurement range)
610  if (m_TOFNbSigmas<0.) m_TOFNbSigmas = m_TOFMeasurementRangeInMm / tof_resolution_sigma;
611  // Ideal Gaussian normalization coefficient (integral=1)
612  mp_TOFGaussianNormCoef[ 0 ] = INV_SQRT_2_PI / tof_resolution_sigma;
613  }
614 
615  // --------------------------------------------------------------
616  // Second: Modify the end points coordinates from common options,
617  // random, offset, and LOR displacements.
618  // -----------------------------------------------------------
619 
620  // Apply common options TODO
621 
622  // Apply LORs displacement TODO
623 
624  // Apply global image offset
625  ap_ProjectionLine->ApplyOffset();
626 
627  // Apply bed position offset
628  ap_ProjectionLine->ApplyBedOffset();
629 
630  // -----------------------------------------------------------
631  // Third: project the line
632  // -----------------------------------------------------------
633 
634  // Compute LOR length
635  ap_ProjectionLine->ComputeLineLength();
636 
637  // Switch on different TOF options
638  switch (m_TOFMethod)
639  {
640  case USE_NOTOF:
641  if (ProjectWithoutTOF( a_direction, ap_ProjectionLine ))
642  {
643  Cerr("***** vProjector::Project() -> A problem occurred while projecting a line without time-of-flight !" << endl);
644  return 1;
645  }
646  break;
647  case USE_TOFLIST:
648  if (ProjectTOFListmode( a_direction, ap_ProjectionLine ))
649  {
650  Cerr("***** vProjector::Project() -> A problem occurred while projecting a line with time-of-flight position !" << endl);
651  return 1;
652  }
653  break;
654  case USE_TOFHISTO:
655  if (ProjectTOFHistogram( a_direction, ap_ProjectionLine ))
656  {
657  Cerr("***** vProjector::Project() -> A problem occurred while projecting a line with binned time-of-flight !" << endl);
658  return 1;
659  }
660  break;
661  // No default
662  }
663 
664  #ifdef CASTOR_VERBOSE
665  if (m_verbose>=10)
666  {
667  Cout("vProjector::Project() -> Exit function" << endl);
668  }
669  #endif
670 
671  // End
672  return 0;
673 }
674 
675 // =====================================================================
676 // ---------------------------------------------------------------------
677 // ---------------------------------------------------------------------
678 // =====================================================================
std::chrono::seconds Secs
FLTNB * GetOrientation1()
This function is used to get the pointer to the mp_orientation1 (3-values tab).
FLTNB * GetPOI1()
This function is used to get the pointer to POI of point 1 (3-values tab).
static void ShowCommonHelp()
This function is used to print out some help about the use of options common to all projectors...
int ReadStringOption(const string &a_input, T *ap_return, int a_nbElts, const string &sep, const string &a_option)
Parse the &#39;a_input&#39; string corresponding to the &#39;a_option&#39; into &#39;a_nbElts&#39; elements, using the &#39;sep&#39; separator. The results are returned in the templated &#39;ap_return&#39; dynamic templated array. Call "ConvertFromString()" to perform the correct conversion depending on the type of the data to convert.
FLTNB GetVoxSizeX()
Get the voxel&#39;s size along the X axis, in mm.
#define Cerr(MESSAGE)
FLTNB GetVoxSizeZ()
Get the voxel&#39;s size along the Z axis, in mm.
FLTNB * GetBufferPosition2()
This function is used to get the pointer to the mp_bufferPosition2 (3-values tab).
std::chrono::time_point< std::chrono::system_clock > ChronoTime
vProjector()
The constructor of vProjector.
int Initialize()
A public function used to initialize the projector.
virtual int ProjectTOFHistogram(int a_direction, oProjectionLine *ap_ProjectionLine)=0
int Project(int a_direction, oProjectionLine *ap_ProjectionLine, uint32_t *ap_index1, uint32_t *ap_index2, int a_nbIndices)
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
std::chrono::hours Hs
FLTNB * GetBufferPosition1()
This function is used to get the pointer to the mp_bufferPosition1 (3-values tab).
virtual int ProjectWithoutTOF(int a_direction, oProjectionLine *ap_ProjectionLine)=0
void Exit(int code)
FLTNB * GetOrientation2()
This function is used to get the pointer to the mp_orientation2 (3-values tab).
virtual int CheckSpecificParameters()=0
A private function used to check the parameters settings specific to the child projector.
void ComputeLineLength()
Simply compute and update the m_length using the associated mp_position1 and mp_position2.
int ReadCommonOptionsList(const string &a_optionsList)
FLTNB GetVoxSizeY()
Get the voxel&#39;s size along the Y axis, in mm.
void ApplyOffset()
Apply the offset of oImageDimensionsAndQuantification to the mp_position1 and mp_position2.
FLTNB * GetPosition1()
This function is used to get the pointer to the mp_position1 (3-values tab).
virtual void ShowHelpSpecific()=0
A function used to show help about the child module.
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
FLTNB * GetBufferOrientation1()
This function is used to get the pointer to the mp_bufferOrientation1 (3-values tab).
virtual ~vProjector()
The destructor of vProjector.
int CheckParameters()
A public function used to check the parameters settings.
FLTNB * GetBufferOrientation2()
This function is used to get the pointer to the mp_bufferOrientation2 (3-values tab).
This class is designed to manage and store system matrix elements associated to a vEvent...
virtual int ProjectTOFListmode(int a_direction, oProjectionLine *ap_ProjectionLine)=0
virtual int InitializeSpecific()=0
A private function used to initialize everything specific to the child projector. ...
std::chrono::duration< int64_t, std::nano > DurationNano
This class is designed to manage all dimensions and quantification related stuff. ...
FLTNB * GetPosition2()
This function is used to get the pointer to the mp_position2 (3-values tab).
INTNB GetNbVoxX()
Get the number of voxels along the X axis.
INTNB GetNbVoxZ()
Get the number of voxels along the Z axis.
virtual INTNB EstimateMaxNumberOfVoxelsPerLine()
This function is used to compute and provide an estimate of the maximum number of voxels that could c...
std::chrono::minutes Mins
void ShowHelp()
A function used to show help about the projector.
FLTNB * GetPOI2()
This function is used to get the pointer to POI of point 2 (3-values tab).
int SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
void ApplyBedOffset()
Apply the bed offset of m_bedOffset to the mp_position1 and mp_position2.
#define Cout(MESSAGE)
virtual int GetPositionsAndOrientations(int a_index1, int a_index2, FLTNB ap_Position1[3], FLTNB ap_Position2[3], FLTNB ap_Orientation1[3], FLTNB ap_Orientation2[3], FLTNB *ap_POI1=NULL, FLTNB *ap_POI2=NULL)=0
INTNB GetNbVoxY()
Get the number of voxels along the Y axis.