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