CASToR  2.0
Tomographic Reconstruction (PET/SPECT/CT)
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
oProjectionLine.cc
Go to the documentation of this file.
1 /*
2 This file is part of CASToR.
3 
4  CASToR is free software: you can redistribute it and/or modify it under the
5  terms of the GNU General Public License as published by the Free Software
6  Foundation, either version 3 of the License, or (at your option) any later
7  version.
8 
9  CASToR is distributed in the hope that it will be useful, but WITHOUT ANY
10  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  details.
13 
14  You should have received a copy of the GNU General Public License along with
15  CASToR (in file GNU_GPL.TXT). If not, see <http://www.gnu.org/licenses/>.
16 
17 Copyright 2017-2018 all CASToR contributors listed below:
18 
19  --> current contributors: Thibaut MERLIN, Simon STUTE, Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Mael MILLARDET
20  --> past contributors: Valentin VIELZEUF
21 
22 This is CASToR version 2.0.
23 */
24 
31 #include "oProjectionLine.hh"
32 #include "sOutputManager.hh"
33 #include "vProjector.hh"
34 
35 // =====================================================================
36 // ---------------------------------------------------------------------
37 // ---------------------------------------------------------------------
38 // =====================================================================
39 
41 {
42  // Default all values
43  m_verbose = 0;
44  m_checked = false;
45  m_initialized = false;
46  m_bedOffset = 0.;
47  m_nbTOFBins = -1;
48  m_currentTOFBin = 0;
49  m_TOFResolution = -1.;
50  m_TOFMeasurement = 0.;
51  mp_POI1 = NULL;
52  mp_POI2 = NULL;
53  mp_POIResolution = NULL;
54  m_useMatchedProjectors = false;
55  mp_ForwardProjector = NULL;
56  mp_BackwardProjector = NULL;
57  m_length = 0.;
58  m2p_allocatedNbVoxels = NULL;
59  m2p_currentNbVoxels = NULL;
60  m3p_voxelIndices = NULL;
61  m3p_voxelWeights = NULL;
64  mp_position1 = NULL;
65  mp_position2 = NULL;
66  mp_orientation1 = NULL;
67  mp_orientation2 = NULL;
68  mp_bufferPosition1 = NULL;
69  mp_bufferPosition2 = NULL;
70  mp_bufferOrientation1 = NULL;
71  mp_bufferOrientation2 = NULL;
72  m_threadNumber = -1;
74  m_index1 = -1;
75  m_index2 = -1;
76 }
77 
78 // =====================================================================
79 // ---------------------------------------------------------------------
80 // ---------------------------------------------------------------------
81 // =====================================================================
82 
84 {
85  // Go through the destructor only if the object was initialized
86  if (m_initialized)
87  {
88  // Delete voxels lists
89  for (int b=0; b<m_nbTOFBins; b++)
90  {
91  if (m3p_voxelIndices[FORWARD][b])
92  {
94  else delete m3p_voxelIndices[FORWARD][b];
95  }
96  if (m3p_voxelWeights[FORWARD][b])
97  {
99  else delete m3p_voxelWeights[FORWARD][b];
100  }
102  {
103  if (m3p_voxelIndices[BACKWARD][b])
104  {
106  else delete m3p_voxelIndices[BACKWARD][b];
107  }
108  if (m3p_voxelWeights[BACKWARD][b])
109  {
111  else delete m3p_voxelWeights[BACKWARD][b];
112  }
113  }
114  }
115  // Delete rest
117  if (m3p_voxelWeights[FORWARD]) delete[] m3p_voxelWeights[FORWARD];
119  {
121  if (m3p_voxelWeights[BACKWARD]) delete[] m3p_voxelWeights[BACKWARD];
122  }
124  if (m2p_currentNbVoxels[FORWARD]) delete m2p_currentNbVoxels[FORWARD];
126  {
128  if (m2p_currentNbVoxels[BACKWARD]) delete m2p_currentNbVoxels[BACKWARD];
129  }
130  }
131 }
132 
133 // =====================================================================
134 // ---------------------------------------------------------------------
135 // ---------------------------------------------------------------------
136 // =====================================================================
137 
139 {
140  // Check mandatory parameters
141  if (m_nbTOFBins<=0)
142  {
143  Cerr("***** oProjectionLine::CheckParameters() -> Forbidden number of TOF bins (" << m_nbTOFBins << ") !" << endl);
144  Exit(EXIT_FAILURE);
145  }
147  {
148  Cerr("***** oProjectionLine::CheckParameters() -> Computation strategy incorrectly set !" << endl);
149  return 1;
150  }
151  if (mp_POIResolution==NULL)
152  {
153  Cerr("***** oProjectionLine::CheckParameters() -> POI resolution not set !" << endl);
154  return 1;
155  }
157  {
158  Cerr("***** oProjectionLine::CheckParameters() -> oImageDimensionsAndQuantification not set !" << endl);
159  return 1;
160  }
161  if (m_threadNumber<0)
162  {
163  Cerr("***** oProjectionLine::CheckParameters() -> The thread number associated to this line is not set !" << endl);
164  return 1;
165  }
166  // End
167  m_checked = true;
168  return 0;
169 }
170 
171 // =====================================================================
172 // ---------------------------------------------------------------------
173 // ---------------------------------------------------------------------
174 // =====================================================================
175 
177 {
178  // Forbid initialization without check
179  if (!m_checked)
180  {
181  Cerr("***** oProjectionLine::Initialize() -> Must call CheckParameters() before Initialize() !" << endl);
182  return 1;
183  }
184 
185  // Verbose
186  if (m_verbose>=4) Cout("oProjectionLine::Initialize() -> Initialize this projection line for thread " << m_threadNumber << endl);
187 
188  // Default LOR length
189  m_length = 0.;
190 
191  // Allocate pointers that depend on forward or backward projectors
192  m2p_allocatedNbVoxels = new INTNB*[2];
193  m2p_currentNbVoxels = new INTNB*[2];
194  m3p_voxelIndices = new INTNB**[2];
195  m3p_voxelWeights = new FLTNB**[2];
196 
197  // Allocate number of voxels and lists for forward projector
202 
203  // Allocate number of voxels and lists for backward projector
205  {
206  // If one single projector, then simply link pointers
211  }
212  else
213  {
214  // If separated projectors, then allocate
219  }
220 
221  // --------------------------------------------------------------------------------------
222  // Image computation strategy
224  {
225  // This image computation strategy is not compatible with system matrix projectors
226  if (mp_ForwardProjector==NULL || mp_BackwardProjector==NULL)
227  {
228  Cerr("***** oProjectionLine::Initialize() -> Image computation strategy is not compatible with the use of system matrix projectors !" << endl);
229  return 1;
230  }
231  // Verbose
232  if (m_verbose>=5) Cout(" --> Choose the image computation strategy" << endl);
233  // The number of voxels is held fixed to the image dimensions
235  // Set numbers and allocate
236  for (int b=0; b<m_nbTOFBins; b++)
237  {
238  // Just to remember the size of the image
239  m2p_allocatedNbVoxels[FORWARD][b] = nb_voxels;
240  m2p_currentNbVoxels[FORWARD][b] = nb_voxels;
241  // Voxel indices are useless with this computation strategy
242  m3p_voxelIndices[FORWARD][b] = NULL;
243  // Voxel weights
244  m3p_voxelWeights[FORWARD][b] = new FLTNB[nb_voxels];
245  // Do the same for backward projector if needed
247  {
248  // Just to remember the size of the image
249  m2p_allocatedNbVoxels[BACKWARD][b] = nb_voxels;
250  m2p_currentNbVoxels[BACKWARD][b] = nb_voxels;
251  // Voxel indices are useless with this computation strategy
252  m3p_voxelIndices[BACKWARD][b] = NULL;
253  // Voxel weights
254  m3p_voxelWeights[BACKWARD][b] = new FLTNB[nb_voxels];
255  }
256  }
257  }
258  // --------------------------------------------------------------------------------------
259  // Fixed list computation strategy
261  {
262  // Verbose
263  if (m_verbose>=5) Cout(" --> Choose the fixed list computation strategy" << endl);
264  // Set numbers and allocate
265  for (int b=0; b<m_nbTOFBins; b++)
266  {
267  // For the system matrix case
268  if (mp_ForwardProjector==NULL)
269  {
270  // Verbose
271  if (m_verbose>=5) Cout(" --> System matrix for forward projection" << endl);
272  // The number of allocated voxels is fixed with this strategy
275  // Voxel indices set to NULL for the moment because the pointer will be copied during the execution
276  m3p_voxelIndices[FORWARD][b] = NULL;
277  // Voxel weights also set to NULL
278  m3p_voxelWeights[FORWARD][b] = NULL;
279  }
280  // For the projector case
281  else
282  {
283  // The number of allocated voxels is fixed with this strategy
286  // Verbose
287  if (m_verbose>=5) Cout(" --> Projector for forward projection using " << m2p_allocatedNbVoxels[FORWARD][b] << " allocated voxels" << endl);
288  // Voxel indices
290  // Voxel weights
291  m3p_voxelWeights[FORWARD][b] = new FLTNB[m2p_allocatedNbVoxels[FORWARD][b]];
292  }
293  // Do the same for backward projector if needed
295  {
296  // For the system matrix case
297  if (mp_BackwardProjector==NULL)
298  {
299  // Verbose
300  if (m_verbose>=5) Cout(" --> System matrix for backward projection" << endl);
301  // The number of allocated voxels is fixed with this strategy
304  // Voxel indices set to NULL for the moment because the pointer will be copied during the execution
305  m3p_voxelIndices[BACKWARD][b] = NULL;
306  // Voxel weights also set to NULL
307  m3p_voxelWeights[BACKWARD][b] = NULL;
308  }
309  // For the projector case
310  else
311  {
312  // The number of allocated voxels is fixed with this strategy
315  // Verbose
316  if (m_verbose>=5) Cout(" --> Projector for backward projection using " << m2p_allocatedNbVoxels[BACKWARD][b] << " allocated voxels" << endl);
317  // Voxel indices
319  // Voxel weights
320  m3p_voxelWeights[BACKWARD][b] = new FLTNB[m2p_allocatedNbVoxels[BACKWARD][b]];
321  }
322  }
323  }
324  }
325  // --------------------------------------------------------------------------------------
326  // Adaptative list computation strategy
328  {
329  // This image computation strategy is not compatible with system matrix projectors
330  if (mp_ForwardProjector==NULL || mp_BackwardProjector==NULL)
331  {
332  Cerr("***** oProjectionLine::Initialize() -> Adaptative list computation strategy is not compatible with the use of system matrix projectors !" << endl);
333  return 1;
334  }
335  // The number of voxels is set to the diagonal as a first guess
337  // Verbose
338  if (m_verbose>=5) Cout(" --> Choose the adaptative list computation strategy, starting with " << nb_voxels << " allocated voxels" << endl);
339  // Set numbers and allocate
340  for (int b=0; b<m_nbTOFBins; b++)
341  {
342  // The number of allocated voxels is fixed with this strategy
343  m2p_allocatedNbVoxels[FORWARD][b] = nb_voxels;
345  // Voxel indices
346  m3p_voxelIndices[FORWARD][b] = (INTNB*)malloc(nb_voxels*sizeof(INTNB));
347  // Voxel weights
348  m3p_voxelWeights[FORWARD][b] = (FLTNB*)malloc(nb_voxels*sizeof(FLTNB));
349  // Do the same for backward projector if needed
351  {
352  // The number of allocated voxels is fixed with this strategy
353  m2p_allocatedNbVoxels[BACKWARD][b] = nb_voxels;
355  // Voxel indices
356  m3p_voxelIndices[BACKWARD][b] = (INTNB*)malloc(nb_voxels*sizeof(INTNB));
357  // Voxel weights
358  m3p_voxelWeights[BACKWARD][b] = (FLTNB*)malloc(nb_voxels*sizeof(FLTNB));
359  }
360  }
361  }
362 
363  // Allocate position and orientation of end points (as well as buffers)
364  mp_position1 = (FLTNB*)malloc(3*sizeof(FLTNB));
365  mp_position2 = (FLTNB*)malloc(3*sizeof(FLTNB));
366  mp_orientation1 = (FLTNB*)malloc(3*sizeof(FLTNB));
367  mp_orientation2 = (FLTNB*)malloc(3*sizeof(FLTNB));
368  mp_bufferPosition1 = (FLTNB*)malloc(3*sizeof(FLTNB));
369  mp_bufferPosition2 = (FLTNB*)malloc(3*sizeof(FLTNB));
370  mp_bufferOrientation1 = (FLTNB*)malloc(3*sizeof(FLTNB));
371  mp_bufferOrientation2 = (FLTNB*)malloc(3*sizeof(FLTNB));
372 
373  // End
374  m_initialized = true;
375  return 0;
376 }
377 
378 // =====================================================================
379 // ---------------------------------------------------------------------
380 // ---------------------------------------------------------------------
381 // =====================================================================
382 
384 {
385  #ifdef CASTOR_DEBUG
386  if (!m_initialized)
387  {
388  Cerr("***** oProjectionLine::ComputeLineLength() -> Called while not initialized !" << endl);
389  Exit(EXIT_DEBUG);
390  }
391  #endif
392 
393  #ifdef CASTOR_VERBOSE
394  if (m_verbose>=10) Cout("oProjectionLine::ComputeLineLength() -> Compute length of the line" << endl);
395  #endif
396 
400 }
401 
402 // =====================================================================
403 // ---------------------------------------------------------------------
404 // ---------------------------------------------------------------------
405 // =====================================================================
406 
408 {
409  #ifdef CASTOR_DEBUG
410  if (!m_initialized)
411  {
412  Cerr("***** oProjectionLine::NotEmptyLine() -> Called while not initialized !" << endl);
413  Exit(EXIT_DEBUG);
414  }
415  #endif
416 
417  #ifdef CASTOR_VERBOSE
418  if (m_verbose>=10) Cout("oProjectionLine::NotEmptyLine() -> Look if line is empty" << endl);
419  #endif
420 
421  // Just look in all TOF bins whether there are some contributing voxels
422  for (int b=0; b<m_nbTOFBins; b++) if (m2p_currentNbVoxels[FORWARD][b]!=0) return true;
423  return false;
424 }
425 
426 // =====================================================================
427 // ---------------------------------------------------------------------
428 // ---------------------------------------------------------------------
429 // =====================================================================
430 
432 {
433  #ifdef CASTOR_DEBUG
434  if (!m_initialized)
435  {
436  Cerr("***** oProjectionLine::Reset() -> Called while not initialized !" << endl);
437  Exit(EXIT_DEBUG);
438  }
439  #endif
440 
441  #ifdef CASTOR_VERBOSE
442  if (m_verbose>=10) Cout("oProjectionLine::Reset() -> Reset buffers of the line" << endl);
443  #endif
444 
445  // Set the length to zero
446  m_length = 0.;
447  // --------------------------------------------------------------------------------------
448  // Image computation strategy
450  {
451  // Loop on the TOF bins
452  for (int b=0; b<m_nbTOFBins; b++)
453  {
454  // Set all voxel weights to zero
455  for (int v=0; v<m2p_allocatedNbVoxels[FORWARD][b]; v++) m3p_voxelWeights[FORWARD][b][v] = 0.;
456  if (!m_useMatchedProjectors) for (int v=0; v<m2p_allocatedNbVoxels[BACKWARD][b]; v++) m3p_voxelWeights[BACKWARD][b][v] = 0.;
457  }
458  }
459  // --------------------------------------------------------------------------------------
460  // List computation strategy
463  {
464  // Loop on the TOF bins
465  for (int b=0; b<m_nbTOFBins; b++)
466  {
467  // Only reset the number of current voxels, no need to reset matrices
470  }
471  }
472 }
473 
474 // =====================================================================
475 // ---------------------------------------------------------------------
476 // ---------------------------------------------------------------------
477 // =====================================================================
478 
480 {
481  #ifdef CASTOR_DEBUG
482  if (!m_initialized)
483  {
484  Cerr("***** oProjectionLine::ApplyOffset() -> Called while not initialized !" << endl);
485  Exit(EXIT_DEBUG);
486  }
487  #endif
488 
489  #ifdef CASTOR_VERBOSE
490  if (m_verbose>=10) Cout("oProjectionLine::ApplyOffset() -> Apply the global offset to the line end points" << endl);
491  #endif
492 
493  // Offset position 1
497  // Offset position 2
501 }
502 
503 // =====================================================================
504 // ---------------------------------------------------------------------
505 // ---------------------------------------------------------------------
506 // =====================================================================
507 
509 {
510  #ifdef CASTOR_DEBUG
511  if (!m_initialized)
512  {
513  Cerr("***** oProjectionLine::ApplyBedOffset() -> Called while not initialized !" << endl);
514  Exit(EXIT_DEBUG);
515  }
516  #endif
517 
518  #ifdef CASTOR_VERBOSE
519  if (m_verbose>=10) Cout("oProjectionLine::ApplyBedOffset() -> Apply the bed position offset to the line end points" << endl);
520  #endif
521 
522  // Offset position 1
524  // Offset position 2
526 }
527 
528 // =====================================================================
529 // ---------------------------------------------------------------------
530 // ---------------------------------------------------------------------
531 // =====================================================================
532 
533 INTNB oProjectionLine::GetVoxelIndex(int a_direction, int a_TOFBin, INTNB a_voxelInLine)
534 {
535  #ifdef CASTOR_DEBUG
536  if (!m_initialized)
537  {
538  Cerr("***** oProjectionLine::GetVoxelIndex() -> Called while not initialized !" << endl);
539  Exit(EXIT_DEBUG);
540  }
541  #endif
542 
543  #ifdef CASTOR_VERBOSE
544  if (m_verbose>=12)
545  {
546  string direction = "";
547  if (a_direction==FORWARD) direction = "forward";
548  else direction = "backward";
549  Cout("oProjectionLine::GetVoxelIndex() -> Get voxel index of voxel number " << a_voxelInLine << " in TOF bin " << a_TOFBin << " of " << direction << " projector" << endl);
550  }
551  #endif
552 
553  // If image computation strategy, then simply return the voxel index itself
555  return a_voxelInLine;
556  // Otherwise, look up for it in the voxel indices table
557  else
558  return m3p_voxelIndices[a_direction][a_TOFBin][a_voxelInLine];
559 }
560 
561 // =====================================================================
562 // ---------------------------------------------------------------------
563 // ---------------------------------------------------------------------
564 // =====================================================================
565 
566 void oProjectionLine::AddVoxelInTOFBin(int a_direction, int a_TOFBin, INTNB a_voxelIndex, FLTNB a_voxelWeight)
567 {
568  #ifdef CASTOR_DEBUG
569  if (!m_initialized)
570  {
571  Cerr("***** oProjectionLine::AddVoxelInTOFBin() -> Called while not initialized !" << endl);
572  Exit(EXIT_DEBUG);
573  }
574  #endif
575 
576  #ifdef CASTOR_VERBOSE
577  if (m_verbose>=12)
578  {
579  string direction = "";
580  if (a_direction==FORWARD) direction = "forward";
581  else direction = "backward";
582  Cout("oProjectionLine::AddVoxelInTOFBin() -> Add voxel index " << a_voxelIndex << " of weight " << a_voxelWeight <<
583  " into TOF bin " << a_TOFBin << " of " << direction << " projector" << endl);
584  }
585  #endif
586 
588  {
589  // No buffer overflow checks for this computation strategy
590  m3p_voxelIndices[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelIndex;
591  m3p_voxelWeights[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelWeight;
592  m2p_currentNbVoxels[a_direction][a_TOFBin]++;
593  }
595  {
596  // Check if the number of contributing voxels is equal to the allocated size
597  if (m2p_currentNbVoxels[a_direction][a_TOFBin]==m2p_allocatedNbVoxels[a_direction][a_TOFBin])
598  {
599  // We realloc for one more voxel
600  m2p_allocatedNbVoxels[a_direction][a_TOFBin]++;
601  m3p_voxelIndices[a_direction][a_TOFBin] = (INTNB*)realloc(m3p_voxelIndices[a_direction][a_TOFBin],m2p_allocatedNbVoxels[a_direction][a_TOFBin]*sizeof(INTNB));
602  m3p_voxelWeights[a_direction][a_TOFBin] = (FLTNB*)realloc(m3p_voxelWeights[a_direction][a_TOFBin],m2p_allocatedNbVoxels[a_direction][a_TOFBin]*sizeof(FLTNB));
603  }
604  // Then register this voxel contribution
605  m3p_voxelIndices[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelIndex;
606  m3p_voxelWeights[a_direction][a_TOFBin][m2p_currentNbVoxels[a_direction][a_TOFBin]] = a_voxelWeight;
607  m2p_currentNbVoxels[a_direction][a_TOFBin]++;
608  }
609  // Different way of doing for each computation strategy
611  {
612  // Simply add the contribution to this voxel index
613  m3p_voxelWeights[a_direction][a_TOFBin][a_voxelIndex] += a_voxelWeight;
614  }
615 }
616 
617 // =====================================================================
618 // ---------------------------------------------------------------------
619 // ---------------------------------------------------------------------
620 // =====================================================================
621 
622 void oProjectionLine::AddVoxelAllTOFBins(int a_direction, INTNB a_voxelIndex, FLTNB a_voxelWeight, HPFLTNB* a_tofWeights, INTNB a_tofBinFirst, INTNB a_tofBinLast)
623 {
624  #ifdef CASTOR_DEBUG
625  if (!m_initialized)
626  {
627  Cerr("***** oProjectionLine::AddVoxelAllTOFBins() -> Called while not initialized !" << endl);
628  Exit(EXIT_DEBUG);
629  }
630  #endif
631 
632  #ifdef CASTOR_VERBOSE
633  if (m_verbose>=12)
634  {
635  string direction = "";
636  if (a_direction==FORWARD) direction = "forward";
637  else direction = "backward";
638  Cout("oProjectionLine::AddVoxelAllTOFBin() -> Add voxel index " << a_voxelIndex << " and weights for all TOF bins of "
639  << direction << " projector" << endl);
640  }
641  #endif
642 
644  {
645  for (INTNB t=a_tofBinFirst; t<=a_tofBinLast; t++)
646  {
647  // No buffer overflow checks for this computation strategy
648  m3p_voxelIndices[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelIndex;
649  m3p_voxelWeights[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelWeight * (FLTNB)(a_tofWeights[t]);
650  m2p_currentNbVoxels[a_direction][t]++;
651  }
652  }
654  {
655  for (INTNB t=a_tofBinFirst; t<=a_tofBinLast; t++)
656  {
657  // Check if the number of contributing voxels is equal to the allocated size
658  if (m2p_currentNbVoxels[a_direction][t]==m2p_allocatedNbVoxels[a_direction][t])
659  {
660  // We realloc for one more voxel
661  m2p_allocatedNbVoxels[a_direction][t]++;
662  m3p_voxelIndices[a_direction][t] = (INTNB*)realloc(m3p_voxelIndices[a_direction][t],m2p_allocatedNbVoxels[a_direction][t]*sizeof(INTNB));
663  m3p_voxelWeights[a_direction][t] = (FLTNB*)realloc(m3p_voxelWeights[a_direction][t],m2p_allocatedNbVoxels[a_direction][t]*sizeof(FLTNB));
664  }
665  // Then register this voxel contribution
666  m3p_voxelIndices[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelIndex;
667  m3p_voxelWeights[a_direction][t][m2p_currentNbVoxels[a_direction][t]] = a_voxelWeight * (FLTNB)(a_tofWeights[t]);
668  m2p_currentNbVoxels[a_direction][t]++;
669  }
670  }
671  // Different way of doing for each computation strategy
673  {
674  // Simply add the contribution to this voxel index
675  for (INTNB t=a_tofBinFirst; t<=a_tofBinLast; t++)
676  {
677  m3p_voxelWeights[a_direction][t][a_voxelIndex] += a_voxelWeight * (FLTNB)(a_tofWeights[t]);
678  }
679  }
680 }
681 
682 // =====================================================================
683 // ---------------------------------------------------------------------
684 // ---------------------------------------------------------------------
685 // =====================================================================
686 
687 void oProjectionLine::AddVoxel(int a_direction, INTNB a_voxelIndex, FLTNB a_voxelWeight)
688 {
689  #ifdef CASTOR_DEBUG
690  if (!m_initialized)
691  {
692  Cerr("***** oProjectionLine::AddVoxel() -> Called while not initialized !" << endl);
693  Exit(EXIT_DEBUG);
694  }
695  #endif
696 
697  #ifdef CASTOR_VERBOSE
698  if (m_verbose>=12)
699  {
700  string direction = "";
701  if (a_direction==FORWARD) direction = "forward";
702  else direction = "backward";
703  Cout("oProjectionLine::AddVoxel() -> Add voxel index " << a_voxelIndex << " of weight " << a_voxelWeight <<
704  " in " << direction << " projector" << endl);
705  }
706  #endif
707 
708  // No TOF here
709  int no_tof_bin = 0;
710 
712  {
713  // No buffer overflow checks for this computation strategy
714  m3p_voxelIndices[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelIndex;
715  m3p_voxelWeights[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelWeight;
716  m2p_currentNbVoxels[a_direction][no_tof_bin]++;
717  }
719  {
720  // Check if the number of contributing voxels is equal to the allocated size
721  if (m2p_currentNbVoxels[a_direction][no_tof_bin]==m2p_allocatedNbVoxels[a_direction][no_tof_bin])
722  {
723  // We realloc for one more voxel
724  m2p_allocatedNbVoxels[a_direction][no_tof_bin]++;
725  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));
726  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));
727  }
728  // Then register this voxel contribution
729  m3p_voxelIndices[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelIndex;
730  m3p_voxelWeights[a_direction][no_tof_bin][m2p_currentNbVoxels[a_direction][no_tof_bin]] = a_voxelWeight;
731  m2p_currentNbVoxels[a_direction][no_tof_bin]++;
732  }
733  // Different way of doing for each computation strategy
735  {
736  // Simply add the contribution to this voxel index
737  m3p_voxelWeights[a_direction][no_tof_bin][a_voxelIndex] += a_voxelWeight;
738  }
739 }
740 
741 // =====================================================================
742 // ---------------------------------------------------------------------
743 // ---------------------------------------------------------------------
744 // =====================================================================
745 
747 {
748  // The forward projection value
749  FLTNB value = 0.;
750  // If image is NULL, then assume 1 everywhere
751  if (ap_image==NULL)
752  {
753  // Loop over voxels inside the current TOF bin
754  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
756  }
757  // Otherwise, project the image
758  else
759  {
761  {
762  // Loop over the whole image
763  for (int v=0; v<mp_ImageDimensionsAndQuantification->GetNbVoxXYZ(); v++)
764  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v] * ap_image[v];
765  }
766  else
767  {
768  // Loop over voxels inside the current TOF bin
769  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
771  * ap_image[ m3p_voxelIndices[FORWARD][m_currentTOFBin][v] ];
772  }
773  }
774  // Apply multiplicative correction term
776  // Return the value
777  return value;
778 }
779 
780 // =====================================================================
781 // ---------------------------------------------------------------------
782 // ---------------------------------------------------------------------
783 // =====================================================================
784 
786 {
787  #ifdef CASTOR_DEBUG
788  // This function cannot be used by definition when using the image computation strategy
790  {
791  Cerr("***** oProjectionLine::ForwardProjectWithSPECTAttenuation() -> Cannot be used with an image computation strategy over the projection line !" << endl);
792  Exit(EXIT_FAILURE); // Have to exit
793  }
794  // This function cannot be used with an incompatible projector
796  {
797  Cerr("***** oProjectionLine::ForwardProjectWithSPECTAttenuation() -> Cannot be used with an incompatible projector !" << endl);
798  Exit(EXIT_FAILURE); // Have to exit
799  }
800  // Note that normally, the incompatibilities are checked before launching the reconstruction
801  #endif
802 
803  // The forward projection value
804  FLTNB value = 0.;
805 
806  // If image is NULL, then assume 1 everywhere in the emission object
807  if (ap_image==NULL)
808  {
809  // Case without attenuation
810  if (ap_attenuation == NULL)
811  {
812  // Loop over the element in the line
813  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
814  {
815  // Update forward projection
817  }
818  }
819  // Case with attenuation
820  else
821  {
822  // Loop over the element in the line
823  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
824  {
825  FLTNB atn_sum = 0.0;
826  // Compute the attenuation of an element belonging to the line
827  for (int w=v; w<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; w++)
828  atn_sum += ap_attenuation[ m3p_voxelIndices[FORWARD][m_currentTOFBin][w] ] * m3p_voxelWeights[FORWARD][m_currentTOFBin][w];
829  // Take the inverse exponential to save a division after that (and convert from cm-1 to mm-1)
830  atn_sum = std::exp( -atn_sum *0.1 );
831  // Update forward projection
832  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v] * atn_sum;
833  }
834  }
835  }
836  // Otherwise, project the image
837  else
838  {
839  // Case without attenuation
840  if (ap_attenuation == NULL)
841  {
842  // Loop over the element in the line
843  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
844  {
845  // Update projection
847  }
848  }
849  // Case with attenuation
850  else
851  {
852  // Loop over the element in the line
853  for (int v=0; v<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; v++)
854  {
855  FLTNB atn_sum = 0.0;
856  // Compute the attenuation of an element belonging to the line
857  for (int w=v; w<m2p_currentNbVoxels[FORWARD][m_currentTOFBin]; w++)
858  atn_sum += ap_attenuation[ m3p_voxelIndices[FORWARD][m_currentTOFBin][w] ] * m3p_voxelWeights[FORWARD][m_currentTOFBin][w];
859  // Take the inverse exponential to save a division after that (and convert from cm-1 to mm-1)
860  atn_sum = exp( atn_sum * ((FLTNB)(-0.1)) );
861  // Update projection
862  value += m3p_voxelWeights[FORWARD][m_currentTOFBin][v] * ap_image[ m3p_voxelIndices[FORWARD][m_currentTOFBin][v] ] * atn_sum;
863  }
864  }
865  }
866  // Apply multiplicative correction term
868  // Return the value
869  return value;
870 }
871 
872 // =====================================================================
873 // ---------------------------------------------------------------------
874 // ---------------------------------------------------------------------
875 // =====================================================================
876 
878 {
879  // Apply multiplicative correction term
880  a_value /= m_multiplicativeCorrection;
881  // Image-based strategy
883  {
884  // Loop over the whole image
885  for (int v=0; v<mp_ImageDimensionsAndQuantification->GetNbVoxXYZ(); v++)
886  ap_image[v] += a_value * m3p_voxelWeights[BACKWARD][m_currentTOFBin][v];
887  }
888  // List-based strategies
889  else
890  {
891  // Loop over voxels inside the current TOF bin
892  for (int v=0; v<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; v++)
894  }
895 }
896 
897 // =====================================================================
898 // ---------------------------------------------------------------------
899 // ---------------------------------------------------------------------
900 // =====================================================================
901 
903 {
904  #ifdef CASTOR_DEBUG
905  // This function cannot be used by definition when using the image computation strategy
907  {
908  Cerr("***** oProjectionLine::BackwardProjectWithSPECTAttenuation() -> Cannot be used with an image computation strategy over the projection line !" << endl);
909  Exit(EXIT_FAILURE); // Have to exit
910  }
911  // This function cannot be used with an incompatible projector
913  {
914  Cerr("***** oProjectionLine::BackwardProjectWithSPECTAttenuation() -> Cannot be used with an incompatible projector !" << endl);
915  Exit(EXIT_FAILURE); // Have to exit
916  }
917  // Note that normally, the incompatibilities are checked before launching the reconstruction
918  #endif
919 
920  // Apply multiplicative correction term
921  a_value /= m_multiplicativeCorrection;
922 
923  // Case where attenuation is not provided
924  if (ap_attenuation == NULL)
925  {
926  // Loop over the element in the line
927  for (int v=0; v<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; v++)
928  {
929  // Update image
931  }
932  }
933  // Case where attenuation is provided
934  else
935  {
936  // Loop over the element in the line
937  for (int v=0; v<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; v++)
938  {
939  FLTNB atn_sum = 0.0;
940  // Compute the attenuation of an element belonging to the line
941  for (int w=v; w<m2p_currentNbVoxels[BACKWARD][m_currentTOFBin]; w++)
942  atn_sum += ap_attenuation[ m3p_voxelIndices[BACKWARD][m_currentTOFBin][w] ] * m3p_voxelWeights[BACKWARD][m_currentTOFBin][w];
943  // Take the inverse exponential to save a division after that (and convert from cm-1 to mm-1)
944  atn_sum = exp( atn_sum * ((FLTNB)(-0.1)) );
945  // Update image
946  ap_image[ m3p_voxelIndices[BACKWARD][m_currentTOFBin][v] ] += m3p_voxelWeights[BACKWARD][m_currentTOFBin][v] * a_value * atn_sum;
947  }
948  }
949 }
950 
951 // =====================================================================
952 // ---------------------------------------------------------------------
953 // ---------------------------------------------------------------------
954 // =====================================================================
955 
957 {
958  // Will be the cumulative integral
959  FLTNB integral = 0.;
960  // Simply loop over all voxels weights and sum them
961  for (int v=0; v<m2p_currentNbVoxels[a_direction][m_currentTOFBin]; v++)
962  integral += m3p_voxelWeights[a_direction][m_currentTOFBin][v];
963  // Return the result
964  return integral;
965 }
966 
~oProjectionLine()
The destructor of oProjectionLine.
#define IMAGE_COMPUTATION_STRATEGY
FLTNB ForwardProjectWithSPECTAttenuation(FLTNB *ap_attenuation, FLTNB *ap_image=NULL)
Forward projects the provided image for the current TOF bin with an inner loop on the attenuation (fo...
#define FLTNB
Definition: gVariables.hh:81
void AddVoxelAllTOFBins(int a_direction, INTNB a_voxelIndex, FLTNB a_voxelWeight, HPFLTNB *a_tofWeights, INTNB a_tofBinFirst, INTNB a_tofBinLast)
Add a voxel contribution to the line for all relevant TOF bins.
#define HPFLTNB
Definition: gVariables.hh:83
FLTNB * mp_bufferOrientation1
vProjector * mp_ForwardProjector
#define ADAPTATIVE_LIST_COMPUTATION_STRATEGY
bool GetCompatibilityWithSPECTAttenuationCorrection()
Definition: vProjector.hh:319
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)
This function is used to get the contributing voxel index of the provided direction, TOF bin and voxel rank.
INTNB *** m3p_voxelIndices
Declaration of class oProjectionLine.
void BackwardProject(FLTNB *ap_image, FLTNB a_value)
Simply backward projects the provided value inside the provided image, for the current TOF bin...
#define Cerr(MESSAGE)
void ApplyOffset()
Apply the offset of oImageDimensionsAndQuantification to the mp_position1 and mp_position2.
FLTNB *** m3p_voxelWeights
Declaration of class vProjector.
void BackwardProjectWithSPECTAttenuation(FLTNB *ap_attenuation, FLTNB *ap_image, FLTNB a_value)
Backward project the provided value inside the provided image with an inner loop on the attenuation (...
void AddVoxel(int a_direction, INTNB a_voxelIndice, FLTNB a_voxelWeight)
This function is used to add a voxel contribution to the line, assuming TOF bin 0 (i...
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 m_multiplicativeCorrection
FLTNB GetOffsetY()
Get the image offset along the Y axis, in mm.
#define INTNB
Definition: gVariables.hh:92
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.
Declaration of class sOutputManager.
FLTNB ForwardProject(FLTNB *ap_image=NULL)
Simply forward projects the provided image if not null, or else 1, for the current TOF bin...
INTNB GetNbVoxXYZ()
Get the total number of voxels.
FLTNB * mp_bufferPosition1
#define EXIT_DEBUG
Definition: gVariables.hh:97
FLTNB * mp_bufferOrientation2
FLTNB GetOffsetX()
Get the image offset along the X axis, in mm.
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
#define FORWARD
#define Cout(MESSAGE)
INTNB ** m2p_allocatedNbVoxels
virtual INTNB EstimateMaxNumberOfVoxelsPerLine()
This function is used to compute and provide an estimate of the maximum number of voxels that could c...
Definition: vProjector.cc:253
void AddVoxelInTOFBin(int a_direction, int a_TOFBin, INTNB a_voxelIndice, FLTNB a_voxelWeight)
This function is used to add a voxel contribution to the line and provided TOF bin.
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.
FLTNB * mp_bufferPosition2
void ApplyBedOffset()
Apply the bed offset of m_bedOffset to the mp_position1 and mp_position2.
INTNB ** m2p_currentNbVoxels
vProjector * mp_BackwardProjector
#define BACKWARD
FLTNB ComputeLineIntegral(int a_direction)
It simply computes the sum of all voxels contributions following the provided direction.