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