Orfeo Toolbox  3.16
itkMIRegistrationFunction.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3 Program: Insight Segmentation & Registration Toolkit
4 Module: $RCSfile: itkMIRegistrationFunction.txx,v $
5 Language: C++
6 Date: $Date: 2009-01-26 21:45:50 $
7 Version: $Revision: 1.22 $
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 __itkMIRegistrationFunction_txx
18 #define __itkMIRegistrationFunction_txx
19 
22 #include "itkExceptionObject.h"
23 #include "vnl/vnl_math.h"
25 
26 #include <vnl/vnl_matrix.h>
27 
28 namespace itk {
29 
33 template <class TFixedImage, class TMovingImage, class TDeformationField>
36 {
37 
38  RadiusType r;
39  unsigned int j;
40  m_NumberOfSamples=1;
41  m_NumberOfBins=4;
42 
43  for( j = 0; j < ImageDimension; j++ )
44  {
45  r[j] = 2;
46  m_NumberOfSamples *= (r[j]*2+1);
47  }
48  this->SetRadius(r);
49 
50  m_MetricTotal=0.0;
51 
52  m_TimeStep = 1.0;
53  m_Minnorm=1.0;
54  m_DenominatorThreshold = 1e-9;
55  m_IntensityDifferenceThreshold = 0.001;
56  this->SetMovingImage(NULL);
57  this->SetFixedImage(NULL);
58  m_FixedImageGradientCalculator = GradientCalculatorType::New();
59 
60  m_DoInverse = true;
61  m_DoInverse = false;
62 
63  if (m_DoInverse)
64  {
65  m_MovingImageGradientCalculator = GradientCalculatorType::New();
66  }
67  typename DefaultInterpolatorType::Pointer interp =
68  DefaultInterpolatorType::New();
69 
70  m_MovingImageInterpolator = static_cast<InterpolatorType*>(
71  interp.GetPointer() );
72 }
73 
74 
75 /*
76  * Standard "PrintSelf" method.
77  */
78 template <class TFixedImage, class TMovingImage, class TDeformationField>
79 void
81 ::PrintSelf(std::ostream& os, Indent indent) const
82 {
83 
84  Superclass::PrintSelf(os, indent);
85 /*
86  os << indent << "MovingImageIterpolator: ";
87  os << m_MovingImageInterpolator.GetPointer() << std::endl;
88  os << indent << "FixedImageGradientCalculator: ";
89  os << m_FixedImageGradientCalculator.GetPointer() << std::endl;
90  os << indent << "DenominatorThreshold: ";
91  os << m_DenominatorThreshold << std::endl;
92  os << indent << "IntensityDifferenceThreshold: ";
93  os << m_IntensityDifferenceThreshold << std::endl;
94 */
95 }
96 
97 
98 /*
99  * Set the function state values before each iteration
100  */
101 template <class TFixedImage, class TMovingImage, class TDeformationField>
102 void
105 {
106  if( !this->m_MovingImage || !this->m_FixedImage || !m_MovingImageInterpolator )
107  {
108  itkExceptionMacro( << "MovingImage, FixedImage and/or Interpolator not set" );
109  }
110 
111  // setup gradient calculator
112  m_FixedImageGradientCalculator->SetInputImage( this->m_FixedImage );
113 
114  if (m_DoInverse)
115  {
116  // setup gradient calculator
117  m_MovingImageGradientCalculator->SetInputImage( this->m_MovingImage );
118  }
119  // setup moving image interpolator
120  m_MovingImageInterpolator->SetInputImage( this->m_MovingImage );
121 
122  m_MetricTotal=0.0;
123 
124 }
125 
129 template <class TFixedImage, class TMovingImage, class TDeformationField>
131 ::PixelType
133 ::ComputeUpdate(const NeighborhoodType &it, void * itkNotUsed(globalData),
134  const FloatOffsetType& itkNotUsed(offset))
135 {
136  // we compute the derivative of MI w.r.t. the infinitesimal
137  // displacement, following viola and wells.
138 
139  // 1) collect samples from M (Moving) and F (Fixed)
140  // 2) compute minimum and maximum values of M and F
141  // 3) discretized M and F into N bins
142  // 4) estimate joint probability P(M,F) and P(F)
143  // 5) derivatives is given as :
144  //
145  // $$ \nabla MI = \frac{1}{N} \sum_i \sum_j (F_i-F_j)
146  // ( W(F_i,F_j) \frac{1}{\sigma_v} -
147  // W((F_i,M_i),(F_j,M_j)) \frac{1}{\sigma_vv} ) \nabla F
148  //
149  // NOTE : must estimate sigma for each pdf
150 
151  typedef vnl_matrix<double> matrixType;
152  typedef std::vector<double> sampleContainerType;
153  typedef std::vector<CovariantVectorType> gradContainerType;
154  typedef std::vector<double> gradMagContainerType;
155  typedef std::vector<unsigned int> inImageIndexContainerType;
156 
157 
158  PixelType update;
159  PixelType derivative;
160  unsigned int j;
161 
162  const IndexType oindex = it.GetIndex();
163 
164  unsigned int indct;
165 
166  for (indct=0;indct<ImageDimension;indct++)
167  {
168  update[indct]=0.0;
169  derivative[indct]=0.0;
170  }
171 
172 
173  float thresh2=1.0/255.;// FIX ME : FOR PET LUNG ONLY !!
174  float thresh1=1.0/255.;
175  if ( this->m_MovingImage->GetPixel(oindex) <= thresh1 &&
176  this->m_FixedImage->GetPixel(oindex) <= thresh2 ) return update;
177 
178  typename FixedImageType::SizeType hradius=this->GetRadius();
179 
180  FixedImageType* img =const_cast<FixedImageType *>(this->m_FixedImage.GetPointer());
181  typename FixedImageType::SizeType imagesize=img->GetLargestPossibleRegion().GetSize();
182 
183 
184  bool inimage;
185 
186 // now collect the samples
187  sampleContainerType fixedSamplesA;
188  sampleContainerType movingSamplesA;
189  sampleContainerType fixedSamplesB;
190  sampleContainerType movingSamplesB;
191  inImageIndexContainerType inImageIndicesA;
192  gradContainerType fixedGradientsA;
193  gradMagContainerType fixedGradMagsA;
194  inImageIndexContainerType inImageIndicesB;
195  gradContainerType fixedGradientsB;
196  gradMagContainerType fixedGradMagsB;
197 
198  unsigned int samplestep=2; //m_Radius[0];
199 
200  double minf=1.e9,minm=1.e9,maxf=0.0,maxm=0.0;
201  double movingMean=0.0;
202  double fixedMean=0.0;
203  double fixedValue=0,movingValue=0;
204 
205  unsigned int sampct=0;
206 
207 
209  asamIt( hradius,
210  this->GetDeformationField(),
211  this->GetDeformationField()->GetRequestedRegion());
212  asamIt.SetLocation(oindex);
213  unsigned int hoodlen=asamIt.Size();
214 
215 // first get the density-related sample
216  for(indct=0; indct<hoodlen; indct=indct+samplestep)
217  {
218  IndexType index=asamIt.GetIndex(indct);
219  inimage=true;
220  for (unsigned int dd=0; dd<ImageDimension; dd++)
221  {
222  if ( index[dd] < 0 || index[dd] > static_cast<typename IndexType::IndexValueType>(imagesize[dd]-1) ) inimage=false;
223  }
224  if (inimage)
225  {
226 
227  fixedValue=0.;
228  movingValue=0.0;
229  CovariantVectorType fixedGradient;
230 
231  // Get fixed image related information
232  fixedValue = (double) this->m_FixedImage->GetPixel( index );
233 
234 
235  fixedGradient = m_FixedImageGradientCalculator->EvaluateAtIndex( index );
236 
237  // Get moving image related information
238  typedef typename DeformationFieldType::PixelType DeformationPixelType;
239  const DeformationPixelType itvec = this->GetDeformationField()->GetPixel(index);
240 
241  PointType mappedPoint;
242  this->GetFixedImage()->TransformIndexToPhysicalPoint(index, mappedPoint);
243  for( j = 0; j < ImageDimension; j++ )
244  {
245  mappedPoint[j] += itvec[j];
246  }
247  if( m_MovingImageInterpolator->IsInsideBuffer( mappedPoint ) )
248  {
249  movingValue = m_MovingImageInterpolator->Evaluate( mappedPoint );
250  }
251  else
252  {
253  movingValue = 0.0;
254  }
255 
256  if (fixedValue > maxf) maxf=fixedValue;
257  else if (fixedValue < minf) minf=fixedValue;
258  if (movingValue > maxm) maxm=movingValue;
259  else if (movingValue < minm) minm=movingValue;
260 
261  fixedMean += fixedValue;
262  movingMean += movingValue;
263 
264  fixedSamplesA.insert(fixedSamplesA.begin(),(double)fixedValue);
265  fixedGradientsA.insert(fixedGradientsA.begin(),fixedGradient);
266  movingSamplesA.insert(movingSamplesA.begin(),(double)movingValue);
267 
268 
269 // fixedSamplesB.insert(fixedSamplesB.begin(),(double)fixedValue);
270 // fixedGradientsB.insert(fixedGradientsB.begin(),fixedGradient);
271 // movingSamplesB.insert(movingSamplesB.begin(),(double)movingValue);
272 
273  sampct++;
274  }
275 
276  }
277 
278 
279 // BEGIN RANDOM A SAMPLES
280  bool getrandasamples=true;
281  if (getrandasamples)
282  {
283 
284  typename FixedImageType::RegionType region=img->GetLargestPossibleRegion();
285 
286  ImageRandomIteratorWithIndex<FixedImageType> randasamit(img,region);
287 // unsigned int numberOfSamples=20;
288  unsigned int numberOfSamples=10;
289  randasamit.SetNumberOfSamples( numberOfSamples );
290 // numberOfSamples=100;
291 
292  indct=0;
293 
294  randasamit.ReinitializeSeed(0);
295  randasamit.GoToBegin();
296  while( !randasamit.IsAtEnd() && indct < numberOfSamples )
297  {
298  IndexType index=randasamit.GetIndex();
299  inimage=true;
300 
301  float d=0.0;
302  for (unsigned int dd=0; dd<ImageDimension; dd++)
303  {
304  if ( index[dd] < 0 || index[dd] > static_cast<typename IndexType::IndexValueType>(imagesize[dd]-1) ) inimage=false;
305  d += (index[dd]-oindex[dd])*(index[dd]-oindex[dd]);
306  }
307 
308  if (inimage )
309  {
310  fixedValue=0.;
311  movingValue=0.0;
312  CovariantVectorType fixedGradient;
313  double fgm=0;
314  // Get fixed image related information
315  fixedValue = (double) this->m_FixedImage->GetPixel( index );
316  fixedGradient = m_FixedImageGradientCalculator->EvaluateAtIndex( index );
317 
318  for( j = 0; j < ImageDimension; j++ )
319  {
320  fgm += fixedGradient[j] *fixedGradient[j];
321  }
322  // Get moving image related information
323  typedef typename DeformationFieldType::PixelType DeformationPixelType;
324  const DeformationPixelType itvec=this->GetDeformationField()->GetPixel(index);
325  PointType mappedPoint;
326  this->GetFixedImage()->TransformIndexToPhysicalPoint(index, mappedPoint);
327  for( j = 0; j < ImageDimension; j++ )
328  {
329  mappedPoint[j] += itvec[j];
330  }
331  if( m_MovingImageInterpolator->IsInsideBuffer( mappedPoint ) )
332  {
333  movingValue = m_MovingImageInterpolator->Evaluate( mappedPoint );
334  }
335  else
336  {
337  movingValue = 0.0;
338  }
339 
340  // if ( (fixedValue > 0 || movingValue > 0 || fgm > 0) || !filtersamples)
341 
342  if ( fixedValue > 0 || movingValue > 0 || fgm > 0 )
343  {
344  fixedMean += fixedValue;
345  movingMean += movingValue;
346 
347  fixedSamplesA.insert(fixedSamplesA.begin(),(double)fixedValue);
348  fixedGradientsA.insert(fixedGradientsA.begin(),fixedGradient);
349  movingSamplesA.insert(movingSamplesA.begin(),(double)movingValue);
350  sampct++;
351  indct++;
352  }
353 
354  }
355  ++randasamit;
356  }
357 
358  }
359  // END RANDOM A SAMPLES
360 
361  const DeformationFieldType * const field = this->GetDeformationField();
362 
363  for (j=0;j<ImageDimension; j++)
364  {
365  hradius[j]=0;
366  }
368  hoodIt( hradius, field, field->GetRequestedRegion());
369  hoodIt.SetLocation(oindex);
370 
371  // then get the entropy ( and MI derivative ) related sample
372  for(indct=0; indct<hoodIt.Size(); indct=indct+1)
373  {
374  const IndexType index=hoodIt.GetIndex(indct);
375  inimage=true;
376  float d=0.0;
377  for (unsigned int dd=0; dd<ImageDimension; dd++)
378  {
379  if ( index[dd] < 0 || index[dd] > static_cast<typename IndexType::IndexValueType>(imagesize[dd]-1) ) inimage=false;
380  d += (index[dd]-oindex[dd])*(index[dd]-oindex[dd]);
381  }
382  if (inimage && vcl_sqrt(d) <= 1.0)
383  {
384  fixedValue=0.;
385  movingValue=0.0;
386  CovariantVectorType fixedGradient;
387 
388  // Get fixed image related information
389  fixedValue = (double) this->m_FixedImage->GetPixel( index );
390  fixedGradient = m_FixedImageGradientCalculator->EvaluateAtIndex( index );
391 
392  // Get moving image related information
393  // Get moving image related information
394  const typename DeformationFieldType::PixelType hooditvec=this->m_DeformationField->GetPixel(index);
395  PointType mappedPoint;
396  this->GetFixedImage()->TransformIndexToPhysicalPoint(index, mappedPoint);
397  for(j = 0; j < ImageDimension; j++ )
398  {
399  mappedPoint[j] += hooditvec[j];
400  }
401  if( m_MovingImageInterpolator->IsInsideBuffer( mappedPoint ) )
402  {
403  movingValue = m_MovingImageInterpolator->Evaluate( mappedPoint );
404  }
405  else
406  {
407  movingValue = 0.0;
408  }
409 
410  fixedSamplesB.insert(fixedSamplesB.begin(),(double)fixedValue);
411  fixedGradientsB.insert(fixedGradientsB.begin(),fixedGradient);
412  movingSamplesB.insert(movingSamplesB.begin(),(double)movingValue);
413  }
414  }
415 
416  double fsigma=0.0;
417  double msigma=0.0;
418  double jointsigma=0.0;
419 
420  const double numsamplesB= (double) fixedSamplesB.size();
421  const double numsamplesA= (double) fixedSamplesA.size();
422  double nsamp=numsamplesB;
423 // if (maxf == minf && maxm == minm) return update;
424 // else std::cout << " b samps " << fixedSamplesB.size()
425 // << " a samps " << fixedSamplesA.size() <<
426 // oindex << hoodIt.Size() << it.Size() << std::endl;
427 
428  fixedMean /= (double)sampct;
429  movingMean /= (double)sampct;
430 
431  bool mattes=false;
432 
433  for(indct=0; indct<(unsigned int)numsamplesA; indct++)
434  {
435 // Get fixed image related information
436  fixedValue=fixedSamplesA[indct];
437  movingValue=movingSamplesA[indct];
438 
439  fsigma += (fixedValue-fixedMean)*(fixedValue-fixedMean);
440  msigma += (movingValue-movingMean)*(movingValue-movingMean);
441  jointsigma += fsigma+msigma;
442 
443  if (mattes)
444  {
445  fixedSamplesA[indct]=fixedSamplesA[indct]-minf;
446  movingSamplesA[indct]=movingSamplesA[indct]-minm;
447  if (indct < numsamplesB)
448  {
449  fixedSamplesB[indct]=fixedSamplesB[indct]-minf;
450  movingSamplesB[indct]=movingSamplesB[indct]-minm;
451  }
452  }
453  }
454 
455 
456  fsigma=vcl_sqrt(fsigma/numsamplesA);
457  float sigmaw=0.8;
458  double m_FixedImageStandardDeviation=fsigma*sigmaw;
459  msigma=vcl_sqrt(msigma/numsamplesA);
460  double m_MovingImageStandardDeviation=msigma*sigmaw;
461  jointsigma=vcl_sqrt(jointsigma/numsamplesA);
462 
463  if (fsigma < 1.e-7 || msigma < 1.e-7 ) return update;
464 
465 
466  double m_MinProbability = 0.0001;
467  double dLogSumFixed=0.,dLogSumMoving=0.,dLogSumJoint=0.0;
468  unsigned int bsamples;
469  unsigned int asamples;
470 
471  // the B samples estimate the entropy
472  for(bsamples=0; bsamples<(unsigned int)numsamplesB; bsamples++)
473  {
474  double dDenominatorMoving = m_MinProbability;
475  double dDenominatorJoint = m_MinProbability;
476  double dDenominatorFixed = m_MinProbability;
477  double dSumFixed = m_MinProbability;
478 
479  // this loop estimates the density
480  for(asamples=0; asamples<(unsigned int)numsamplesA; asamples++)
481  {
482  double valueFixed = ( fixedSamplesB[bsamples] - fixedSamplesA[asamples] )
483  / m_FixedImageStandardDeviation;
484  valueFixed = vcl_exp(-0.5*valueFixed*valueFixed);
485 
486  double valueMoving = ( movingSamplesB[bsamples] - movingSamplesA[asamples] )
487  / m_MovingImageStandardDeviation;
488  valueMoving = vcl_exp(-0.5*valueMoving*valueMoving);
489 
490  dDenominatorMoving += valueMoving;
491  dDenominatorFixed += valueFixed;
492  dSumFixed += valueFixed;
493 
494 // everything above here can be pre-computed only once and stored,
495 // assuming const v.f. in small n-hood
496  dDenominatorJoint += valueMoving * valueFixed;
497  } // end of sample A loop
498 
499  dLogSumFixed -= vcl_log(dSumFixed );
500  dLogSumMoving -= vcl_log(dDenominatorMoving );
501  dLogSumJoint -= vcl_log(dDenominatorJoint );
502 
503  // this loop estimates the density
504  for(asamples=0; asamples<(unsigned int)numsamplesA; asamples++)
505  {
506  double valueFixed = ( fixedSamplesB[bsamples] - fixedSamplesA[asamples] )
507  / m_FixedImageStandardDeviation;
508  valueFixed = vcl_exp(-0.5*valueFixed*valueFixed);
509 
510  double valueMoving = ( movingSamplesB[bsamples] - movingSamplesA[asamples] )
511  / m_MovingImageStandardDeviation;
512  valueMoving = vcl_exp(-0.5*valueMoving*valueMoving);
513  const double weightFixed = valueFixed / dDenominatorFixed;
514 // dDenominatorJoint and weightJoint are what need to be computed each time
515  const double weightJoint = valueMoving * valueFixed / dDenominatorJoint;
516 
517 // begin where we may switch fixed and moving
518  double weight = ( weightFixed - weightJoint );
519  weight *= ( fixedSamplesB[bsamples] - fixedSamplesA[asamples] );
520 // end where we may switch fixed and moving
521 
522 // this can also be stored away
523  for (unsigned int i=0; i<ImageDimension;i++)
524  {
525  derivative[i] += ( fixedGradientsB[bsamples][i] - fixedGradientsA[asamples][i] ) * weight;
526  }
527  } // end of sample A loop
528  } // end of sample B loop
529 
530  const double threshold = -0.1 * nsamp * vcl_log(m_MinProbability );
531  if( dLogSumMoving > threshold || dLogSumFixed > threshold ||
532  dLogSumJoint > threshold )
533  {
534  // at least half the samples in B did not occur within
535  // the Parzen window width of samples in A
536  return update;
537  }
538 
539  double value=0.0;
540  value = dLogSumFixed + dLogSumMoving - dLogSumJoint;
541  value /= nsamp;
542  value += vcl_log(nsamp );
543 
544  m_MetricTotal += value;
545  this->m_Energy += value;
546 
547  derivative /= nsamp;
548  derivative /= vnl_math_sqr( m_FixedImageStandardDeviation );
549 
550  double updatenorm=0.0;
551  for (unsigned int tt=0; tt<ImageDimension; tt++)
552  {
553  updatenorm += derivative[tt]*derivative[tt];
554  }
555  updatenorm=vcl_sqrt(updatenorm);
556 
557  if (updatenorm > 1.e-20 && this->GetNormalizeGradient())
558  {
559  derivative=derivative/updatenorm;
560  }
561 
562  return derivative*this->GetGradientStep();
563 }
564 
565 } // end namespace itk
566 
567 #endif

Generated at Sat May 18 2013 23:53:48 for Orfeo Toolbox with doxygen 1.8.3.1