CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
oComputeProjection.cc
Go to the documentation of this file.
1 
2 /*
3  Implementation of class oComputeProjection
4 
5  - separators: X
6  - doxygen: X
7  - default initialization: X
8  - CASTOR_DEBUG: none
9  - CASTOR_VERBOSE: X
10 */
11 
19 #include "oComputeProjection.hh"
20 
21 
22 // =====================================================================
23 // ---------------------------------------------------------------------
24 // ---------------------------------------------------------------------
25 // =====================================================================
26 /*
27  \brief oComputeProjection constructor.
28  \param ap_ImageDimensionsAndQuantification
29  Initialize the member variables to their default values.
30 */
32 {
33  mp_ID = ap_ImageDimensionsAndQuantification;
34  m_noiseModelEnabled = false;
35 }
36 
37 
38 
39 
40 // =====================================================================
41 // ---------------------------------------------------------------------
42 // ---------------------------------------------------------------------
43 // =====================================================================
44 /*
45  \brief oComputeProjection destructor.
46 */
48 {
49 
50 }
51 
52 
53 
54 
55 // =====================================================================
56 // ---------------------------------------------------------------------
57 // ---------------------------------------------------------------------
58 // =====================================================================
59 /*
60  \fn DataUpdateStep
61  \param ap_DataFile : pointer to the datafile which manage output data writing
62  \param a2p_Line : pointer to the structure containing system matrix components
63  \param ap_Image : pointer to the image space to access forward/attenuation/projection images
64  \param ap_Event : pointer to the structure containing the event geometric indices
65  \param a_fr : frame index
66  \param a_rg : respiratory gate index
67  \param a_cg : cardiac gate index
68  \param a_timestamp : event timestamp
69  \brief Perform the forward-projection, and send the result to the datafile for writing.
70  Implements random Poisson noise.
71  Write the result in the projection image matrix (only implemented for SPECT).
72  \return 0 if success, positive value otherwise
73 */
75  oProjectionLine* a2p_Line,
76  oImageSpace* ap_Image,
77  vEvent* ap_Event,
78  int a_fr,
79  int a_rg,
80  int a_cg,
81  int th,
82  uint32_t a_timestamp)
83 {
84 
85  #ifdef CASTOR_VERBOSE
86  if(m_verbose >=4) Cout("oComputeProjection::DataUpdateStep ... " << endl);
87  #endif
88 
89  FLTNB fp = 0., fp_atn = 0.;
90 
91 
92  // Projection with attenuation for PET
93  //TODO : add fonction in oProjectionLine for PET attenuation ?
94  if(ap_DataFile->GetDataType() == TYPE_PET)
95  {
96  // Forward project input image
97  fp = a2p_Line->ForwardProject(ap_Image->m4p_forwardImage[a_fr][a_rg][a_cg]);
98 
99  // Forward project attenuation if atn map has been provided
100  if(ap_Image->m4p_attenuation != NULL && ap_Image->m4p_attenuation[a_fr][a_rg][a_cg] != NULL)
101  fp_atn = a2p_Line->ForwardProject(ap_Image->m4p_attenuation[a_fr][a_rg][a_cg]) * 0.1; // 0.1 -> convert in mm-1
102 
103  // Apply attenuation factor
104  fp *= std::exp(-fp_atn);
105 
106  // Store Atn correction factor in Event if PET (not recorded in datafile if no atn map provided by the user)
107  (dynamic_cast<iEventPET*>(ap_Event))->SetAttenuationCorrectionFactor(1/exp(-fp_atn));
108  }
109  // Project with attenuation for SPECT
110  else if (ap_DataFile->GetDataType() == TYPE_SPECT)
111  {
112  if(ap_Image->m4p_attenuation != NULL) // Attenuation has been provided
113  fp = a2p_Line->ForwardProjectWithSPECTAttenuation(ap_Image->m4p_attenuation[a_fr][a_rg][a_cg] ,
114  ap_Image->m4p_forwardImage[a_fr][a_rg][a_cg] );
115  else // No attenuation
116  fp = a2p_Line->ForwardProjectWithSPECTAttenuation(NULL ,
117  ap_Image->m4p_forwardImage[a_fr][a_rg][a_cg] );
118  }
119 
120  #ifdef CASTOR_VERBOSE
121  if(m_verbose >=4) Cout("oComputeProjection::DataUpdateStep : Projeted value = "<< fp << endl);
122  #endif
123 
124  // Poisson noise
126  {
127  fp = GetPoissonNoise(fp);
128 
129  #ifdef CASTOR_VERBOSE
130  if(m_verbose >=4) Cout("oComputeProjection::DataUpdateStep : Projeted value with Poisson noise = "<< fp << endl);
131  #endif
132  }
133 
134  // Write event in datafile
135  ap_Event->SetEventValue(0, fp);
136  ap_Event->SetTimeInMs(a_timestamp);
137 
138  if(ap_DataFile->PROJ_WriteEvent(ap_Event, th) )
139  {
140  Cerr("*****oComputeProjection::DataUpdateStep()-> Error while trying to write a projeted event" << endl);
141  return 1;
142  }
143 
144  // Add the result to the projection image (only implemented for SPECT)
145  if(ap_DataFile->GetDataType() == TYPE_SPECT)
146  ap_Image->m2p_projectionImage[ap_Event->GetID1(0)][ap_Event->GetID2(0)] += fp;
147 
148  return 0;
149 }
150 
151 
152 
153 
154 // =====================================================================
155 // ---------------------------------------------------------------------
156 // ---------------------------------------------------------------------
157 // =====================================================================
158 /*
159  \fn InitNoiseModel
160  \param aNoiseModel : string corresponding to a noise model
161  \brief This is a premature implementation of noise model initialization
162  for analytic simulator.
163  Currently, only the Poisson noise can be selected.
164  It will be replaced with a more efficient system when a more
165  advanced analytical simulator will be implemented
166  \return 0 if success, positive value otherwise
167 */
168 int oComputeProjection::InitNoiseModel(string aNoiseModel)
169 {
170  if(m_verbose >=3) Cout("oComputeProjection::InitNoiseModel ... " << endl);
171 
172  // Get the noise model name in the options and isolate the real model's options
173 
174  // First check emptyness of the options
175  if (aNoiseModel=="")
176  {
177  m_noiseModelEnabled = false;
178  return 0;
179  }
180  else
181  {
182  string name_noise_model = "";
183  string list_options_noise_model = "";
184  string file_options_noise_model = "";
185 
186  // Search for a colon ":", this indicates that a configuration file is provided after the optimizer name
187  size_t colon = aNoiseModel.find_first_of(":");
188  size_t comma = aNoiseModel.find_first_of(",");
189 
190  // Case 1: we have a colon
191  if (colon!=string::npos)
192  {
193  // Get the optimizer name before the colon
194  name_noise_model = aNoiseModel.substr(0,colon);
195  // Get the configuration file after the colon
196  file_options_noise_model = aNoiseModel.substr(colon+1);
197  // List of options is empty
198  list_options_noise_model = "";
199  }
200  // Case 2: we have a comma
201  else if (comma!=string::npos)
202  {
203  // Get the optimizer name before the first comma
204  name_noise_model = aNoiseModel.substr(0,comma);
205  // Get the list of options after the first comma
206  list_options_noise_model = aNoiseModel.substr(comma+1);
207  // Configuration file is empty
208  file_options_noise_model = "";
209  }
210  // Case 3: no colon and no comma (a single model name)
211  else
212  {
213  // Get the optimizer name
214  name_noise_model = aNoiseModel;
215  // Configuration file is empty
216  file_options_noise_model = "";
217  // List of options is empty
218  list_options_noise_model = "";
219  }
220 
221  // Check if the noise model is known
222  if (aNoiseModel == "poisson")
223  {
224  m_noiseModelEnabled = true;
225  return 0;
226  }
227  else
228  {
229  Cerr("*****oComputeProjection::InitNoiseModel()-> Error while trying to initialize noise model. Model '"<<aNoiseModel<<"' is unknown"<<endl;);
230  return 1;
231  }
232  }
233 
234  return 0;
235 }
236 
237 
238 
239 
240 // =====================================================================
241 // ---------------------------------------------------------------------
242 // ---------------------------------------------------------------------
243 // =====================================================================
244 /*
245  \fn GetPoissonNoise
246  \param a_lambda : event rate
247  \brief Generate a Poisson random variable from a provided lambda
248  \details Depending on lambda, use either :
249  - Poisson noise if a_lambda <= 60
250  - Normal approximation otherwise
251  \return a random value
252  \todo Check Implementation
253  \todo Use C++11 Poisson noise distribution ?
254 */
255 uint32_t oComputeProjection::GetPoissonNoise(int32_t a_lambda)
256 {
257  #ifdef CASTOR_VERBOSE
258  if(m_verbose >=4) Cout("oComputeProjection::GetPoissonNoise ... " << endl);
259  #endif
260 
261  // Get instance of Random Number Generator
263 
264  double return_value = 0.;
265 
266  // Normal approximation for projection with high value
267  if (a_lambda > 60)
268  {
269  double rdm_1, rdm_2, w;
270 
271  do
272  {
273  rdm_1 = 2.0 * p_RNG->GenerateRdmNber() - 1.0;
274  rdm_2 = 2.0 * p_RNG->GenerateRdmNber() - 1.0;
275  w = rdm_1*rdm_1 + rdm_2*rdm_2;
276  } while (w > 1.0);
277 
278  w = sqrt( (-2.0 * log(w) ) / w );
279 
280  return_value = a_lambda + sqrt(a_lambda)*rdm_1*w;
281 
282  return_value = (return_value<0) ? 0 : round(return_value);
283  }
284  // Poisson noise
285  else
286  {
287  double L = exp(-(a_lambda));
288  int n = 0;
289  double p = 1;
290 
291  do
292  {
293  n++;
294  // Generate uniform random number u in [0,1] and let p ← p × u.
295  p *= p_RNG->GenerateRdmNber();
296  } while (p > L);
297 
298  return_value = n-1;
299  }
300 
301  return (uint32_t) return_value;
302 }
FLTNB **** m4p_forwardImage
Definition: oImageSpace.hh:68
This class is designed to be a mother virtual class for Datafile.
Definition: vDataFile.hh:67
FLTNB ** m2p_projectionImage
Definition: oImageSpace.hh:144
static sRandomNumberGenerator * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define TYPE_PET
Definition: vDataFile.hh:51
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:55
double GenerateRdmNber()
Generate a random number for the thread whose index is recovered from the ompenMP function...
uint32_t GetID2(int a_line)
Definition: vEvent.hh:88
virtual void SetEventValue(int a_bin, FLTNBDATA a_value)=0
This function is implemented by child classes.
Definition: vEvent.hh:120
#define TYPE_SPECT
Definition: vDataFile.hh:53
int InitNoiseModel(string aNoiseModel)
This is a premature implementation of noise model initialization for analytic simulator. Currently, only the Poisson noise can be selected.
#define Cerr(MESSAGE)
int GetDataType()
Definition: vDataFile.hh:286
virtual int PROJ_WriteEvent(vEvent *ap_Event, int a_th)=0
This function is implemented in child classes Write event according to the chosen type of data...
oComputeProjection(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
oComputeProjection constructor.
Singleton class that generate a thread-safe random generator number for openMP As singleton...
int DataUpdateStep(vDataFile *ap_DataFile, oProjectionLine *a2p_Line, oImageSpace *ap_Image, vEvent *ap_Event, int a_fr, int a_rg, int a_cg, int th, uint32_t a_timestamp)
Perform the forward-projection, and send the result to the datafile for writing. Implements random ...
Inherit from vEvent. Main PET class for the Event objects.
Definition: iEventPET.hh:22
This class is designed to manage and store system matrix elements associated to a vEvent...
void SetTimeInMs(uint32_t a_value)
Set the timestamp of the Event.
Definition: vEvent.hh:119
This class holds all the matrices in the image domain that can be used in the algorithm: image...
Definition: oImageSpace.hh:41
Mother class for the Event objects.
Definition: vEvent.hh:23
FLTNB ForwardProject(FLTNB *ap_image=NULL)
Simply forward projects the provided image if not null, or else 1, for the current TOF bin...
uint32_t GetID1(int a_line)
Definition: vEvent.hh:81
This class is designed to manage all dimensions and quantification related stuff. ...
uint32_t GetPoissonNoise(int32_t a_lambda)
Generate a Poisson random variable from a provided lambda.
oImageDimensionsAndQuantification * mp_ID
#define Cout(MESSAGE)
FLTNB **** m4p_attenuation
Definition: oImageSpace.hh:108
~oComputeProjection()
oComputeProjection destructor.
Declaration of class oComputeProjection.