CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
src/projector/oProjectionLine.cc
Go to the documentation of this file.
1 
8 #include "oProjectionLine.hh"
9 #include "sOutputManager.hh"
10 #include "vProjector.hh"
11 
12 // =====================================================================
13 // ---------------------------------------------------------------------
14 // ---------------------------------------------------------------------
15 // =====================================================================
16 
18 {
19  // Default all values
20  m_verbose = 0;
21  m_checked = false;
22  m_initialized = false;
23  m_bedOffset = 0.;
24  m_nbTOFBins = -1;
25  m_currentTOFBin = 0;
27  mp_POI1 = NULL;
28  mp_POI2 = NULL;
29  mp_POIResolution = NULL;
30  m_nbCustomINTData = -1;
31  m_nbCustomFLTData = -1;
32  mp_customINTData = NULL;
33  mp_customFLTData = NULL;
34  m_useMatchedProjectors = false;
35  mp_ForwardProjector = NULL;
36  mp_BackwardProjector = NULL;
37  m_length = 0.;
38  m2p_allocatedNbVoxels = NULL;
39  m2p_currentNbVoxels = NULL;
40  m3p_voxelIndices = NULL;
41  m3p_voxelWeights = NULL;
44  mp_position1 = NULL;
45  mp_position2 = NULL;
46  mp_orientation1 = NULL;
47  mp_orientation2 = NULL;
48  mp_bufferPosition1 = NULL;
49  mp_bufferPosition2 = NULL;
50  mp_bufferOrientation1 = NULL;
51  mp_bufferOrientation2 = NULL;
52  m_threadNumber = -1;
54  m_index1 = -1;
55  m_index2 = -1;
56 }
57 
58 // =====================================================================
59 // ---------------------------------------------------------------------
60 // ---------------------------------------------------------------------
61 // =====================================================================
62 
64 {
65  // Go through the destructor only if the object was initialized
66  if (m_initialized)
67  {
68  // Delete voxels lists
69  for (int b=0; b<m_nbTOFBins; b++)
70  {
71  if (m3p_voxelIndices[FORWARD][b])
72  {
74  else delete m3p_voxelIndices[FORWARD][b];
75  }
76  if (m3p_voxelWeights[FORWARD][b])
77  {
79  else delete m3p_voxelWeights[FORWARD][b];
80  }
82  {
83  if (m3p_voxelIndices[BACKWARD][b])
84  {
86  else delete m3p_voxelIndices[BACKWARD][b];
87  }
88  if (m3p_voxelWeights[BACKWARD][b])
89  {
91  else delete m3p_voxelWeights[BACKWARD][b];
92  }
93  }
94  }
95  // Delete rest
97  if (m3p_voxelWeights[FORWARD]) delete[] m3p_voxelWeights[FORWARD];
99  {
101  if (m3p_voxelWeights[BACKWARD]) delete[] m3p_voxelWeights[BACKWARD];
102  }
104  if (m2p_currentNbVoxels[FORWARD]) delete m2p_currentNbVoxels[FORWARD];
106  {
108  if (m2p_currentNbVoxels[BACKWARD]) delete m2p_currentNbVoxels[BACKWARD];
109  }
110  }
111 }
112 
113 // =====================================================================
114 // ---------------------------------------------------------------------
115 // ---------------------------------------------------------------------
116 // =====================================================================
117 
119 {
120  // Check mandatory parameters
121  if (m_nbTOFBins<=0)
122  {
123  Cerr("***** oProjectionLine::CheckParameters() -> Forbidden number of TOF bins (" << m_nbTOFBins << ") !" << endl);
124  Exit(EXIT_FAILURE);
125  }
127  {
128  Cerr("***** oProjectionLine::CheckParameters() -> Computation strategy incorrectly set !" << endl);
129  return 1;
130  }
131  if (mp_POIResolution==NULL)
132  {
133  Cerr("***** oProjectionLine::CheckParameters() -> POI resolution not set !" << endl);
134  return 1;
135  }
137  {
138  Cerr("***** oProjectionLine::CheckParameters() -> oImageDimensionsAndQuantification not set !" << endl);
139  return 1;
140  }
141  if (m_threadNumber<0)
142  {
143  Cerr("***** oProjectionLine::CheckParameters() -> The thread number associated to this line is not set !" << endl);
144  return 1;
145  }
146  // End
147  m_checked = true;
148  return 0;
149 }
150 
151 // =====================================================================
152 // ---------------------------------------------------------------------
153 // ---------------------------------------------------------------------
154 // =====================================================================
155 
157 {
158  // Forbid initialization without check
159  if (!m_checked)
160  {
161  Cerr("***** oProjectionLine::Initialize() -> Must call CheckParameters() before Initialize() !" << endl);
162  return 1;
163  }
164 
165  // Verbose
166  if (m_verbose>=4) Cout("oProjectionLine::Initialize() -> Initialize this projection line for thread " << m_threadNumber << endl);
167 
168  // Default LOR length
169  m_length = 0.;
170 
171  // Allocate pointers that depend on forward or backward projectors
172  m2p_allocatedNbVoxels = new INTNB*[2];
173  m2p_currentNbVoxels = new INTNB*[2];
174  m3p_voxelIndices = new INTNB**[2];
175  m3p_voxelWeights = new FLTNB**[2];
176 
177  // Allocate number of voxels and lists for forward projector
182 
183  // Allocate number of voxels and lists for backward projector
185  {
186  // If one single projector, then simply link pointers
191  }
192  else
193  {
194  // If separated projectors, then allocate
199  }
200 
201  // --------------------------------------------------------------------------------------
202  // Image computation strategy
204  {
205  // This image computation strategy is not compatible with system matrix projectors
206  if (mp_ForwardProjector==NULL || mp_BackwardProjector==NULL)
207  {
208  Cerr("***** oProjectionLine::Initialize() -> Image computation strategy is not compatible with the use of system matrix projectors !" << endl);
209  return 1;
210  }
211  // Verbose
212  if (m_verbose>=5) Cout(" --> Choose the image computation strategy" << endl);
213  // The number of voxels is held fixed to the image dimensions
215  // Set numbers and allocate
216  for (int b=0; b<m_nbTOFBins; b++)
217  {
218  // Just to remember the size of the image
219  m2p_allocatedNbVoxels[FORWARD][b] = nb_voxels;
220  m2p_currentNbVoxels[FORWARD][b] = nb_voxels;
221  // Voxel indices are useless with this computation strategy
222  m3p_voxelIndices[FORWARD][b] = NULL;
223  // Voxel weights
224  m3p_voxelWeights[FORWARD][b] = new FLTNB[nb_voxels];
225  // Do the same for backward projector if needed
227  {
228  // Just to remember the size of the image
229  m2p_allocatedNbVoxels[BACKWARD][b] = nb_voxels;
230  m2p_currentNbVoxels[BACKWARD][b] = nb_voxels;
231  // Voxel indices are useless with this computation strategy
232  m3p_voxelIndices[BACKWARD][b] = NULL;
233  // Voxel weights
234  m3p_voxelWeights[BACKWARD][b] = new FLTNB[nb_voxels];
235  }
236  }
237  }
238  // --------------------------------------------------------------------------------------
239  // Fixed list computation strategy
241  {
242  // Verbose
243  if (m_verbose>=5) Cout(" --> Choose the fixed list computation strategy" << endl);
244  // Set numbers and allocate
245  for (int b=0; b<m_nbTOFBins; b++)
246  {
247  // For the system matrix case
248  if (mp_ForwardProjector==NULL)
249  {
250  // Verbose
251  if (m_verbose>=5) Cout(" --> System matrix for forward projection" << endl);
252  // The number of allocated voxels is fixed with this strategy
255  // Voxel indices set to NULL for the moment because the pointer will be copied during the execution
256  m3p_voxelIndices[FORWARD][b] = NULL;
257  // Voxel weights also set to NULL
258  m3p_voxelWeights[FORWARD][b] = NULL;
259  }
260  // For the projector case
261  else
262  {
263  // The number of allocated voxels is fixed with this strategy
266  // Verbose
267  if (m_verbose>=5)
268  {
269  if (m_nbTOFBins>1) Cout(" --> Allocate " << m2p_allocatedNbVoxels[FORWARD][b] << " voxels for forward projection of TOF bin " << b << endl);
270  else Cout(" --> Allocate " << m2p_allocatedNbVoxels[FORWARD][b] << " voxels for forward projection" << endl);
271  }
272  // Voxel indices
274  // Voxel weights
275  m3p_voxelWeights[FORWARD][b] = new FLTNB[m2p_allocatedNbVoxels[FORWARD][b]];
276  }
277  // Do the same for backward projector if needed
279  {
280  // For the system matrix case
281  if (mp_BackwardProjector==NULL)
282  {
283  // Verbose
284  if (m_verbose>=5) Cout(" --> System matrix for backward projection" << endl);
285  // The number of allocated voxels is fixed with this strategy
288  // Voxel indices set to NULL for the moment because the pointer will be copied during the execution
289  m3p_voxelIndices[BACKWARD][b] = NULL;
290  // Voxel weights also set to NULL
291  m3p_voxelWeights[BACKWARD][b] = NULL;
292  }
293  // For the projector case
294  else
295  {
296  // The number of allocated voxels is fixed with this strategy
299  // Verbose
300  if (m_verbose>=5)
301  {
302  if (m_nbTOFBins>1) Cout(" --> Allocate " << m2p_allocatedNbVoxels[FORWARD][b] << " voxels for backward projection of TOF bin " << b << endl);
303  else Cout(" --> Allocate " << m2p_allocatedNbVoxels[FORWARD][b] << " voxels for backward projection" << endl);
304  }
305  // Voxel indices
307  // Voxel weights
308  m3p_voxelWeights[BACKWARD][b] = new FLTNB[m2p_allocatedNbVoxels[BACKWARD][b]];
309  }
310  }
311  }
312  }
313  // --------------------------------------------------------------------------------------
314  // Adaptative list computation strategy
316  {
317  // This image computation strategy is not compatible with system matrix projectors
318  if (mp_ForwardProjector==NULL || mp_BackwardProjector==NULL)
319  {
320  Cerr("***** oProjectionLine::Initialize() -> Adaptative list computation strategy is not compatible with the use of system matrix projectors !" << endl);
321  return 1;
322  }
323  // The number of voxels is set to the diagonal as a first guess
325  // Verbose
326  if (m_verbose>=5) Cout(" --> Choose the adaptative list computation strategy, starting with " << nb_voxels << " allocated voxels" << endl);
327  // Set numbers and allocate
328  for (int b=0; b<m_nbTOFBins; b++)
329  {
330  // The number of allocated voxels is fixed with this strategy
331  m2p_allocatedNbVoxels[FORWARD][b] = nb_voxels;
333  // Voxel indices
334  m3p_voxelIndices[FORWARD][b] = (INTNB*)malloc(nb_voxels*sizeof(INTNB));
335  // Voxel weights
336  m3p_voxelWeights[FORWARD][b] = (FLTNB*)malloc(nb_voxels*sizeof(FLTNB));
337  // Do the same for backward projector if needed
339  {
340  // The number of allocated voxels is fixed with this strategy
341  m2p_allocatedNbVoxels[BACKWARD][b] = nb_voxels;
343  // Voxel indices
344  m3p_voxelIndices[BACKWARD][b] = (INTNB*)malloc(nb_voxels*sizeof(INTNB));
345  // Voxel weights
346  m3p_voxelWeights[BACKWARD][b] = (FLTNB*)malloc(nb_voxels*sizeof(FLTNB));
347  }
348  }
349  }
350 
351  // Allocate position and orientation of end points (as well as buffers)
352  mp_position1 = (FLTNB*)malloc(3*sizeof(FLTNB));
353  mp_position2 = (FLTNB*)malloc(3*sizeof(FLTNB));
354  mp_orientation1 = (FLTNB*)malloc(3*sizeof(FLTNB));
355  mp_orientation2 = (FLTNB*)malloc(3*sizeof(FLTNB));
356  mp_bufferPosition1 = (FLTNB*)malloc(3*sizeof(FLTNB));
357  mp_bufferPosition2 = (FLTNB*)malloc(3*sizeof(FLTNB));
358  mp_bufferOrientation1 = (FLTNB*)malloc(3*sizeof(FLTNB));
359  mp_bufferOrientation2 = (FLTNB*)malloc(3*sizeof(FLTNB));
360 
361  // End
362  m_initialized = true;
363  return 0;
364 }
365 
366 // =====================================================================
367 // ---------------------------------------------------------------------
368 // ---------------------------------------------------------------------
369 // =====================================================================
370 
372 {
373  #ifdef CASTOR_DEBUG
374  if (!m_initialized)
375  {
376  Cerr("***** oProjectionLine::ComputeLineLength() -> Called while not initialized !" << endl);
377  Exit(EXIT_DEBUG);
378  }
379  #endif
380 
381  #ifdef CASTOR_VERBOSE
382  if (m_verbose>=10) Cout("oProjectionLine::ComputeLineLength() -> Compute length of the line" << endl);
383  #endif
384 
388 }
389 
390 // =====================================================================
391 // ---------------------------------------------------------------------
392 // ---------------------------------------------------------------------
393 // =====================================================================
394 
396 {
397  #ifdef CASTOR_DEBUG
398  if (!m_initialized)
399  {
400  Cerr("***** oProjectionLine::NotEmptyLine() -> Called while not initialized !" << endl);
401  Exit(EXIT_DEBUG);
402  }
403  #endif
404 
405  #ifdef CASTOR_VERBOSE
406  if (m_verbose>=10) Cout("oProjectionLine::NotEmptyLine() -> Look if line is empty" << endl);
407  #endif
408 
409  // Just look in all TOF bins whether there are some contributing voxels
410  for (int b=0; b<m_nbTOFBins; b++) if (m2p_currentNbVoxels[FORWARD][b]!=0) return true;
411  return false;
412 }
413 
414 // =====================================================================
415 // ---------------------------------------------------------------------
416 // ---------------------------------------------------------------------
417 // =====================================================================
418 
420 {
421  #ifdef CASTOR_DEBUG
422  if (!m_initialized)
423  {
424  Cerr("***** oProjectionLine::Reset() -> Called while not initialized !" << endl);
425  Exit(EXIT_DEBUG);
426  }
427  #endif
428 
429  #ifdef CASTOR_VERBOSE
430  if (m_verbose>=10) Cout("oProjectionLine::Reset() -> Reset buffers of the line" << endl);
431  #endif
432 
433  // Set the length to zero
434  m_length = 0.;
435  // --------------------------------------------------------------------------------------
436  // Image computation strategy
438  {
439  // Loop on the TOF bins
440  for (int b=0; b<m_nbTOFBins; b++)
441  {
442  // Set all voxel weights to zero
443  for (int v=0; v<m2p_allocatedNbVoxels[FORWARD][b]; v++) m3p_voxelWeights[FORWARD][b][v] = 0.;
444  if (!m_useMatchedProjectors) for (int v=0; v<m2p_allocatedNbVoxels[BACKWARD][b]; v++) m3p_voxelWeights[BACKWARD][b][v] = 0.;
445  }
446  }
447  // --------------------------------------------------------------------------------------
448  // List computation strategy
451  {
452  // Loop on the TOF bins
453  for (int b=0; b<m_nbTOFBins; b++)
454  {
455  // Only reset the number of current voxels, no need to reset matrices
458  }
459  }
460 }
461 
462 // =====================================================================
463 // ---------------------------------------------------------------------
464 // ---------------------------------------------------------------------
465 // =====================================================================
466 
468 {
469  #ifdef CASTOR_DEBUG
470  if (!m_initialized)
471  {
472  Cerr("***** oProjectionLine::ApplyOffset() -> Called while not initialized !" << endl);
473  Exit(EXIT_DEBUG);
474  }
475  #endif
476 
477  #ifdef CASTOR_VERBOSE
478  if (m_verbose>=10) Cout("oProjectionLine::ApplyOffset() -> Apply the global offset to the line end points" << endl);
479  #endif
480 
481  // Offset position 1
485  // Offset position 2
489 }
490 
491 // =====================================================================
492 // ---------------------------------------------------------------------
493 // ---------------------------------------------------------------------
494 // =====================================================================
495 
497 {
498  #ifdef CASTOR_DEBUG
499  if (!m_initialized)
500  {
501  Cerr("***** oProjectionLine::ApplyBedOffset() -> Called while not initialized !" << endl);
502  Exit(EXIT_DEBUG);
503  }
504  #endif
505 
506  #ifdef CASTOR_VERBOSE
507  if (m_verbose>=10) Cout("oProjectionLine::ApplyBedOffset() -> Apply the bed position offset to the line end points" << endl);
508  #endif
509 
510  // Offset position 1
512  // Offset position 2
514 }
515 
516 // =====================================================================
517 // ---------------------------------------------------------------------
518 // ---------------------------------------------------------------------
519 // =====================================================================
520 
521 INTNB oProjectionLine::GetVoxelIndex(int a_direction, int a_TOFBin, INTNB a_voxelInLine)
522 {
523  #ifdef CASTOR_DEBUG
524  if (!m_initialized)
525  {
526  Cerr("***** oProjectionLine::GetVoxelIndex() -> Called while not initialized !" << endl);
527  Exit(EXIT_DEBUG);
528  }
529  #endif
530 
531  #ifdef CASTOR_VERBOSE
532  if (m_verbose>=12)
533  {
534  string direction = "";
535  if (a_direction==FORWARD) direction = "forward";
536  else direction = "backward";
537  Cout("oProjectionLine::GetVoxelIndex() -> Get voxel index of voxel number " << a_voxelInLine << " in TOF bin " << a_TOFBin << " of " << direction << " projector" << endl);
538  }
539  #endif
540 
541  // If image computation strategy, then simply return the voxel index itself
543  return a_voxelInLine;
544  // Otherwise, look up for it in the voxel indices table
545  else
546  return m3p_voxelIndices[a_direction][a_TOFBin][a_voxelInLine];
547 }
548 
549 // =====================================================================
550 // ---------------------------------------------------------------------
551 // ---------------------------------------------------------------------
552 // =====================================================================
553 
554 void oProjectionLine::AddVoxelInTOFBin(int a_direction, int a_TOFBin, INTNB a_voxelIndex, FLTNB a_voxelWeight)
555 {
556  #ifdef CASTOR_DEBUG
557  if (!m_initialized)
558  {
559  Cerr("***** oProjectionLine::AddVoxelInTOFBin() -> Called while not initialized !" << endl);
560  Exit(EXIT_DEBUG);
561  }
562  #endif
563 
564  #ifdef CASTOR_VERBOSE
565  if (m_verbose>=12)
566  {
567  string direction = "";
568  if (a_direction==FORWARD) direction = "forward";
569  else direction = "backward";
570  Cout("oProjectionLine::AddVoxelInTOFBin() -> Add voxel index " << a_voxelIndex << " of weight " << a_voxelWeight <<
571  " into TOF bin " << a_TOFBin << " of " << direction << " projector" << endl);
572  }
573  #endif
574 
576  {
577  // No buffer overflow checks for this computation strategy
578  m3p_voxelIndices[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelIndex;
579  m3p_voxelWeights[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelWeight;
580  m2p_currentNbVoxels[a_direction][a_TOFBin]++;
581  }
583  {
584  // Check if the number of contributing voxels is equal to the allocated size
585  if (m2p_currentNbVoxels[a_direction][a_TOFBin]==m2p_allocatedNbVoxels[a_direction][a_TOFBin])
586  {
587  // We realloc for one more voxel
588  m2p_allocatedNbVoxels[a_direction][a_TOFBin]++;
589  m3p_voxelIndices[a_direction][a_TOFBin] = (INTNB*)realloc(m3p_voxelIndices[a_direction][a_TOFBin],m2p_allocatedNbVoxels[a_direction][a_TOFBin]*sizeof(INTNB));
590  m3p_voxelWeights[a_direction][a_TOFBin] = (FLTNB*)realloc(m3p_voxelWeights[a_direction][a_TOFBin],m2p_allocatedNbVoxels[a_direction][a_TOFBin]*sizeof(FLTNB));
591  }
592  // Then register this voxel contribution
593  m3p_voxelIndices[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelIndex;
594  m3p_voxelWeights[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelWeight;
595  m2p_currentNbVoxels[a_direction][a_TOFBin]++;
596  }
597  // Different way of doing for each computation strategy
599  {
600  // Simply add the contribution to this voxel index
601  m3p_voxelWeights[a_direction][a_TOFBin][a_voxelIndex] += a_voxelWeight;
602  }
603 }
604 
605 // =====================================================================
606 // ---------------------------------------------------------------------
607 // ---------------------------------------------------------------------
608 // =====================================================================
609 
610 void oProjectionLine::AddVoxelAllTOFBins(int a_direction, INTNB a_voxelIndex, FLTNB a_voxelWeight, HPFLTNB* a_tofWeights, INTNB a_tofBinFirst, INTNB a_tofBinLast)
611 {
612  #ifdef CASTOR_DEBUG
613  if (!m_initialized)
614  {
615  Cerr("***** oProjectionLine::AddVoxelAllTOFBins() -> Called while not initialized !" << endl);
616  Exit(EXIT_DEBUG);
617  }
618  #endif
619 
620  #ifdef CASTOR_VERBOSE
621  if (m_verbose>=12)
622  {
623  string direction = "";
624  if (a_direction==FORWARD) direction = "forward";
625  else direction = "backward";
626  Cout("oProjectionLine::AddVoxelAllTOFBin() -> Add voxel index " << a_voxelIndex << " and weights for all TOF bins of "
627  << direction << " projector" << endl);
628  }
629  #endif
630 
632  {
633  for (INTNB t=a_tofBinFirst; t<=a_tofBinLast; t++)
634  {
635  // No buffer overflow checks for this computation strategy
636  m3p_voxelIndices[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelIndex;
637  m3p_voxelWeights[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelWeight * (FLTNB)(a_tofWeights[t]);
638  m2p_currentNbVoxels[a_direction][t]++;
639  }
640  }
642  {
643  for (INTNB t=a_tofBinFirst; t<=a_tofBinLast; t++)
644  {
645  // Check if the number of contributing voxels is equal to the allocated size
646  if (m2p_currentNbVoxels[a_direction][t]==m2p_allocatedNbVoxels[a_direction][t])
647  {
648  // We realloc for one more voxel
649  m2p_allocatedNbVoxels[a_direction][t]++;
650  m3p_voxelIndices[a_direction][t] = (INTNB*)realloc(m3p_voxelIndices[a_direction][t],m2p_allocatedNbVoxels[a_direction][t]*sizeof(INTNB));
651  m3p_voxelWeights[a_direction][t] = (FLTNB*)realloc(m3p_voxelWeights[a_direction][t],m2p_allocatedNbVoxels[a_direction][t]*sizeof(FLTNB));
652  }
653  // Then register this voxel contribution
654  m3p_voxelIndices[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelIndex;
655  m3p_voxelWeights[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelWeight * (FLTNB)(a_tofWeights[t]);
656  m2p_currentNbVoxels[a_direction][t]++;
657  }
658  }
659  // Different way of doing for each computation strategy
661  {
662  // Simply add the contribution to this voxel index
663  for (INTNB t=a_tofBinFirst; t<=a_tofBinLast; t++)
664  {
665  m3p_voxelWeights[a_direction][t][a_voxelIndex] += a_voxelWeight * (FLTNB)(a_tofWeights[t]);
666  }
667  }
668 }
669 
670 // =====================================================================
671 // ---------------------------------------------------------------------
672 // ---------------------------------------------------------------------
673 // =====================================================================
674 
675 void oProjectionLine::AddVoxel(int a_direction, INTNB a_voxelIndex, FLTNB a_voxelWeight)
676 {
677  #ifdef CASTOR_DEBUG
678  if (!m_initialized)
679  {
680  Cerr("***** oProjectionLine::AddVoxel() -> Called while not initialized !" << endl);
681  Exit(EXIT_DEBUG);
682  }
683  #endif
684 
685  #ifdef CASTOR_VERBOSE
686  if (m_verbose>=12)
687  {
688  string direction = "";
689  if (a_direction==FORWARD) direction = "forward";
690  else direction = "backward";
691  Cout("oProjectionLine::AddVoxel() -> Add voxel index " << a_voxelIndex << " of weight " << a_voxelWeight <<
692  " in " << direction << " projector" << endl);
693  }
694  #endif
695 
696  // No TOF here
697  int no_tof_bin = 0;
698 
700  {
701  // No buffer overflow checks for this computation strategy
702  m3p_voxelIndices[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelIndex;
703  m3p_voxelWeights[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelWeight;
704  m2p_currentNbVoxels[a_direction][no_tof_bin]++;
705  }
707  {
708  // Check if the number of contributing voxels is equal to the allocated size
709  if (m2p_currentNbVoxels[a_direction][no_tof_bin]==m2p_allocatedNbVoxels[a_direction][no_tof_bin])
710  {
711  // We realloc for one more voxel
712  m2p_allocatedNbVoxels[a_direction][no_tof_bin]++;
713  m3p_voxelIndices[a_direction][no_tof_bin] = (INTNB*)realloc(m3p_voxelIndices[a_direction][no_tof_bin],m2p_allocatedNbVoxels[a_direction][no_tof_bin]*sizeof(INTNB));
714  m3p_voxelWeights[a_direction][no_tof_bin] = (FLTNB*)realloc(m3p_voxelWeights[a_direction][no_tof_bin],m2p_allocatedNbVoxels[a_direction][no_tof_bin]*sizeof(FLTNB));
715  }
716  // Then register this voxel contribution
717  m3p_voxelIndices[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelIndex;
718  m3p_voxelWeights[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelWeight;
719  m2p_currentNbVoxels[a_direction][no_tof_bin]++;
720  }
721  // Different way of doing for each computation strategy
723  {
724  // Simply add the contribution to this voxel index
725  m3p_voxelWeights[a_direction][no_tof_bin][a_voxelIndex] += a_voxelWeight;
726  }
727 }
728 
729 // =====================================================================
730 // ---------------------------------------------------------------------
731 // ---------------------------------------------------------------------
732 // =====================================================================
733 
735 {
736  // The forward projection value
737  FLTNB value = 0.;
738  // If image is NULL, then assume 1 everywhere
739  if (ap_image==NULL)
740  {
741  // Loop over voxels inside the current TOF bin
742  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
743  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v];
744  }
745  // Otherwise, project the image
746  else
747  {
749  {
750  // Loop over the whole image
751  for (int v=0; v<mp_ImageDimensionsAndQuantification->GetNbVoxXYZ(); v++)
752  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v] * ap_image[v];
753  }
754  else
755  {
756  // Loop over voxels inside the current TOF bin
757  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
758  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v]
759  * ap_image[ m3p_voxelIndices[FORWARD][m_currentTOFBin][v] ];
760  }
761  }
762  // Apply multiplicative correction term
764  // Return the value
765  return value;
766 }
767 
768 // =====================================================================
769 // ---------------------------------------------------------------------
770 // ---------------------------------------------------------------------
771 // =====================================================================
772 
774 {
775  #ifdef CASTOR_DEBUG
776  // This function cannot be used by definition when using the image computation strategy
778  {
779  Cerr("***** oProjectionLine::ForwardProjectWithSPECTAttenuation() -> Cannot be used with an image computation strategy over the projection line !" << endl);
780  Exit(EXIT_FAILURE); // Have to exit
781  }
782  // This function cannot be used with an incompatible projector
784  {
785  Cerr("***** oProjectionLine::ForwardProjectWithSPECTAttenuation() -> Cannot be used with an incompatible projector !" << endl);
786  Exit(EXIT_FAILURE); // Have to exit
787  }
788  // Note that normally, the incompatibilities are checked before launching the reconstruction
789  #endif
790 
791  // The forward projection value
792  FLTNB value = 0.;
793 
794  // If image is NULL, then assume 1 everywhere in the emission object
795  if (ap_image==NULL)
796  {
797  // Case without attenuation
798  if (ap_attenuation == NULL)
799  {
800  // Loop over the element in the line
801  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
802  {
803  // Update forward projection
805  }
806  }
807  // Case with attenuation
808  else
809  {
810  // Loop over the element in the line
811  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
812  {
813  FLTNB atn_sum = 0.0;
814  // Compute the attenuation of an element belonging to the line
815  for (int w=v; w<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; w++)
816  atn_sum += ap_attenuation[ m3p_voxelIndices[FORWARD][m_currentTOFBin][w] ] * m3p_voxelWeights[FORWARD][m_currentTOFBin][w];
817  // Take the inverse exponential to save a division after that (and convert from cm-1 to mm-1)
818  atn_sum = std::exp( -atn_sum *0.1 );
819  // Update forward projection
820  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v] * atn_sum;
821  }
822  }
823  }
824  // Otherwise, project the image
825  else
826  {
827  // Case without attenuation
828  if (ap_attenuation == NULL)
829  {
830  // Loop over the element in the line
831  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
832  {
833  // Update projection
835  }
836  }
837  // Case with attenuation
838  else
839  {
840  // Loop over the element in the line
841  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
842  {
843  FLTNB atn_sum = 0.0;
844  // Compute the attenuation of an element belonging to the line
845  for (int w=v; w<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; w++)
846  atn_sum += ap_attenuation[ m3p_voxelIndices[FORWARD][m_currentTOFBin][w] ] * m3p_voxelWeights[FORWARD][m_currentTOFBin][w];
847  // Take the inverse exponential to save a division after that (and convert from cm-1 to mm-1)
848  atn_sum = exp( atn_sum * ((FLTNB)(-0.1)) );
849  // Update projection
850  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v] * ap_image[ m3p_voxelIndices[FORWARD][m_currentTOFBin][v] ] * atn_sum;
851  }
852  }
853  }
854  // Apply multiplicative correction term
856  // Return the value
857  return value;
858 }
859 
860 // =====================================================================
861 // ---------------------------------------------------------------------
862 // ---------------------------------------------------------------------
863 // =====================================================================
864 
865 void oProjectionLine::BackwardProject(FLTNB* ap_image, FLTNB a_value)
866 {
867  // Apply multiplicative correction term
868  a_value /= m_multiplicativeCorrection;
869  // Image-based strategy
871  {
872  // Loop over the whole image
873  for (int v=0; v<mp_ImageDimensionsAndQuantification->GetNbVoxXYZ(); v++)
874  ap_image[v] += a_value * m3p_voxelWeights[BACKWARD][m_currentTOFBin][v];
875  }
876  // List-based strategies
877  else
878  {
879  // Loop over voxels inside the current TOF bin
880  for (int v=0; v<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; v++)
881  ap_image[ m3p_voxelIndices[BACKWARD][m_currentTOFBin][v] ] += a_value * m3p_voxelWeights[BACKWARD][m_currentTOFBin][v];
882  }
883 }
884 
885 // =====================================================================
886 // ---------------------------------------------------------------------
887 // ---------------------------------------------------------------------
888 // =====================================================================
889 
890 void oProjectionLine::BackwardProjectWithSPECTAttenuation(FLTNB* ap_attenuation, FLTNB* ap_image, FLTNB a_value)
891 {
892  #ifdef CASTOR_DEBUG
893  // This function cannot be used by definition when using the image computation strategy
895  {
896  Cerr("***** oProjectionLine::BackwardProjectWithSPECTAttenuation() -> Cannot be used with an image computation strategy over the projection line !" << endl);
897  Exit(EXIT_FAILURE); // Have to exit
898  }
899  // This function cannot be used with an incompatible projector
901  {
902  Cerr("***** oProjectionLine::BackwardProjectWithSPECTAttenuation() -> Cannot be used with an incompatible projector !" << endl);
903  Exit(EXIT_FAILURE); // Have to exit
904  }
905  // Note that normally, the incompatibilities are checked before launching the reconstruction
906  #endif
907 
908  // Apply multiplicative correction term
909  a_value /= m_multiplicativeCorrection;
910 
911  // Case where attenuation is not provided
912  if (ap_attenuation == NULL)
913  {
914  // Loop over the element in the line
915  for (int v=0; v<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; v++)
916  {
917  // Update image
919  }
920  }
921  // Case where attenuation is provided
922  else
923  {
924  // Loop over the element in the line
925  for (int v=0; v<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; v++)
926  {
927  FLTNB atn_sum = 0.0;
928  // Compute the attenuation of an element belonging to the line
929  for (int w=v; w<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; w++)
930  atn_sum += ap_attenuation[ m3p_voxelIndices[BACKWARD][m_currentTOFBin][w] ] * m3p_voxelWeights[BACKWARD][m_currentTOFBin][w];
931  // Take the inverse exponential to save a division after that (and convert from cm-1 to mm-1)
932  atn_sum = exp( atn_sum * ((FLTNB)(-0.1)) );
933  // Update image
934  ap_image[ m3p_voxelIndices[BACKWARD][m_currentTOFBin][v] ] += m3p_voxelWeights[BACKWARD][m_currentTOFBin][v] * a_value * atn_sum;
935  }
936  }
937 }
938 
939 // =====================================================================
940 // ---------------------------------------------------------------------
941 // ---------------------------------------------------------------------
942 // =====================================================================
943 
945 {
946  // Will be the cumulative integral
947  FLTNB integral = 0.;
948  // Simply loop over all voxels weights and sum them
949  for (int v=0; v<m2p_currentNbVoxels[a_direction][m_currentTOFBin]; v++)
950  integral += m3p_voxelWeights[a_direction][m_currentTOFBin][v];
951  // Return the result
952  return integral;
953 }
954 
~oProjectionLine()
The destructor of oProjectionLine.
FLTNB ForwardProjectWithSPECTAttenuation(FLTNB *ap_attenuation, FLTNB *ap_image=NULL)
#define Cerr(MESSAGE)
void AddVoxelAllTOFBins(int a_direction, INTNB a_voxelIndex, FLTNB a_voxelWeight, HPFLTNB *a_tofWeights, INTNB a_tofBinFirst, INTNB a_tofBinLast)
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
#define ADAPTATIVE_LIST_COMPUTATION_STRATEGY
void Exit(int code)
oProjectionLine()
The constructor of oProjectionLine.
void ComputeLineLength()
Simply compute and update the m_length using the associated mp_position1 and mp_position2.
#define FIXED_LIST_COMPUTATION_STRATEGY
INTNB GetVoxelIndex(int a_direction, int a_TOFBin, INTNB a_voxelInLine)
void BackwardProject(FLTNB *ap_image, FLTNB a_value)
void ApplyOffset()
Apply the offset of oImageDimensionsAndQuantification to the mp_position1 and mp_position2.
void BackwardProjectWithSPECTAttenuation(FLTNB *ap_attenuation, FLTNB *ap_image, FLTNB a_value)
void AddVoxel(int a_direction, INTNB a_voxelIndice, FLTNB a_voxelWeight)
void Reset()
Reset length and all the voxel indices and weights tabs.
bool NotEmptyLine()
This function is used to know if the line contains any voxel contribution.
FLTNB GetOffsetY()
Get the image offset along the Y axis, in mm.
INTNB GetNbVoxDiagonal()
Get an estimation of the number of voxels along the image diagonal.
FLTNB GetOffsetZ()
Get the image offset along the Z axis, in mm.
FLTNB ForwardProject(FLTNB *ap_image=NULL)
FLTNB GetOffsetX()
Get the image offset along the X axis, in mm.
virtual INTNB EstimateMaxNumberOfVoxelsPerLine()
This function is used to compute and provide an estimate of the maximum number of voxels that could c...
void AddVoxelInTOFBin(int a_direction, int a_TOFBin, INTNB a_voxelIndice, FLTNB a_voxelWeight)
int CheckParameters()
A function used to check the parameters settings.
int Initialize()
A function used to initialize a bunch of stuff after parameters have been checked.
void ApplyBedOffset()
Apply the bed offset of m_bedOffset to the mp_position1 and mp_position2.
#define Cout(MESSAGE)
FLTNB ComputeLineIntegral(int a_direction)