Orfeo Toolbox  3.16
itkLevelSetMotionRegistrationFunction.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkLevelSetMotionRegistrationFunction.txx,v $
5  Language: C++
6  Date: $Date: 2009-10-20 20:39:08 $
7  Version: $Revision: 1.7 $
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 __itkLevelSetMotionRegistrationFunction_txx
18 #define __itkLevelSetMotionRegistrationFunction_txx
19 
21 #include "itkExceptionObject.h"
22 #include "vnl/vnl_math.h"
23 
24 namespace itk {
25 
29 template <class TFixedImage, class TMovingImage, class TDeformationField>
32 {
33 
34  RadiusType r;
35  unsigned int j;
36  for( j = 0; j < ImageDimension; j++ )
37  {
38  r[j] = 0;
39  }
40  this->SetRadius(r);
41 
42  m_Alpha = 0.1;
43  m_GradientMagnitudeThreshold = 1e-9;
44  m_IntensityDifferenceThreshold = 0.001;
45  m_GradientSmoothingStandardDeviations = 1.0;
46  this->SetMovingImage(NULL);
47  this->SetFixedImage(NULL);
48 
49  typename DefaultInterpolatorType::Pointer interp =
50  DefaultInterpolatorType::New();
51 
52  m_MovingImageInterpolator = static_cast<InterpolatorType*>(
53  interp.GetPointer() );
54 
55  m_Metric = NumericTraits<double>::max();
56  m_SumOfSquaredDifference = 0.0;
57  m_NumberOfPixelsProcessed = 0L;
58  m_RMSChange = NumericTraits<double>::max();
59  m_SumOfSquaredChange = 0.0;
60  m_UseImageSpacing = true;
61 
62  m_MovingImageSmoothingFilter = MovingImageSmoothingFilterType::New();
63  m_MovingImageSmoothingFilter
64  ->SetSigma( m_GradientSmoothingStandardDeviations );
65  m_MovingImageSmoothingFilter->SetNormalizeAcrossScale(false);
66 
67  m_SmoothMovingImageInterpolator
68  = static_cast<InterpolatorType *>(
69  DefaultInterpolatorType::New().GetPointer());
70 }
71 
72 
73 /*
74  * Standard "PrintSelf" method.
75  */
76 template <class TFixedImage, class TMovingImage, class TDeformationField>
77 void
79 ::PrintSelf(std::ostream& os, Indent indent) const
80 {
81  Superclass::PrintSelf(os, indent);
82 
83  os << indent << "MovingImageIterpolator: ";
84  os << m_MovingImageInterpolator.GetPointer() << std::endl;
85  os << indent << "IntensityDifferenceThreshold: ";
86  os << m_IntensityDifferenceThreshold << std::endl;
87  os << indent << "GradientMagnitudeThreshold: ";
88  os << m_GradientMagnitudeThreshold << std::endl;
89  os << indent << "Alpha: ";
90  os << m_Alpha << std::endl;
91 
92  os << indent << "Metric: ";
93  os << m_Metric << std::endl;
94  os << indent << "SumOfSquaredDifference: ";
95  os << m_SumOfSquaredDifference << std::endl;
96  os << indent << "NumberOfPixelsProcessed: ";
97  os << m_NumberOfPixelsProcessed << std::endl;
98  os << indent << "RMSChange: ";
99  os << m_RMSChange << std::endl;
100  os << indent << "SumOfSquaredChange: ";
101  os << m_SumOfSquaredChange << std::endl;
102 
103 }
104 
105 
109 template <class TFixedImage, class TMovingImage, class TDeformationField>
110 void
112 ::SetAlpha(double alpha)
113 {
114  m_Alpha = alpha;
115 }
116 
120 template <class TFixedImage, class TMovingImage, class TDeformationField>
121 double
123 ::GetAlpha() const
124 {
125  return m_Alpha;
126 }
127 
131 template <class TFixedImage, class TMovingImage, class TDeformationField>
132 void
135 {
136  m_IntensityDifferenceThreshold = threshold;
137 }
138 
142 template <class TFixedImage, class TMovingImage, class TDeformationField>
143 double
146 {
147  return m_IntensityDifferenceThreshold;
148 }
149 
150 
154 template <class TFixedImage, class TMovingImage, class TDeformationField>
155 void
158 {
159  m_GradientMagnitudeThreshold = threshold;
160 }
161 
165 template <class TFixedImage, class TMovingImage, class TDeformationField>
166 double
169 {
170  return m_GradientMagnitudeThreshold;
171 }
172 
173 
177 template <class TFixedImage, class TMovingImage, class TDeformationField>
178 void
181 {
182  m_GradientSmoothingStandardDeviations = sigma;
183 }
184 
188 template <class TFixedImage, class TMovingImage, class TDeformationField>
189 double
192 {
193  return m_GradientSmoothingStandardDeviations;
194 }
195 
200 template <class TFixedImage, class TMovingImage, class TDeformationField>
201 bool
204 {
205  return this->m_UseImageSpacing;
206 }
207 
212 template <class TFixedImage, class TMovingImage, class TDeformationField>
213 void
215 ::SetUseImageSpacing( bool useImageSpacing )
216 {
217  this->m_UseImageSpacing = useImageSpacing;
218 }
219 
223 template <class TFixedImage, class TMovingImage, class TDeformationField>
224 void
227 {
228  if( !this->GetMovingImage() || !this->GetFixedImage() || !m_MovingImageInterpolator )
229  {
230  itkExceptionMacro( << "MovingImage, FixedImage and/or Interpolator not set" );
231  }
232 
233  // create a smoothed version of the moving image for the calculation
234  // of gradients. due to the pipeline structure, this will only be
235  // calculated once. InitializeIteration() is called in a single
236  // threaded execution model.
237  m_MovingImageSmoothingFilter->SetInput( this->GetMovingImage() );
238  m_MovingImageSmoothingFilter
239  ->SetSigma( m_GradientSmoothingStandardDeviations );
240  m_MovingImageSmoothingFilter->Update();
241 
242  m_SmoothMovingImageInterpolator
243  ->SetInputImage( m_MovingImageSmoothingFilter->GetOutput() );
244 
245  // setup moving image interpolator
246  m_MovingImageInterpolator->SetInputImage( this->GetMovingImage() );
247 
248  // initialize metric computation variables
249  m_SumOfSquaredDifference = 0.0;
250  m_NumberOfPixelsProcessed = 0L;
251  m_SumOfSquaredChange = 0.0;
252 
253 }
254 
258 template <class TFixedImage, class TMovingImage, class TDeformationField>
260 ::PixelType
262 ::ComputeUpdate(const NeighborhoodType &it, void * gd,
263  const FloatOffsetType& itkNotUsed(offset))
264 {
265  const IndexType index = it.GetIndex();
266 
267  // Get fixed image related information
268  // Note: no need to check the index is within
269  // fixed image buffer. This is done by the external filter.
270  const double fixedValue = (double) this->GetFixedImage()->GetPixel( index );
271 
272  // Get moving image related information
273  PointType mappedPoint;
274  this->GetFixedImage()->TransformIndexToPhysicalPoint(index, mappedPoint);
275  for(unsigned int j = 0; j < ImageDimension; j++ )
276  {
277  mappedPoint[j] += it.GetCenterPixel()[j];
278  }
279  PixelType update;
280  double movingValue;
281  if( m_MovingImageInterpolator->IsInsideBuffer( mappedPoint ) )
282  {
283  movingValue = m_MovingImageInterpolator->Evaluate( mappedPoint );
284  }
285  else
286  {
287  update.Fill(0.0);
288  return update;
289  }
290 
291  // Calculate the gradient using minmod finite differences
292  //
293  //
294  //
295 
296  // first calculate the forward and backward differences on the
297  // smooth image. Do we need to structure the gradient calculation to
298  // take into account the Jacobian of the deformation field? i.e. in
299  // which coordinate frame do we ultimately want the gradient vector?
300 
301  MovingSpacingType mSpacing = this->GetMovingImage()->GetSpacing();
302 
303  if( !this->m_UseImageSpacing )
304  {
305  mSpacing.Fill( 1.0 );
306  }
307 
308  PointType mPoint( mappedPoint );
309  const double centralValue = m_SmoothMovingImageInterpolator->Evaluate( mPoint );
310  double forwardDifferences[ImageDimension];
311  double backwardDifferences[ImageDimension];
312  for (unsigned int j=0; j < ImageDimension; j++)
313  {
314  mPoint[j] += mSpacing[j];
315  if( m_SmoothMovingImageInterpolator->IsInsideBuffer( mPoint ) )
316  {
317  forwardDifferences[j] = m_SmoothMovingImageInterpolator->Evaluate(mPoint)
318  - centralValue;
319  forwardDifferences[j] /= mSpacing[j];
320  }
321  else
322  {
323  forwardDifferences[j] = 0.0;
324  }
325 
326  mPoint[j] -= (2.0 * mSpacing[j]);
327  if( m_SmoothMovingImageInterpolator->IsInsideBuffer( mPoint ) )
328  {
329  backwardDifferences[j] = centralValue
330  - m_SmoothMovingImageInterpolator->Evaluate( mPoint );
331  backwardDifferences[j] /= mSpacing[j];
332  }
333  else
334  {
335  backwardDifferences[j] = 0.0;
336  }
337  // std::cout << "F(" << j << ") : " << forwardDifferences[j] << std::endl;
338  // std::cout << "B(" << j << ") : " << backwardDifferences[j] << std::endl;
339  mPoint[j] += mSpacing[j];
340  }
341 
342  // minmod finite difference
343  //
344  // m(x,y) = sign(x) min(|x|, |y|) if xy > 0
345  // 0 if xy <= 0
346  //
347  // gradient[j] = m(forwardDifferences[j], backwardDifferences[j])
348  //
349  CovariantVectorType gradient;
350  double gradientMagnitude = 0.0;
351  for(unsigned int j = 0; j < ImageDimension; j++ )
352  {
353  if (forwardDifferences[j] * backwardDifferences[j] > 0.0)
354  {
355  const double bvalue = vnl_math_abs(backwardDifferences[j]);
356  double gvalue = vnl_math_abs(forwardDifferences[j]);
357  if (gvalue > bvalue)
358  {
359  gvalue = bvalue;
360  }
361  gradient[j] = gvalue * vnl_math_sgn(forwardDifferences[j]);
362  }
363  else
364  {
365  gradient[j] = 0.0;
366  }
367  gradientMagnitude += vnl_math_sqr( gradient[j] );
368  }
369  gradientMagnitude = vcl_sqrt( gradientMagnitude );
370 
374  const double speedValue = fixedValue - movingValue;
375  // update the metric
376  GlobalDataStruct *globalData = (GlobalDataStruct *)gd;
377  if ( globalData )
378  {
379  globalData->m_SumOfSquaredDifference += vnl_math_sqr( speedValue );
380  globalData->m_NumberOfPixelsProcessed += 1;
381  }
382 
383  if ( vnl_math_abs(speedValue) < m_IntensityDifferenceThreshold
384  || gradientMagnitude < m_GradientMagnitudeThreshold )
385  {
386  update.Fill(0.0);
387  return update;
388  }
389 
390  double L1norm = 0.0;
391  for(unsigned int j = 0; j < ImageDimension; j++ )
392  {
393  update[j] = speedValue * gradient[j] / (gradientMagnitude + m_Alpha);
394  if ( globalData )
395  {
396  globalData->m_SumOfSquaredChange += vnl_math_sqr( update[j] );
397 
398  // build up the L1norm of the update, normalized by the pixel
399  // spacing. we will use this to calculate a timestep which
400  // converts the update (measured in intensity) to a vector
401  // measured in physical units (mm).
402  L1norm += (vnl_math_abs(update[j]) / mSpacing[j]);
403  }
404  }
405 
406  // Store the L1 norm of the update vector if it is the largest
407  // update. This is used in calculating the timestep.
408  if (globalData && (L1norm > globalData->m_MaxL1Norm))
409  {
410  globalData->m_MaxL1Norm = L1norm;
411  }
412  return update;
413 }
414 
418 template <class TFixedImage, class TMovingImage, class TDeformationField>
421 ::ComputeGlobalTimeStep(void *GlobalData) const
422 {
423  TimeStepType dt = 1.0;
424 
425  GlobalDataStruct *d = (GlobalDataStruct *)GlobalData;
426 
427  if (d->m_MaxL1Norm > 0.0)
428  {
429  dt = 1.0 / d->m_MaxL1Norm;
430  // std::cout << "Computed timestep: " << dt << std::endl;
431  }
432  else
433  {
434  // std::cout << "Using default timestep: " << dt << std::endl;
435  }
436 
437  return dt;
438 }
439 
440 
441 /*
442  * Update the metric and release the per-thread-global data.
443  */
444 template <class TFixedImage, class TMovingImage, class TDeformationField>
445 void
447 ::ReleaseGlobalDataPointer( void *gd ) const
448 {
449  GlobalDataStruct * globalData = (GlobalDataStruct *) gd;
450 
451  m_MetricCalculationLock.Lock();
452  m_SumOfSquaredDifference += globalData->m_SumOfSquaredDifference;
453  m_NumberOfPixelsProcessed += globalData->m_NumberOfPixelsProcessed;
454  m_SumOfSquaredChange += globalData->m_SumOfSquaredChange;
455  if ( m_NumberOfPixelsProcessed )
456  {
457  m_Metric = m_SumOfSquaredDifference /
458  static_cast<double>( m_NumberOfPixelsProcessed );
459  m_RMSChange = vcl_sqrt( m_SumOfSquaredChange /
460  static_cast<double>( m_NumberOfPixelsProcessed ) );
461  }
462  m_MetricCalculationLock.Unlock();
463 
464  delete globalData;
465 }
466 
467 } // end namespace itk
468 
469 #endif

Generated at Sat Feb 2 2013 23:51:03 for Orfeo Toolbox with doxygen 1.8.1.1