Orfeo Toolbox  3.16
itkImagePCAShapeModelEstimator.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkImagePCAShapeModelEstimator.txx,v $
5  Language: C++
6  Date: $Date: 2009-01-24 20:02:56 $
7  Version: $Revision: 1.11 $
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 __itkImagePCAShapeModelEstimator_txx
18 #define __itkImagePCAShapeModelEstimator_txx
19 
21 
22 namespace itk
23 {
24 
25 template<class TInputImage, class TOutputImage>
27 ::ImagePCAShapeModelEstimator(void):m_NumberOfPixels(0),m_NumberOfTrainingImages(0)
28 {
29  m_EigenVectors.set_size(0,0);
30  m_EigenValues.set_size(0);
31 
32  m_NumberOfPrincipalComponentsRequired = 0;
33  this->SetNumberOfPrincipalComponentsRequired( 1 );
34 
35 }
36 
37 template<class TInputImage, class TOutputImage>
40 {
41 
42 }
43 
47 template <class TInputImage, class TOutputImage>
48 void
50 ::PrintSelf( std::ostream& os, Indent indent ) const
51 {
52 
53  os << indent << " " << std::endl;
54  os << indent << "Shape Models " << std::endl;
55  os << indent << "Results printed in the superclass " << std::endl;
56  os << indent << " " << std::endl;
57 
58  Superclass::PrintSelf(os,indent);
59 
60  itkDebugMacro(<<" ");
61  itkDebugMacro(<<"Results of the shape model algorithms");
62  itkDebugMacro(<<"====================================");
63 
64  itkDebugMacro(<< "The eigen values new method are: ");
65 
66  itkDebugMacro(<< m_EigenValues);
67  itkDebugMacro(<< m_EigenVectorNormalizedEnergy);
68 
69  itkDebugMacro(<< " ");
70  itkDebugMacro(<< "================== ");
71 
72  itkDebugMacro(<< "The eigen vectors new method are: ");
73 
74 
75  for(unsigned int i = 0; i < m_EigenValues.size(); i++)
76  {
77  itkDebugMacro(<< m_EigenVectors.get_row(i));
78  }
79 
80  itkDebugMacro(<< " ");
81  itkDebugMacro(<< "+++++++++++++++++++++++++");
82 
83  // Print out ivars
84  os << indent << "NumberOfPrincipalComponentsRequired: ";
85  os << m_NumberOfPrincipalComponentsRequired << std::endl;
86  os << indent << "NumberOfTrainingImages: ";
87  os << m_NumberOfTrainingImages << std::endl;
88 
89 
90 }// end PrintSelf
91 
95 template<class TInputImage, class TOutputImage>
96 void
99 {
100 
101  // this filter requires the all of the output images to be in
102  // the buffer
103  for ( unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx)
104  {
105  if ( this->GetOutput(idx) )
106  {
107  this->GetOutput(idx)->SetRequestedRegionToLargestPossibleRegion();
108  }
109  }
110 
111 }
112 
117 template<class TInputImage, class TOutputImage>
118 void
121 {
122  Superclass::GenerateInputRequestedRegion();
123 
124  if ( this->GetInput(0) )
125  {
126 
127  // Set the requested region of the first input to largest possible region
128  InputImagePointer input = const_cast< TInputImage *>( this->GetInput(0) );
129  input->SetRequestedRegionToLargestPossibleRegion();
130 
131  // Set the requested region of the remaining input to the largest possible
132  // region of the first input
133  unsigned int idx;
134  for (idx = 1; idx < this->GetNumberOfInputs(); ++idx)
135  {
136  if ( this->GetInput(idx) )
137  {
138  typename TInputImage::RegionType requestedRegion =
139  this->GetInput(0)->GetLargestPossibleRegion();
140 
141  typename TInputImage::RegionType largestRegion =
142  this->GetInput(idx)->GetLargestPossibleRegion();
143 
144  if( !largestRegion.IsInside( requestedRegion ) )
145  {
146  itkExceptionMacro("LargestPossibleRegion of input " << idx <<
147  " is not a superset of the LargestPossibleRegion of input 0" );
148  }
149 
150  InputImagePointer ptr = const_cast<TInputImage *>( this->GetInput(idx) );
151  ptr->SetRequestedRegion( requestedRegion );
152 
153  } // if ( this->GetIntput(idx))
154  } // for idx
155  } // if( this->GetInput(0) )
156 
157 }
158 
162 template<class TInputImage, class TOutputImage>
163 void
166 {
167  this->EstimateShapeModels();
168 
169  // Allocate memory for each output.
170  unsigned int numberOfOutputs =
171  static_cast<unsigned int>( this->GetNumberOfOutputs() );
172 
173  InputImagePointer input = const_cast<TInputImage *>( this->GetInput(0) );
174  unsigned int j;
175  for( j = 0; j < numberOfOutputs; j++ )
176  {
177 
178  OutputImagePointer output = this->GetOutput( j );
179  output->SetBufferedRegion( output->GetRequestedRegion() );
180  output->Allocate();
181 
182  }
183 
184  // Fill the output images.
185  VectorOfDoubleType m_OneEigenVector;
186  typedef ImageRegionIterator<OutputImageType> OutputIterator;
187 
188  //Fill the mean image first
189 
190  typename OutputImageType::RegionType region = this->GetOutput( 0 )->GetRequestedRegion();
191  OutputIterator outIter( this->GetOutput( 0 ), region );
192 
193  unsigned int i = 0;
194  outIter.GoToBegin();
195  while( !outIter.IsAtEnd() )
196  {
197  outIter.Set( static_cast<typename OutputImageType::PixelType>(m_Means[i]));
198  ++outIter;
199  ++i;
200  }
201 
202  //Now fill the principal component outputs
203  unsigned int kthLargestPrincipalComp = m_NumberOfTrainingImages;
204  unsigned int numberOfValidOutputs =
205  vnl_math_min( numberOfOutputs, m_NumberOfTrainingImages + 1 );
206 
207  for( j = 1; j < numberOfValidOutputs; j++ )
208  {
209 
210  //Extract one column vector at a time
211  m_OneEigenVector = m_EigenVectors.get_column(kthLargestPrincipalComp-1);
212 
213  region = this->GetOutput( j )->GetRequestedRegion();
214  OutputIterator outIterJ( this->GetOutput( j ), region );
215 
216  unsigned int idx = 0;
217  outIterJ.GoToBegin();
218  while( !outIterJ.IsAtEnd() )
219  {
220  outIterJ.Set( static_cast<typename OutputImageType::PixelType>(
221  m_OneEigenVector[ idx ] ) );
222  ++outIterJ;
223  ++idx;
224  }
225 
226  //Decrement to get the next principal component
227  --kthLargestPrincipalComp;
228  }
229 
230  // Fill extraneous outputs with zero
231  for(; j < numberOfOutputs; j++ )
232  {
233  region = this->GetOutput( j )->GetRequestedRegion();
234  OutputIterator outIterJ( this->GetOutput( j ), region );
235 
236  outIterJ.GoToBegin();
237  while( !outIterJ.IsAtEnd() )
238  {
239  outIterJ.Set( 0 );
240  ++outIterJ;
241  }
242 
243  }
244 
245 }// end Generate data
246 
247 
251 template<class TInputImage, class TOutputImage>
252 void
255 {
256  if ( m_NumberOfPrincipalComponentsRequired != n )
257  {
258  m_NumberOfPrincipalComponentsRequired = n;
259 
260  this->Modified();
261 
262  // Modify the required number of outputs ( 1 extra for the mean image )
263  this->SetNumberOfRequiredOutputs( m_NumberOfPrincipalComponentsRequired + 1 );
264 
265  unsigned int numberOfOutputs = static_cast<unsigned int>( this->GetNumberOfOutputs() );
266  unsigned int idx;
267 
268  if( numberOfOutputs < m_NumberOfPrincipalComponentsRequired + 1 )
269  {
270  // Make and add extra outputs
271  for( idx = numberOfOutputs; idx <= m_NumberOfPrincipalComponentsRequired; idx++ )
272  {
273  typename DataObject::Pointer output = this->MakeOutput( idx );
274  this->SetNthOutput( idx, output.GetPointer() );
275  }
276  }
277  else if ( numberOfOutputs > m_NumberOfPrincipalComponentsRequired + 1 )
278  {
279  // Remove the extra outputs
280  for ( idx = numberOfOutputs - 1; idx >= m_NumberOfPrincipalComponentsRequired + 1; idx-- )
281  {
282  typename DataObject::Pointer output = this->GetOutputs()[idx];
283  this->RemoveOutput( output );
284  }
285  }
286 
287  }
288 }
289 
293 template<class TInputImage, class TOutputImage>
294 void
297 {
298  if ( m_NumberOfTrainingImages != n )
299  {
300  m_NumberOfTrainingImages = n;
301 
302  this->Modified();
303 
304  // Modify the required number of inputs
305  this->SetNumberOfRequiredInputs( m_NumberOfTrainingImages );
306  }
307 }
308 
314 template<class TInputImage, class TOutputImage>
315 void
318 {
319 
320  this->CalculateInnerProduct();
321 
322  this->EstimatePCAShapeModelParameters();
323 
324 }// end EstimateShapeModels
325 
330 template<class TInputImage, class TOutputImage>
331 void
334 {
335  // Get the pointers to the input images and initialize the iterators
336  // We use dynamic_cast since inputs are stored as DataObjects. The
337  // ImageToImageFilter::GetInput(int) always returns a pointer to a
338  // TInputImage1 so it cannot be used for the second input.
339 
340  InputImagePointerArray inputImagePointerArray( m_NumberOfTrainingImages );
341  m_InputImageIteratorArray.resize( m_NumberOfTrainingImages );
342 
343 
344  for( unsigned int i=0; i< m_NumberOfTrainingImages; i++ )
345  {
346 
347  InputImageConstPointer inputImagePtr
348  = dynamic_cast<const TInputImage*>(ProcessObject::GetInput(i));
349 
350  inputImagePointerArray[i] = inputImagePtr;
351 
352  InputImageConstIterator inputImageIt( inputImagePtr, inputImagePtr->GetBufferedRegion() );
353 
354  m_InputImageIteratorArray[i] = inputImageIt;
355 
356  m_InputImageIteratorArray[i].GoToBegin();
357 
358  }
359 
360  //-------------------------------------------------------------------
361  // Set up the matrix to hold the inner product and the means from the
362  // training data
363  //-------------------------------------------------------------------
364  m_InputImageSize = (inputImagePointerArray[0])->GetBufferedRegion().GetSize();
365 
366  m_NumberOfPixels = 1;
367  for( unsigned int i = 0; i < InputImageDimension; i++ )
368  {
369  m_NumberOfPixels *= m_InputImageSize[i];
370  }
371 
372  //-------------------------------------------------------------------------
373  //Calculate the Means
374  //-------------------------------------------------------------------------
375  m_Means.set_size(m_NumberOfPixels);
376  m_Means.fill(0);
377 
378  InputImageConstIterator tempImageItA;
379 
380  for(unsigned int img_number = 0; img_number < m_NumberOfTrainingImages; img_number++)
381  {
382  tempImageItA = m_InputImageIteratorArray[img_number];
383 
384  for(unsigned int band_x = 0; band_x < m_NumberOfPixels; band_x++)
385  {
386  m_Means[band_x] += tempImageItA.Get();
387  ++tempImageItA;
388  }
389  } // end: looping through the image
390  //-------------------------------------------------------------------------
391 
392  m_Means /= m_NumberOfTrainingImages;
393 
394  //-------------------------------------------------------------------------
395  // Calculate the inner product
396  //-------------------------------------------------------------------------
397  m_InnerProduct.set_size( m_NumberOfTrainingImages, m_NumberOfTrainingImages );
398  m_InnerProduct.fill( 0 );
399 
400  InputImageConstIterator tempImageItB;
401 
402  //-------------------------------------------------------------------------
403  for(unsigned int band_x = 0; band_x < m_NumberOfTrainingImages; band_x++)
404  {
405  for(unsigned int band_y = 0; band_y <= band_x; band_y++ )
406  {
407  //Pointer to the vector (in original matrix)
408  tempImageItA = m_InputImageIteratorArray[band_x];
409 
410  //Pointer to the vector in the transposed matrix
411  tempImageItB = m_InputImageIteratorArray[band_y];
412 
413  for(unsigned int pix_number = 0; pix_number < m_NumberOfPixels; pix_number++)
414  {
415  m_InnerProduct[band_x][band_y] +=
416  (tempImageItA.Get() - m_Means[pix_number]) *
417  (tempImageItB.Get() - m_Means[pix_number]);
418 
419  ++tempImageItA;
420  ++tempImageItB;
421  }// end: looping through the image
422  } // end: band_y loop
423  } // end: band_x loop
424 
425  //---------------------------------------------------------------------
426  // Fill the rest of the inner product matrix and make it symmetric
427  //---------------------------------------------------------------------
428 
429  for(unsigned int band_x = 0; band_x < (m_NumberOfTrainingImages - 1); band_x++)
430  {
431  for(unsigned int band_y = band_x+1; band_y < m_NumberOfTrainingImages; band_y++)
432  {
433  m_InnerProduct[band_x][band_y] = m_InnerProduct[band_y][band_x];
434  }// end band_y loop
435  }// end band_x loop
436 
437  if( ( m_NumberOfTrainingImages - 1 ) != 0 )
438  {
439  m_InnerProduct /= ( m_NumberOfTrainingImages - 1 );
440  }
441  else
442  {
443  m_InnerProduct.fill(0);
444  }
445 
446 }// end CalculateInnerProduct
447 
448 
449 /*-----------------------------------------------------------------
450  *Estimage shape models using PCA.
451  *-----------------------------------------------------------------
452  */
453 template<class TInputImage, class TOutputImage>
454 void
457 {
458 
459  MatrixOfDoubleType identityMatrix( m_NumberOfTrainingImages, m_NumberOfTrainingImages );
460  identityMatrix.set_identity();
461 
462  vnl_generalized_eigensystem eigenVectors_eigenValues(m_InnerProduct, identityMatrix);
463 
464  MatrixOfDoubleType eigenVectorsOfInnerProductMatrix = eigenVectors_eigenValues.V;
465 
466  //--------------------------------------------------------------------
467  //Calculate the pricipal shape variations
468  //
469  //m_EigenVectors capture the principal shape variantions
470  //m_EigenValues capture the relative weight of each variation
471  //Multiply original image vetors with the eigenVectorsOfInnerProductMatrix
472  //to derive the pricipal shapes.
473  //--------------------------------------------------------------------
474 
475  m_EigenVectors.set_size(m_NumberOfPixels, m_NumberOfTrainingImages);
476  m_EigenVectors.fill(0);
477 
478  double pix_value;
479  InputImageConstIterator tempImageItA;
480 
481  for(unsigned int img_number =0; img_number < m_NumberOfTrainingImages; img_number++ )
482  {
483  tempImageItA = m_InputImageIteratorArray[img_number];
484  for(unsigned int pix_number =0; pix_number < m_NumberOfPixels; pix_number++ )
485  {
486  pix_value = tempImageItA.Get();
487  for( unsigned int vec_number = 0; vec_number < m_NumberOfTrainingImages; vec_number++ )
488  {
489  m_EigenVectors[pix_number][vec_number] +=
490  (pix_value * eigenVectorsOfInnerProductMatrix[img_number][vec_number]);
491  }
492  ++tempImageItA;
493  }
494  }
495 
496  m_EigenVectors.normalize_columns();
497 
498  m_EigenValues.set_size(m_NumberOfTrainingImages);
499 
500  //Extract the diagonal elements into the Eigen value vector
501  m_EigenValues = (eigenVectors_eigenValues.D).diagonal();
502 
503  //Flip the eigen values since the eigen vectors output
504  //is ordered in decending order of theri corresponding eigen values.
505  m_EigenValues.flip();
506 
507  //--------------------------------------------------------------------
508  //Normalize the eigen values
509  //--------------------------------------------------------------------
510 
511  m_EigenVectorNormalizedEnergy = m_EigenValues;
512  m_EigenVectorNormalizedEnergy.normalize();
513 
514 
515 }// end EstimatePCAShapeModelParameters
516 
517 //-----------------------------------------------------------------
518 
519 
520 } // namespace itk
521 
522 #endif

Generated at Sat Feb 2 2013 23:43:24 for Orfeo Toolbox with doxygen 1.8.1.1