CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
iImageConvolverStationaryGaussian.cc
Go to the documentation of this file.
1 
2 /*
3  Implementation of class iImageConvolverStationaryGaussian
4 
5  - separators: done
6  - doxygen: done
7  - default initialization: done
8  - CASTOR_DEBUG:
9  - CASTOR_VERBOSE:
10 */
11 
18 #include "vImageConvolver.hh"
20 #include "oImageSpace.hh"
22 
23 // =====================================================================
24 // ---------------------------------------------------------------------
25 // ---------------------------------------------------------------------
26 // =====================================================================
27 
29 {
30  m_nbSigmas = -1.;
31  m_transFWHM = -1.;
32  m_axialFWHM = -1.;
33  m_dimKernelXY = -1;
34  m_dimKernelXYZ = -1;
35 }
36 
37 // =====================================================================
38 // ---------------------------------------------------------------------
39 // ---------------------------------------------------------------------
40 // =====================================================================
41 
43 {
44 }
45 
46 // =====================================================================
47 // ---------------------------------------------------------------------
48 // ---------------------------------------------------------------------
49 // =====================================================================
50 
52 {
53  cout << "This convolver is based on a classic stationary Gaussian kernel." << endl;
54  cout << "It can be anisotropic so that the transaxial and axial FWHM can be different." << endl;
55  cout << "One also have to choose the number of sigmas of the Gaussian distribution that will be included in the kernel." << endl;
56  cout << "The following options can be used (in this particular order when provided as a list, separated by commas):" << endl;
57  cout << " transaxial FWHM: to set the transaxial FWHM (in mm)" << endl;
58  cout << " axial FWHM: to set the axial FWHM (in mm)" << endl;
59  cout << " number of sigmas: to set the number of sigmas included in the kernel (recommendations: at least 3. and maximum 5.)" << endl;
60 }
61 
62 // =====================================================================
63 // ---------------------------------------------------------------------
64 // ---------------------------------------------------------------------
65 // =====================================================================
66 
67 int iImageConvolverStationaryGaussian::ReadConfigurationFile(const string& a_configurationFile)
68 {
69  string key_word = "";
70  // Read the transaxial FWHM option
71  key_word = "transaxial FWHM";
72  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_transFWHM, 1, KEYWORD_MANDATORY))
73  {
74  Cerr("***** iImageConvolverStationaryGaussian::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
75  return 1;
76  }
77  // Read the axial FWHM option
78  key_word = "axial FWHM";
79  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_axialFWHM, 1, KEYWORD_MANDATORY))
80  {
81  Cerr("***** iImageConvolverStationaryGaussian::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
82  return 1;
83  }
84  // Read the number of sigma option
85  key_word = "number of sigmas";
86  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_nbSigmas, 1, KEYWORD_MANDATORY))
87  {
88  Cerr("***** iImageConvolverStationaryGaussian::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
89  return 1;
90  }
91  // Normal end
92  return 0;
93 }
94 
95 // =====================================================================
96 // ---------------------------------------------------------------------
97 // ---------------------------------------------------------------------
98 // =====================================================================
99 
101 {
102  // There are 3 floating point variables as options
103  FLTNB options[3];
104  // Read them
105  if (ReadStringOption(a_optionsList, options, 3, ",", "Stationary Gaussian convolver configuration"))
106  {
107  Cerr("***** iImageConvolverStationaryGaussian::ReadConfigurationFile() -> Failed to correctly read the list of options !" << endl);
108  return 1;
109  }
110  // Affect options
111  m_transFWHM = options[0];
112  m_axialFWHM = options[1];
113  m_nbSigmas = options[2];
114  // Normal end
115  return 0;
116 }
117 
118 // =====================================================================
119 // ---------------------------------------------------------------------
120 // ---------------------------------------------------------------------
121 // =====================================================================
122 
124 {
125  // Check number of sigmas
126  if (m_nbSigmas<=0.)
127  {
128  Cerr("***** iImageConvolverStationaryGaussian::CheckSpecificParameters() -> Number of sigmas included in the kernel must be strictly positive !" << endl);
129  return 1;
130  }
131  // Check the transaxial FWHM
132  if (m_transFWHM<0.)
133  {
134  Cerr("***** iImageConvolverStationaryGaussian::CheckSpecificParameters() -> Transaxial FWHM is negative !" << endl);
135  return 1;
136  }
137  // Check the axial FWHM
138  if (m_axialFWHM<0.)
139  {
140  Cerr("***** iImageConvolverStationaryGaussian::CheckSpecificParameters() -> Axial FWHM is negative !" << endl);
141  return 1;
142  }
143  // Normal end
144  return 0;
145 }
146 
147 // =====================================================================
148 // ---------------------------------------------------------------------
149 // ---------------------------------------------------------------------
150 // =====================================================================
151 
153 {
154  // Verbose
155  if (m_verbose>=2)
156  {
157  Cout("iImageConvolverStationaryGaussian::BuildConvolutionKernel() -> Compute convolution kernel" << endl);
158  Cout(" --> Transaxial FWHM: " << m_transFWHM << " mm" << endl);
159  Cout(" --> Axial FWHM: " << m_axialFWHM << " mm" << endl);
160  Cout(" --> Included sigmas: " << m_nbSigmas << endl);
161  }
162 
163  // --------------------------------
164  // Stationary kernel
165  // --------------------------------
166 
167  // Set the number of kernels to 1
168  m_nbKernels = 1;
169  // Specify that it is stationary (we do not overload the Convolve() function here)
170  m_stationary = true;
171  // Compute kernel half size based on the number of sigmas included in the kernel
172  FLTNB two_sqrt_two_ln_two = 2.*sqrt(2.*log(2.));
173  FLTNB half_kern_floatX = m_transFWHM * m_nbSigmas / (two_sqrt_two_ln_two*mp_ImageDimensionsAndQuantification->GetVoxSizeX());
174  FLTNB half_kern_floatY = m_transFWHM * m_nbSigmas / (two_sqrt_two_ln_two*mp_ImageDimensionsAndQuantification->GetVoxSizeY());
175  FLTNB half_kern_floatZ = m_axialFWHM * m_nbSigmas / (two_sqrt_two_ln_two*mp_ImageDimensionsAndQuantification->GetVoxSizeZ());
176  // For each half size, if the decimal part is below 0.5, then it will be taken into account into the central kernel's voxel,
177  // otherwise, we had a voxel to the half size
178  INTNB half_kern_dimX = ((INTNB)(half_kern_floatX));
179  if (half_kern_floatX-((FLTNB)half_kern_dimX)>0.5) half_kern_dimX++;
180  INTNB half_kern_dimY = ((INTNB)(half_kern_floatY));
181  if (half_kern_floatY-((FLTNB)half_kern_dimY)>0.5) half_kern_dimY++;
182  INTNB half_kern_dimZ = ((INTNB)(half_kern_floatZ));
183  if (half_kern_floatZ-((FLTNB)half_kern_dimZ)>0.5) half_kern_dimZ++;
184  // Allocate kernel dimensions
185  mp_dimKernelX = (INTNB*)malloc(1*sizeof(INTNB));
186  mp_dimKernelY = (INTNB*)malloc(1*sizeof(INTNB));
187  mp_dimKernelZ = (INTNB*)malloc(1*sizeof(INTNB));
188  // Compute kernel dimensions
189  mp_dimKernelX[0] = half_kern_dimX * 2 + 1;
190  mp_dimKernelY[0] = half_kern_dimY * 2 + 1;
191  mp_dimKernelZ[0] = half_kern_dimZ * 2 + 1;
194  // Verbose
195  if (m_verbose>=2) Cout (" --> Kernel dimensions: [" << mp_dimKernelX[0] << ";" << mp_dimKernelY[0] << ";" << mp_dimKernelZ[0] << "]" << endl);
196  // Allocate kernel
197  m2p_kernel = (FLTNB**)malloc(1*sizeof(FLTNB*));
198  m2p_kernel[0] = (FLTNB*)malloc(m_dimKernelXYZ*sizeof(FLTNB));
199 
200  // --------------------------------
201  // Compute the kernel
202  // --------------------------------
203 
204  // Variables
205  FLTNB sigma_x = m_transFWHM / two_sqrt_two_ln_two;
206  FLTNB sigma_y = m_transFWHM / two_sqrt_two_ln_two;
207  FLTNB sigma_z = m_axialFWHM / two_sqrt_two_ln_two;
208  FLTNB mu_x = (FLTNB)(half_kern_dimX);
209  FLTNB mu_y = (FLTNB)(half_kern_dimY);
210  FLTNB mu_z = (FLTNB)(half_kern_dimZ);
211  // Compute kernel by integration of the Gaussian distribution (this method is not exactly exact... but is closer to it compared to single Gaussian points)
212  FLTNB sum_kernel = 0.;
213  for (int z=0, index=0; z<mp_dimKernelZ[0]; z++)
214  {
215  FLTNB kern_Z = 0.5 * ( erf( ( (((FLTNB)z)-mu_z+0.5)*mp_ImageDimensionsAndQuantification->GetVoxSizeZ()) / (sqrt(2.)*sigma_z) )
216  - erf( ( (((FLTNB)z)-mu_z-0.5)*mp_ImageDimensionsAndQuantification->GetVoxSizeZ()) / (sqrt(2.)*sigma_z) ) );
217  for (int y=0; y<mp_dimKernelY[0]; y++)
218  {
219  FLTNB kern_ZY = 0.5 * ( erf( ( (((FLTNB)y)-mu_y+0.5)*mp_ImageDimensionsAndQuantification->GetVoxSizeY()) / (sqrt(2.)*sigma_y) )
220  - erf( ( (((FLTNB)y)-mu_y-0.5)*mp_ImageDimensionsAndQuantification->GetVoxSizeY()) / (sqrt(2.)*sigma_y) ) )
221  * kern_Z;
222  for (int x=0; x<mp_dimKernelX[0]; x++, index++)
223  {
224  m2p_kernel[0][index] = 0.5 * ( erf( ( (((FLTNB)x)-mu_x+0.5)*mp_ImageDimensionsAndQuantification->GetVoxSizeX()) / (sqrt(2.)*sigma_x) )
225  - erf( ( (((FLTNB)x)-mu_x-0.5)*mp_ImageDimensionsAndQuantification->GetVoxSizeX()) / (sqrt(2.)*sigma_x) ) )
226  * kern_ZY;
227  sum_kernel += m2p_kernel[0][index];
228  }
229  }
230  }
231  // Normalize kernel
232  for (int v=0; v<m_dimKernelXYZ; v++) m2p_kernel[0][v] /= sum_kernel;
233  // Normal end
234  return 0;
235 }
236 
237 // =====================================================================
238 // ---------------------------------------------------------------------
239 // ---------------------------------------------------------------------
240 // =====================================================================
Declaration of class oImageDimensionsAndQuantification.
#define FLTNB
Definition: gVariables.hh:55
FLTNB GetVoxSizeX()
Get the voxel's size along the X axis, in mm.
int BuildConvolutionKernel()
A private function used to build the convolution kernel specific to the child convolver.
FLTNB GetVoxSizeZ()
Get the voxel's size along the Z axis, in mm.
int ReadConfigurationFile(const string &a_fileOptions)
A function used to read options from a configuration file.
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child module.
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
FLTNB GetVoxSizeY()
Get the voxel's size along the Y axis, in mm.
#define Cerr(MESSAGE)
Declaration of class iImageConvolverStationaryGaussian.
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
Definition: gOptions.cc:111
iImageConvolverStationaryGaussian()
The constructor of iImageConvolverStationaryGaussian.
#define KEYWORD_MANDATORY
Definition: gOptions.hh:25
int ReadOptionsList(const string &a_listOptions)
A function used to read options from a list of options.
#define INTNB
Definition: gVariables.hh:64
Declaration of class oImageSpace.
~iImageConvolverStationaryGaussian()
The destructor of iImageConvolverStationaryGaussian.
#define Cout(MESSAGE)
Declaration of class vImageConvolver.
int ReadStringOption(const string &a_input, T *ap_return, int a_nbElts, const string &sep, const string &a_option)
Parse the 'a_input' string corresponding to the 'a_option' into 'a_nbElts' elements, using the 'sep' separator. The results are returned in the templated 'ap_return' dynamic templated array. Call "ConvertFromString()" to perform the correct conversion depending on the type of the data to convert.
Definition: gOptions.cc:50
void ShowHelp()
A function used to show help about the child module.
This abstract class is the generic image convolver class used by the oImageConvolverManager.