Orfeo Toolbox  3.16
itkMRFImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkMRFImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2009-10-27 16:06:46 $
7  Version: $Revision: 1.69 $
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 __itkMRFImageFilter_txx
18 #define __itkMRFImageFilter_txx
19 #include "itkMRFImageFilter.h"
20 
21 namespace itk
22 {
23 
24 template<class TInputImage, class TClassifiedImage>
27  m_NumberOfClasses(0),
28  m_MaximumNumberOfIterations(50),
29  m_ErrorCounter(0),
30  m_NeighborhoodSize(27),
31  m_TotalNumberOfValidPixelsInOutputImage(1),
32  m_TotalNumberOfPixelsInInputImage(1),
33  m_ErrorTolerance(0.2),
34  m_SmoothingFactor(1),
35  m_ClassProbability(0),
36  m_NumberOfIterations(0),
37  m_StopCondition(MaximumNumberOfIterations),
38  m_ClassifierPtr(0)
39 {
40 
41  if( (int)InputImageDimension != (int)ClassifiedImageDimension )
42  {
43  OStringStream msg;
44  msg << "Input image dimension: " << InputImageDimension << " != output image dimension: " << ClassifiedImageDimension;
45  throw ExceptionObject(__FILE__, __LINE__,msg.str().c_str(),ITK_LOCATION);
46  }
47  m_InputImageNeighborhoodRadius.Fill(0);
48  m_MRFNeighborhoodWeight.resize(0);
49  m_NeighborInfluence.resize(0);
50  m_DummyVector.resize(0);
51  this->SetMRFNeighborhoodWeight( m_DummyVector );
52  this->SetDefaultMRFNeighborhoodWeight();
53 }
54 
55 template<class TInputImage, class TClassifiedImage>
58 {
59 
60 }
61 
62 template<class TInputImage, class TClassifiedImage>
63 void
65 ::PrintSelf( std::ostream& os, Indent indent ) const
66 {
67  Superclass::PrintSelf(os,indent);
68  unsigned int i;
69 
70  os << indent <<" MRF Image filter object " << std::endl;
71 
72  os << indent <<" Number of classes: " << m_NumberOfClasses << std::endl;
73 
74  os << indent <<" Maximum number of iterations: " <<
75  m_MaximumNumberOfIterations << std::endl;
76 
77  os << indent <<" Error tolerance for convergence: " <<
78  m_ErrorTolerance << std::endl;
79 
80  os << indent <<" Size of the MRF neighborhood radius:" <<
81  m_InputImageNeighborhoodRadius << std::endl;
82 
83  os << indent <<" Number of elements in MRF neighborhood :" <<
84  static_cast<unsigned long>( m_MRFNeighborhoodWeight.size() ) << std::endl;
85 
86  os << indent <<" Neighborhood weight : [";
87  const unsigned int neighborhoodWeightSize =
88  static_cast<unsigned int>( m_MRFNeighborhoodWeight.size() );
89  for (i=0; i+1 < neighborhoodWeightSize; i++)
90  {
91  os << m_MRFNeighborhoodWeight[i] << ", ";
92  }
93  os << m_MRFNeighborhoodWeight[i] << "]" << std::endl;
94 
95  os << indent <<" Smoothing factor for the MRF neighborhood:" <<
96  m_SmoothingFactor << std::endl;
97 
98  os << indent << "StopCondition: "
99  << m_StopCondition << std::endl;
100 
101  os << indent <<" Number of iterations: " <<
102  m_NumberOfIterations << std::endl;
103 
104 }// end PrintSelf
105 
106 /*
107  * GenerateInputRequestedRegion method.
108  */
109 template <class TInputImage, class TClassifiedImage>
110 void
113 {
114 
115  // this filter requires the all of the input images
116  // to be at the size of the output requested region
117  InputImagePointer inputPtr =
118  const_cast< InputImageType * >( this->GetInput() );
119  OutputImagePointer outputPtr = this->GetOutput();
120  if (inputPtr && outputPtr)
121  {
122  inputPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() );
123  }
124 }
125 
126 
130 template <class TInputImage, class TClassifiedImage>
131 void
134  DataObject *output )
135 {
136 
137  // this filter requires the all of the output image to be in
138  // the buffer
139  TClassifiedImage *imgData;
140  imgData = dynamic_cast<TClassifiedImage*>( output );
141  imgData->SetRequestedRegionToLargestPossibleRegion();
142 
143 }
144 
148 template <class TInputImage, class TClassifiedImage>
149 void
152 {
153  typename TInputImage::ConstPointer input = this->GetInput();
154  typename TClassifiedImage::Pointer output = this->GetOutput();
155  output->SetLargestPossibleRegion( input->GetLargestPossibleRegion() );
156 
157 }
158 
159 template<class TInputImage, class TClassifiedImage>
160 void
163 {
164  //First run the Gaussian classifier calculator and
165  //generate the Gaussian model for the different classes
166  //and then generate the initial labelled dataset.
167 
168  InputImageConstPointer inputImage = this->GetInput();
169 
170  //Give the input image and training image set to the
171  // classifier
172  m_ClassifierPtr->SetInputImage( inputImage );
173 
174  //Run the gaussian classifier algorithm
175  m_ClassifierPtr->Update();
176 
177  //Allocate memory for the labelled images
178  this->Allocate();
179 
180  this->ApplyMRFImageFilter();
181  //Set the output labelled and allocate the memory
182  LabelledImagePointer outputPtr = this->GetOutput();
183 
184  //Allocate the output buffer memory
185  outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() );
186  outputPtr->Allocate();
187 
188  //--------------------------------------------------------------------
189  //Copy labelling result to the output buffer
190  //--------------------------------------------------------------------
191  // Set the iterators to the processed image
192  //--------------------------------------------------------------------
194  labelledImageIt( m_ClassifierPtr->GetClassifiedImage(),
195  outputPtr->GetRequestedRegion() );
196 
197  //--------------------------------------------------------------------
198  // Set the iterators to the output image buffer
199  //--------------------------------------------------------------------
201  outImageIt( outputPtr, outputPtr->GetRequestedRegion() );
202 
203  //--------------------------------------------------------------------
204 
205  while ( !outImageIt.IsAtEnd() )
206  {
207  LabelledImagePixelType labelvalue =
208  ( LabelledImagePixelType ) labelledImageIt.Get();
209 
210  outImageIt.Set( labelvalue );
211  ++labelledImageIt;
212  ++outImageIt;
213  }// end while
214 
215 }// end GenerateData
216 
217 template<class TInputImage, class TClassifiedImage>
218 void
220 ::SetClassifier( typename ClassifierType::Pointer ptrToClassifier )
221 {
222  if( ( ptrToClassifier.IsNull() ) || (m_NumberOfClasses <= 0) )
223  {
224  throw ExceptionObject(__FILE__, __LINE__,"NumberOfClasses is <= 0",ITK_LOCATION);
225  }
226  m_ClassifierPtr = ptrToClassifier;
227  m_ClassifierPtr->SetNumberOfClasses( m_NumberOfClasses );
228 }//end SetPtrToClassifier
229 
230 //-------------------------------------------------------
231 //Set the neighborhood radius
232 //-------------------------------------------------------
233 
234 template<class TInputImage, class TClassifiedImage>
235 void
237 ::SetNeighborhoodRadius( const unsigned long radiusValue)
238 {
239  //Set up the neighbor hood
240  NeighborhoodRadiusType radius;
241  for(unsigned int i=0;i < InputImageDimension; ++i)
242  {
243  radius[i] = radiusValue;
244  }
245  this->SetNeighborhoodRadius( radius );
246 
247 }// end SetNeighborhoodRadius
248 
249 template<class TInputImage, class TClassifiedImage>
250 void
252 ::SetNeighborhoodRadius( const unsigned long *radiusArray)
253 {
254  NeighborhoodRadiusType radius;
255  for(unsigned int i=0;i < InputImageDimension; ++i)
256  {
257  radius[i] = radiusArray[i];
258  }
259  //Set up the neighbor hood
260  this->SetNeighborhoodRadius( radius );
261 
262 }// end SetNeighborhoodRadius
263 
264 //Set the neighborhood radius
265 template<class TInputImage, class TClassifiedImage>
266 void
269 {
270  //Set up the neighbor hood
271  for(unsigned int i=0;i < InputImageDimension; ++i)
272  {
273  m_InputImageNeighborhoodRadius[ i ] =
274  radius[ i ];
275  m_LabelledImageNeighborhoodRadius[ i ] =
276  radius[ i ];
277  m_LabelStatusImageNeighborhoodRadius[ i ] =
278  radius[ i ];
279  }
280 
281 }// end SetNeighborhoodRadius
282 //-------------------------------------------------------
283 
284 //-------------------------------------------------------
285 //Set the neighborhood weights
286 //-------------------------------------------------------
287 
288 template<class TInputImage, class TClassifiedImage>
289 void
292 {
293 
294  // Set the beta matrix of a 3x3x3 kernel
295  // The index starts from 0 going along the three dimensions
296  // in the order of [coloumn], [row], [depth].
297 
298  //Allocate memory for the weights of the 3D MRF algorithm
299  // and corresponding memory offsets.
300 
301  //-----------------------------------------------------
302  //Determine the default neighborhood size
303  //-----------------------------------------------------
304  m_NeighborhoodSize = 1;
305  int neighborhoodRadius = 1; //Default assumes a radius of 1
306  for( unsigned int i = 0; i < InputImageDimension; i++ )
307  {
308  m_NeighborhoodSize *= (2*neighborhoodRadius+1);
309  }
310  if( (InputImageDimension == 3) )
311  {
312  //Assumes a default 3x3x3 window size
313  m_MRFNeighborhoodWeight.resize( m_NeighborhoodSize );
314 
315  for( int i = 0; i < 9; i++ )
316  m_MRFNeighborhoodWeight[i] = 1.3 * m_SmoothingFactor;
317 
318  for( int i = 9; i < 18; i++ )
319  m_MRFNeighborhoodWeight[i] = 1.7 * m_SmoothingFactor;
320 
321  for( int i = 18; i < 27; i++ )
322  m_MRFNeighborhoodWeight[i] = 1.3 * m_SmoothingFactor;
323 
324  // Change the center weights
325  m_MRFNeighborhoodWeight[4] = 1.5 * m_SmoothingFactor;
326  m_MRFNeighborhoodWeight[13] = 0.0;
327  m_MRFNeighborhoodWeight[22] = 1.5 * m_SmoothingFactor;
328  }
329  if( (InputImageDimension == 2) )
330  {
331  //Assumes a default 3x3x3 window size
332  m_MRFNeighborhoodWeight.resize( m_NeighborhoodSize );
333 
334  for( int i = 0; i < m_NeighborhoodSize; i++ )
335  m_MRFNeighborhoodWeight[i] = 1.7 * m_SmoothingFactor;
336 
337  // Change the center weights
338  m_MRFNeighborhoodWeight[4] = 0;
339  } else
340  if( (InputImageDimension > 3) )
341  {
342  for( int i = 0; i < m_NeighborhoodSize; i++ )
343  {
344  m_MRFNeighborhoodWeight[i] = 1;
345  }
346  }
347 }// SetMRFNeighborhoodWeight
348 
349 template<class TInputImage, class TClassifiedImage>
350 void
352 ::SetMRFNeighborhoodWeight( std::vector<double> betaMatrix)
353 {
354  if( betaMatrix.size() == 0 )
355  {
356  //Call a the function to set the default neighborhood
357  this->SetDefaultMRFNeighborhoodWeight();
358  }
359  else
360  {
361  m_NeighborhoodSize = 1;
362  for( unsigned int i = 0; i < InputImageDimension; i++ )
363  {
364  m_NeighborhoodSize *= (2*m_InputImageNeighborhoodRadius[i]+1);
365  }
366 
367  if( m_NeighborhoodSize != static_cast<int>(betaMatrix.size()) )
368  {
369  throw ExceptionObject(__FILE__, __LINE__, "NeighborhoodSize != betaMatrix.szie()", ITK_LOCATION);
370  }
371 
372  //Allocate memory for the weights of the 3D MRF algorithm
373  // and corresponding memory offsets.
374  m_MRFNeighborhoodWeight.resize( m_NeighborhoodSize );
375 
376  for( unsigned int i = 0; i < betaMatrix.size(); i++ )
377  {
378  m_MRFNeighborhoodWeight[i] = (betaMatrix[i] * m_SmoothingFactor);
379  }
380  }
381 }// end SetDefaultMRFNeighborhoodWeight
382 
383 
384 //-------------------------------------------------------
385 //-------------------------------------------------------
386 //Allocate algorithm specific resources
387 //-------------------------------------------------------
388 template<class TInputImage, class TClassifiedImage>
389 void
392 {
393  if( m_NumberOfClasses <= 0 )
394  {
395  throw ExceptionObject(__FILE__, __LINE__,"NumberOfClasses <= 0.",ITK_LOCATION);
396  }
397 
398  InputImageSizeType inputImageSize = this->GetInput()->GetBufferedRegion().GetSize();
399 
400  //---------------------------------------------------------------------
401  //Get the number of valid pixels in the output MRF image
402  //---------------------------------------------------------------------
403  int tmp;
404  for( unsigned int i=0; i < InputImageDimension; i++ )
405  {
406  tmp = static_cast<int>(inputImageSize[i]);
407 
408  m_TotalNumberOfPixelsInInputImage *= tmp;
409 
410  m_TotalNumberOfValidPixelsInOutputImage *=
411  ( tmp - 2*m_InputImageNeighborhoodRadius[i] );
412  }
413 
414  //Allocate the label image status
415  LabelStatusIndexType index;
416  index.Fill(0);
417 
418  LabelStatusRegionType region;
419  region.SetSize( inputImageSize );
420  region.SetIndex( index );
421 
422  m_LabelStatusImage = LabelStatusImageType::New();
423  m_LabelStatusImage->SetLargestPossibleRegion( region );
424  m_LabelStatusImage->SetBufferedRegion( region );
425  m_LabelStatusImage->Allocate();
426 
427  LabelStatusImageIterator rIter( m_LabelStatusImage,
428  m_LabelStatusImage->GetBufferedRegion() );
429 
430  //Initialize the label status image to 1
431  while( !rIter.IsAtEnd() )
432  {
433  rIter.Set( 1 );
434  ++rIter;
435  }
436 
437 }// Allocate
438 //-------------------------------------------------------
439 //-------------------------------------------------------
440 //Apply the MRF image filter
441 //-------------------------------------------------------
442 
443 template<class TInputImage, class TClassifiedImage>
444 void
447 {
448 
449  InputImageSizeType inputImageSize =
450  this->GetInput()->GetBufferedRegion().GetSize();
451 
452  int totalNumberOfPixelsInInputImage = 1;
453 
454  for( unsigned int i = 0; i < InputImageDimension; i++ )
455  {
456  totalNumberOfPixelsInInputImage *= static_cast<int>(inputImageSize[ i ]);
457  }
458 
459  int maxNumPixelError = Math::Round<int>( m_ErrorTolerance *
460  m_TotalNumberOfValidPixelsInOutputImage);
461 
462  m_NumberOfIterations = 0;
463  do
464  {
465  itkDebugMacro(<< "Iteration No." << m_NumberOfIterations);
466 
467  MinimizeFunctional();
468  m_NumberOfIterations += 1;
469  m_ErrorCounter = m_TotalNumberOfValidPixelsInOutputImage -
470  totalNumberOfPixelsInInputImage;
471 
472  LabelStatusImageIterator rIter( m_LabelStatusImage,
473  m_LabelStatusImage->GetBufferedRegion() );
474 
475  //Initialize the label status image to 1
476  while( !rIter.IsAtEnd() )
477  {
478  if ( rIter.Get( ) == 1 ) m_ErrorCounter += 1;
479  ++rIter;
480  }
481  }
482  while(( m_NumberOfIterations < m_MaximumNumberOfIterations ) &&
483  ( m_ErrorCounter > maxNumPixelError ) );
484 
485  //Determine stop condition
486  if( m_NumberOfIterations >= m_MaximumNumberOfIterations )
487  {
488  m_StopCondition = MaximumNumberOfIterations;
489  }
490  else if( m_ErrorCounter <= maxNumPixelError )
491  {
492  m_StopCondition = ErrorTolerance;
493  }
494 
495 }// ApplyMRFImageFilter
496 
497 //-------------------------------------------------------
498 //-------------------------------------------------------
499 //Minimize the functional
500 //-------------------------------------------------------
501 
502 template<class TInputImage, class TClassifiedImage>
503 void
506 {
507  //This implementation uses the ICM algorithm
508  ApplyICMLabeller();
509 }
510 
511 //-------------------------------------------------------
512 //-------------------------------------------------------
513 //Core of the ICM algorithm
514 //-------------------------------------------------------
515 template<class TInputImage, class TClassifiedImage>
516 void
519 {
520 
521  //---------------------------------------------------------------------
522  // Loop through the data set and classify the data
523  //---------------------------------------------------------------------
524  m_NeighborInfluence.resize( m_NumberOfClasses );
525 
526  //Varible to store the input pixel vector value
527  //InputImagePixelType inputPixel;
528 
529  m_MahalanobisDistance.resize( m_NumberOfClasses );
530 
531  //---------------------------------------------------------------------
532  // Set up the neighborhood iterators and the valid neighborhoods
533  // for iteration
534  //---------------------------------------------------------------------
535 
536  //Set up the nighborhood iterators
537 
538  //Define the face list for the input/labelled image
539  InputImageFacesCalculator inputImageFacesCalculator;
540  LabelledImageFacesCalculator labelledImageFacesCalculator;
541  LabelStatusImageFacesCalculator labelStatusImageFacesCalculator;
542 
543  InputImageFaceListType inputImageFaceList;
544  LabelledImageFaceListType labelledImageFaceList;
545  LabelStatusImageFaceListType labelStatusImageFaceList;
546 
547  //Compute the faces for the neighborhoods in the input/labelled image
548  InputImageConstPointer inputImage = this->GetInput();
549  inputImageFaceList =
550  inputImageFacesCalculator( inputImage,
551  inputImage->GetBufferedRegion(),
552  m_InputImageNeighborhoodRadius );
553 
554  LabelledImagePointer labelledImage = m_ClassifierPtr->GetClassifiedImage();
555  labelledImageFaceList =
556  labelledImageFacesCalculator( labelledImage,
557  labelledImage->GetBufferedRegion(),
558  m_LabelledImageNeighborhoodRadius );
559 
560  labelStatusImageFaceList =
561  labelStatusImageFacesCalculator( m_LabelStatusImage,
562  m_LabelStatusImage->GetBufferedRegion(),
563  m_LabelStatusImageNeighborhoodRadius );
564  //Set up a face list iterator
565  InputImageFaceListIterator inputImageFaceListIter
566  = inputImageFaceList.begin();
567 
568  LabelledImageFaceListIterator labelledImageFaceListIter
569  = labelledImageFaceList.begin();
570 
571  LabelStatusImageFaceListIterator labelStatusImageFaceListIter
572  = labelStatusImageFaceList.begin();
573 
574  //Walk through the entire data set (not visiting the boundaries )
576  nInputImageNeighborhoodIter( m_InputImageNeighborhoodRadius,
577  inputImage,
578  *inputImageFaceListIter );
579 
581  nLabelledImageNeighborhoodIter( m_LabelledImageNeighborhoodRadius,
582  labelledImage,
583  *labelledImageFaceListIter );
584 
586  nLabelStatusImageNeighborhoodIter( m_LabelStatusImageNeighborhoodRadius,
587  m_LabelStatusImage,
588  *labelStatusImageFaceListIter );
589 
590  //---------------------------------------------------------------------
591  while( !nInputImageNeighborhoodIter.IsAtEnd() )
592  {
593 
594  //Process each neighborhood
595  this->DoNeighborhoodOperation( nInputImageNeighborhoodIter,
596  nLabelledImageNeighborhoodIter,
597  nLabelStatusImageNeighborhoodIter );
598 
599 
600  ++nInputImageNeighborhoodIter;
601  ++nLabelledImageNeighborhoodIter;
602  ++nLabelStatusImageNeighborhoodIter;
603 
604  }
605 }//ApplyICMlabeller
606 
607 //-------------------------------------------------------
608 //-------------------------------------------------------
609 //Function that performs the MRF operation with each neighborhood
610 //-------------------------------------------------------
611 
612 template<class TInputImage, class TClassifiedImage>
613 void
616  LabelledImageNeighborhoodIterator &labelledIter,
617  LabelStatusImageNeighborhoodIterator &labelStatusIter )
618 {
619 
620  unsigned int index;
621 
622  //Read the pixel of interest and get its corresponding membership value
623  InputImagePixelType *inputPixelVec = imageIter.GetCenterValue();
624 
625  const std::vector<double> & pixelMembershipValue =
626  m_ClassifierPtr->GetPixelMembershipValue( *inputPixelVec );
627 
628 
629  //Reinitialize the neighborhood influence at the beginning of the
630  //neighborhood operation
631  for( index = 0; index < m_NeighborInfluence.size(); index++ )
632  {
633  m_NeighborInfluence[index]= 0;
634  }
635 
636  LabelledImagePixelType labelledPixel;
637 
638  //Begin neighborhood processing. Calculate the prior for each label
639  for( int i = 0; i < m_NeighborhoodSize; ++i )
640  {
641 
642  labelledPixel = labelledIter.GetPixel( i );
643  index = (unsigned int) labelledPixel;
644  m_NeighborInfluence[ index ] += m_MRFNeighborhoodWeight[ i ];
645 
646  }//End neighborhood processing
647 
648  //Add the prior probability to the pixel probability
649  for( index = 0; index < m_NumberOfClasses; index++ )
650  {
651  m_MahalanobisDistance[index] = m_NeighborInfluence[index] -
652  pixelMembershipValue[index];
653  }
654 
655  //Determine the maximum possible distance
656  double maximumDistance = -1e+20;
657  int pixLabel = -1;
658  double tmpPixDistance;
659  for( index = 0; index < m_NumberOfClasses; index++ )
660  {
661  tmpPixDistance = m_MahalanobisDistance[index];
662  if ( tmpPixDistance > maximumDistance )
663  {
664  maximumDistance = tmpPixDistance;
665  pixLabel = index;
666  }// if
667  }// for
668 
669  //Read the current pixel label
670  LabelledImagePixelType *previousLabel = labelledIter.GetCenterValue();
671 
672  //Check if the labelled pixel value in the previous iteration has changed
673  //If the value has changed then update the m_LabelStatus set;
674 
675  if( pixLabel != (int) ( *previousLabel ) )
676  {
677  labelledIter.SetCenterPixel( pixLabel );
678  for( int i = 0; i < m_NeighborhoodSize; ++i )
679  {
680  labelStatusIter.SetPixel( i, 1 );
681  } //End neighborhood processing
682  } //end if
683  else
684  {
685  labelStatusIter.SetCenterPixel( 0 );
686  }
687 
688 }// end DoNeighborhoodOperation
689 
690 
691 } // namespace itk
692 
693 #endif

Generated at Sat May 11 2013 23:56:07 for Orfeo Toolbox with doxygen 1.8.3.1