Orfeo Toolbox  3.16
itkCumulativeGaussianOptimizer.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkCumulativeGaussianOptimizer.cxx,v $
5  Language: C++
6  Date: $Date: 2009-10-27 16:05:46 $
7  Version: $Revision: 1.20 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef _itkCumulativeGaussianOptimizer_cxx
18 #define _itkCumulativeGaussianOptimizer_cxx
19 
21 #include "assert.h"
22 #include "itkMath.h"
23 
24 namespace itk
25 {
26 
28 {
29  // Set some initial values for the variables.
30  m_ComputedMean = 0;
34  m_UpperAsymptote = 0;
35  m_LowerAsymptote = 0;
36  m_OffsetForMean = 0;
37  m_DifferenceTolerance = 1e-10;
38  m_Verbose = 0;
39  m_FitError = 0;
42  m_StopConditionDescription << this->GetNameOfClass() << ": Constructed";
43 }
44 
46 {
47  delete m_FinalSampledArray;
48 }
49 
52 ::ExtendGaussian(MeasureType * originalArray, MeasureType * extendedArray, int startingPointForInsertion)
53 {
54  // Use the parameters from originalArray to construct a Gaussian in extendedArray
55  // shifting the mean to the right by startingPointForInsertion.
56  double mean = startingPointForInsertion + m_ComputedMean;
57  double sd = m_ComputedStandardDeviation;
58  double amplitude = m_ComputedAmplitude;
59 
60  m_OffsetForMean = startingPointForInsertion;
61 
62  for(int i=0; i<(int)(extendedArray->GetNumberOfElements()); i++)
63  {
64  extendedArray->put(i, amplitude * vcl_exp(- ( vcl_pow((i-mean),2) / (2*vcl_pow(sd,2)) ) ));
65  }
66  // Then insert the originalArray over the middle section of extendedArray.
67  for(int i=0; i<(int)(originalArray->GetNumberOfElements()); i++)
68  {
69  extendedArray->put(i+startingPointForInsertion, originalArray->get(i));
70  }
71  return extendedArray;
72 }
73 
74 double
77 {
78  // Given two arrays array1 and array2 of equal length, calculate the average sum of squared
79  // differences between them.
80  int size = array1->GetNumberOfElements();
81  double sum = 0;
82  for (int i=0; i<size; i++)
83  sum = sum + (array1->get(i) - array2->get(i)) * (array1->get(i) - array2->get(i));
84  return (sum/size);
85 }
86 
87 void
89 ::FindParametersOfGaussian(MeasureType * sampledGaussianArray)
90 {
91  // Measure the parameters of the sampled Gaussian curve and use these parameters to
92  // construct an extended curve. Then measure the parameters of the extended curve, which
93  // should be closer to the original Gaussian parameters and recalculate the extended portion
94  // of the curve. Iterate these last two steps until the average sum of squared differences
95  // between 2 iterations converge within differenceTolerance.
96  MeasureGaussianParameters(sampledGaussianArray);
97 
98  if(m_Verbose)
99  {
100  PrintComputedParameterHeader();
101  PrintComputedParameters();
102  }
103 
104  int sampledGaussianArraySize = sampledGaussianArray->GetNumberOfElements();
105  int extendedArraySize = 3 * sampledGaussianArraySize;
106  MeasureType * extendedArray = new MeasureType();
107  extendedArray->SetSize(extendedArraySize);
108  MeasureType * extendedArrayCopy = new MeasureType();
109  extendedArrayCopy->SetSize(extendedArraySize);
110 
111  double averageSumOfSquaredDifferences = m_DifferenceTolerance;
112 
113  extendedArray = ExtendGaussian(sampledGaussianArray, extendedArray, sampledGaussianArraySize);
114 
115  MeasureGaussianParameters(extendedArray);
116  bool smallChangeBetweenIterations = false;
117  while (averageSumOfSquaredDifferences >= m_DifferenceTolerance)
118  {
119  for(int j = 0; j < extendedArraySize; j++)
120  {
121  extendedArrayCopy->put(j, extendedArray->get(j));
122  }
123  extendedArray = RecalculateExtendedArrayFromGaussianParameters(sampledGaussianArray,
124  extendedArray,
125  sampledGaussianArraySize);
126 
127  MeasureGaussianParameters(extendedArray);
128  if(m_Verbose)
129  {
130  PrintComputedParameters();
131  }
132  double temp = averageSumOfSquaredDifferences;
133  averageSumOfSquaredDifferences = FindAverageSumOfSquaredDifferences(extendedArray, extendedArrayCopy);
134 
135  // Stop if there is a very very very small change between iterations.
136  if(vcl_fabs(temp - averageSumOfSquaredDifferences) <= m_DifferenceTolerance)
137  {
138  m_StopConditionDescription.str("");
139  m_StopConditionDescription << this->GetNameOfClass() << ": "
140  << "Change between iterations ("
141  << vcl_fabs(temp - averageSumOfSquaredDifferences)
142  << ") is less than DifferenceTolerance ("
143  << m_DifferenceTolerance
144  << ").";
145  break;
146  }
147  }
148  if (!smallChangeBetweenIterations)
149  {
150  m_StopConditionDescription.str("");
151  m_StopConditionDescription << this->GetNameOfClass() << ": "
152  << "Average sum of squared differences ("
153  << averageSumOfSquaredDifferences
154  << ") is less than DifferenceTolerance ("
155  << m_DifferenceTolerance
156  << ").";
157  }
158 
159  // Update the mean calculation.
160  m_ComputedMean = m_ComputedMean - m_OffsetForMean;
161 
162  delete extendedArray;
163  delete extendedArrayCopy;
164 }
165 
168 {
169  // Assuming the input array is Gaussian, compute the mean, SD, amplitude, and change in intensity.
170  m_ComputedMean = 0;
171  m_ComputedStandardDeviation = 0;
172  m_ComputedAmplitude = 0;
173  m_ComputedTransitionHeight = 0;
174 
175  double sum = 0;
176 
177  // Calculate the mean.
178  for(int i = 0; i < (int)(array->GetNumberOfElements()); i++)
179  {
180  m_ComputedMean += i * array->get(i);
181  sum += array->get(i);
182  }
183  // Assertion fails if number of samples <=2 or UpperAsymptote==LowerAsymptote
184  // improper behavior if number of samples == 3.
185  assert(sum != 0);
186  m_ComputedMean /= sum;
187 
188  // Calculate the standard deviation
189  for(int i = 0; i < (int)(array->GetNumberOfElements()); i++)
190  {
191  m_ComputedStandardDeviation += array->get(i) * vcl_pow((i - m_ComputedMean), 2);
192  }
193  m_ComputedStandardDeviation = vcl_sqrt(m_ComputedStandardDeviation/sum );
194 
195  // For the ERF, sum is the difference between the lower and upper intensities.
196  m_ComputedTransitionHeight = sum;
197 
198  // Calculate the amplitude.
199  m_ComputedAmplitude = sum / (m_ComputedStandardDeviation * vcl_sqrt(2*vnl_math::pi));
200 }
201 
202 void
205 {
206  std::cerr << "Mean\t" << "SD\t" << "Amp\t" << "Transition" <<std::endl;
207 }
208 
211 {
212  std::cerr << m_ComputedMean - m_OffsetForMean << "\t" // Printed mean is shifted.
213  << m_ComputedStandardDeviation << "\t"
214  << m_ComputedAmplitude << "\t"
215  << m_ComputedTransitionHeight << std::endl;
216 }
217 
221  MeasureType * extendedArray,
222  int startingPointForInsertion)
223 {
224  // From the Gaussian parameters stored with the extendedArray,
225  // recalculate the extended portion of the extendedArray,
226  // leaving the inserted original array unchaged.
227  double mean = m_ComputedMean;
228  double sd = m_ComputedStandardDeviation;
229  double amplitude = m_ComputedAmplitude;
230 
231  for(int i = 0; i < (int)(extendedArray->GetNumberOfElements()); i++)
232  {
233  // Leave the original inserted array unchanged.
234  if( i < startingPointForInsertion ||
235  i >= startingPointForInsertion + (int)(originalArray->GetNumberOfElements()) )
236  {
237  extendedArray->put(i, amplitude * vcl_exp(-(vcl_pow((i - mean),2) / (2 * vcl_pow(sd,2)))));
238  }
239  }
240  return extendedArray;
241 }
242 
243 void
245 ::SetDataArray(MeasureType * cumGaussianArray)
246 {
247  m_CumulativeGaussianArray = cumGaussianArray;
248 }
249 
250 void
253 {
254  this->InvokeEvent( StartEvent() );
255  m_StopConditionDescription.str("");
256  m_StopConditionDescription << this->GetNameOfClass() << ": Running";
257 
258  // Declare arrays.
259  int cumGaussianArraySize = m_CumulativeGaussianArray->GetNumberOfElements();
260  int sampledGaussianArraySize = cumGaussianArraySize;
261  // int cumGaussianArrayCopySize = cumGaussianArraySize;
262 
263  MeasureType * sampledGaussianArray = new MeasureType();
264  sampledGaussianArray->SetSize(sampledGaussianArraySize);
265 
266  MeasureType * cumGaussianArrayCopy = new MeasureType();
267  cumGaussianArrayCopy->SetSize(cumGaussianArraySize);
268 
269  // Make a copy of the Cumulative Gaussian sampled data array.
270  for(int j = 0; j < cumGaussianArraySize; j++)
271  {
272  cumGaussianArrayCopy->put(j, m_CumulativeGaussianArray->get(j));
273  }
274  // Take the derivative of the data array resulting in a Gaussian array.
275  MeasureType * derivative = new MeasureType();
276  derivative->SetSize(cumGaussianArraySize - 1);
277 
278  for(int i=1; i < (int)(derivative->GetNumberOfElements()+1); i++)
279  {
280  derivative->put(i-1, m_CumulativeGaussianArray->get(i) - m_CumulativeGaussianArray->get(i-1) );
281  }
282  m_CumulativeGaussianArray = derivative;
283 
284  // Iteratively recalculate and resample the Gaussian array.
285  FindParametersOfGaussian(m_CumulativeGaussianArray);
286 
287  // Generate new Gaussian array with final parameters.
288  for(int i = 0; i < sampledGaussianArraySize; i++)
289  {
290  sampledGaussianArray->put(i, m_ComputedAmplitude * vcl_exp(- ( vcl_pow((i-m_ComputedMean),2) / (2*vcl_pow(m_ComputedStandardDeviation,2)) ) ));
291  }
292  // Add 0.5 to the mean of the sampled Gaussian curve to make up for the 0.5
293  // shift during derivation, then take the integral of the Gaussian sample
294  // to produce a Cumulative Gaussian.
295 
296  for(int i = sampledGaussianArraySize-1; i > 0; i--)
297  {
298  sampledGaussianArray->put(i-1, sampledGaussianArray->get(i) - sampledGaussianArray->get(i-1));
299  }
300  m_ComputedMean += 0.5;
301 
302  // Find the best vertical shift that minimizes the least square error.
303  double c = VerticalBestShift(cumGaussianArrayCopy, sampledGaussianArray);
304 
305  // Add constant c to array.
306  for(int i = 0; i < (int)(sampledGaussianArray->GetNumberOfElements()); i++)
307  {
308  sampledGaussianArray->put(i, sampledGaussianArray->get(i) + c);
309  }
310  // Calculate the mean, standard deviation, lower and upper asymptotes of the
311  // sampled Cumulative Gaussian.
312  int floorOfMean = (int)(m_ComputedMean);
313  double yFloorOfMean = sampledGaussianArray->get(floorOfMean);
314  double yCeilingOfMean = sampledGaussianArray->get(floorOfMean + 1);
315  double y = (m_ComputedMean-floorOfMean)*(yCeilingOfMean-yFloorOfMean)+yFloorOfMean;
316  m_UpperAsymptote = y + m_ComputedTransitionHeight/2;
317  m_LowerAsymptote = y - m_ComputedTransitionHeight/2;
318 
319  m_FinalSampledArray = new MeasureType();
320  m_FinalSampledArray->SetSize(sampledGaussianArray->GetNumberOfElements());
321  for(int i = 0; i < (int)(m_FinalSampledArray->GetNumberOfElements()); i++)
322  {
323  m_FinalSampledArray->put(i, sampledGaussianArray->get(i));
324  }
325  // Calculate the least square error as a measure of goodness of fit.
326  m_FitError = static_cast<CostFunctionType*>(m_CostFunction.GetPointer())->CalculateFitError(sampledGaussianArray);
327 
328 
329  delete sampledGaussianArray;
330  delete cumGaussianArrayCopy;
331  delete derivative;
332 }
333 
335 {
336  for(int i = 0; i < (int)(array->GetNumberOfElements()); i++)
337  {
338  std::cerr << i << " " << array->get(i) << std::endl;
339  }
340 }
341 
342 double
344 ::VerticalBestShift(MeasureType * originalArray, MeasureType * newArray)
345 {
346 
347  // Find the constant to minimize the sum of squares of the difference between original Array and newArray+c
348  // Proof of algorithm:
349  // Let A = the original array.
350  // Let B = the new array.
351  // Let n = the number of elements in each array (note they must be the same).
352  // We want to mimimize sum(((Bi+c) - (Ai))^2).
353  // So we take the derivative with respect to c and equate this derivative to 0.
354  // d/dc sum(((Bi+c) - (Ai))^2) dc = 0
355  // => sum (2(Bi+c - Ai)) = 0
356  // => sum (Bi + c - Ai) = 0
357  // => (sum(Bi)) + (sum(c)) - (sum(Ai)) = 0
358  // => nC = sum(Ai) - sum(Bi)
359  // => C = (sum(Ai) - sum(Bi)) / n
360 
361  double c = 0;
362  int size = originalArray->GetNumberOfElements();
363  for(int i=0; i<size; i++)
364  {
365  c += originalArray->get(i);
366  }
367  for(int i=0; i<size; i++)
368  {
369  c -= newArray->get(i);
370  }
371  return (c/size);
372 }
373 
374 const std::string
377 {
378  return m_StopConditionDescription.str();
379 }
380 
381 void
383 ::PrintSelf(std::ostream &os, Indent indent) const
384 {
385  Superclass::PrintSelf(os,indent);
386 
387  os << indent << "Difference Tolerance = " << m_DifferenceTolerance << std::endl;
388  os << indent << "Computed Mean = " << m_ComputedMean << std::endl;
389  os << indent << "Computed Standard Deviation = " << m_ComputedStandardDeviation << std::endl;
390  os << indent << "Computed Amplitude = " << m_ComputedAmplitude << std::endl;
391  os << indent << "Computed Transition Height = " << m_ComputedTransitionHeight << std::endl;
392 
393  os << indent << "Upper Asymptote = " << m_UpperAsymptote << std::endl;
394  os << indent << "Lower Asymptote = " << m_LowerAsymptote << std::endl;
395  os << indent << "Offset For Mean = " << m_OffsetForMean << std::endl;
396  os << indent << "Verbose = " << m_Verbose << std::endl;
397  os << indent << "Fit Error = " << m_FitError << std::endl;
398 
399  os << indent << "StopConditionDescription: " << m_StopConditionDescription << std::endl;
400  if(m_FinalSampledArray)
401  {
402  os << indent << "Final Sampled Array = " << m_FinalSampledArray << std::endl;
403  }
404  else
405  {
406  os << indent << "Final Sampled Array = [not defined] " << std::endl;
407  }
408 }
409 
410 
411 } // end namespace itk
412 
413 #endif

Generated at Sat Feb 2 2013 23:34:06 for Orfeo Toolbox with doxygen 1.8.1.1