Orfeo Toolbox  3.16
itkMultiResolutionPyramidImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkMultiResolutionPyramidImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2009-07-12 10:52:50 $
7  Version: $Revision: 1.33 $
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 __itkMultiResolutionPyramidImageFilter_txx
18 #define __itkMultiResolutionPyramidImageFilter_txx
19 
21 #include "itkGaussianOperator.h"
22 #include "itkCastImageFilter.h"
24 #include "itkExceptionObject.h"
25 #include "itkResampleImageFilter.h"
26 #include "itkShrinkImageFilter.h"
27 #include "itkIdentityTransform.h"
28 
29 #include "vnl/vnl_math.h"
30 
31 namespace itk
32 {
33 
37 template <class TInputImage, class TOutputImage>
40 {
41  m_NumberOfLevels = 0;
42  this->SetNumberOfLevels( 2 );
43  m_MaximumError = 0.1;
44  m_UseShrinkImageFilter = false;
45 }
46 
47 
51 template <class TInputImage, class TOutputImage>
52 void
55  unsigned int num )
56 {
57  if( m_NumberOfLevels == num )
58  {
59  return;
60  }
61 
62  this->Modified();
63 
64  // clamp value to be at least one
65  m_NumberOfLevels = num;
66  if( m_NumberOfLevels < 1 ) m_NumberOfLevels = 1;
67 
68  // resize the schedules
69  ScheduleType temp( m_NumberOfLevels, ImageDimension );
70  temp.Fill( 0 );
71  m_Schedule = temp;
72 
73  // determine initial shrink factor
74  unsigned int startfactor = 1;
75  startfactor = startfactor << ( m_NumberOfLevels - 1 );
76 
77  // set the starting shrink factors
78  this->SetStartingShrinkFactors( startfactor );
79 
80  // set the required number of outputs
81  this->SetNumberOfRequiredOutputs( m_NumberOfLevels );
82 
83  unsigned int numOutputs = static_cast<unsigned int>( this->GetNumberOfOutputs() );
84  unsigned int idx;
85  if( numOutputs < m_NumberOfLevels )
86  {
87  // add extra outputs
88  for( idx = numOutputs; idx < m_NumberOfLevels; idx++ )
89  {
90  typename DataObject::Pointer output =
91  this->MakeOutput( idx );
92  this->SetNthOutput( idx, output.GetPointer() );
93  }
94 
95  }
96  else if( numOutputs > m_NumberOfLevels )
97  {
98  // remove extra outputs
99  for( idx = m_NumberOfLevels; idx < numOutputs; idx++ )
100  {
101  typename DataObject::Pointer output =
102  this->GetOutputs()[idx];
103  this->RemoveOutput( output );
104  }
105  }
106 
107 }
108 
109 
110 /*
111  * Set the starting shrink factors
112  */
113 template <class TInputImage, class TOutputImage>
114 void
117  unsigned int factor )
118 {
119 
120  unsigned int array[ImageDimension];
121  for( unsigned int dim = 0; dim < ImageDimension; ++dim )
122  {
123  array[dim] = factor;
124  }
125 
126  this->SetStartingShrinkFactors( array );
127 
128 }
129 
130 
134 template <class TInputImage, class TOutputImage>
135 void
138  unsigned int * factors )
139 {
140 
141  for( unsigned int dim = 0; dim < ImageDimension; ++dim )
142  {
143  m_Schedule[0][dim] = factors[dim];
144  if( m_Schedule[0][dim] == 0 )
145  {
146  m_Schedule[0][dim] = 1;
147  }
148  }
149 
150  for( unsigned int level = 1; level < m_NumberOfLevels; ++level )
151  {
152  for( unsigned int dim = 0; dim < ImageDimension; ++dim )
153  {
154  m_Schedule[level][dim] = m_Schedule[level-1][dim] / 2;
155  if( m_Schedule[level][dim] == 0 )
156  {
157  m_Schedule[level][dim] = 1;
158  }
159  }
160  }
161 
162  this->Modified();
163 
164 }
165 
166 
167 /*
168  * Get the starting shrink factors
169  */
170 template <class TInputImage, class TOutputImage>
171 const unsigned int *
174 {
175  return ( m_Schedule.data_block() );
176 }
177 
178 
179 /*
180  * Set the multi-resolution schedule
181  */
182 template <class TInputImage, class TOutputImage>
183 void
186  const ScheduleType& schedule )
187 {
188 
189  if( schedule.rows() != m_NumberOfLevels ||
190  schedule.columns() != ImageDimension )
191  {
192  itkDebugMacro(<< "Schedule has wrong dimensions" );
193  return;
194  }
195 
196  if( schedule == m_Schedule )
197  {
198  return;
199  }
200 
201  this->Modified();
202  unsigned int level, dim;
203  for( level = 0; level < m_NumberOfLevels; level++ )
204  {
205  for( dim = 0; dim < ImageDimension; dim++ )
206  {
207 
208  m_Schedule[level][dim] = schedule[level][dim];
209 
210  // set schedule to max( 1, min(schedule[level],
211  // schedule[level-1] );
212  if( level > 0 )
213  {
214  m_Schedule[level][dim] = vnl_math_min(
215  m_Schedule[level][dim], m_Schedule[level-1][dim] );
216  }
217 
218  if( m_Schedule[level][dim] < 1 )
219  {
220  m_Schedule[level][dim] = 1;
221  }
222 
223  }
224  }
225 }
226 
227 
228 /*
229  * Is the schedule downward divisible ?
230  */
231 template <class TInputImage, class TOutputImage>
232 bool
235 {
236 
237  unsigned int ilevel, idim;
238  for( ilevel = 0; ilevel < schedule.rows() - 1; ilevel++ )
239  {
240  for( idim = 0; idim < schedule.columns(); idim++ )
241  {
242  if( schedule[ilevel][idim] == 0 )
243  {
244  return false;
245  }
246  if( ( schedule[ilevel][idim] % schedule[ilevel+1][idim] ) > 0 )
247  {
248  return false;
249  }
250  }
251  }
252 
253  return true;
254 }
255 
256 /*
257  * GenerateData for non downward divisible schedules
258  */
259 template <class TInputImage, class TOutputImage>
260 void
263 {
264  // Get the input and output pointers
265  InputImageConstPointer inputPtr = this->GetInput();
266 
267  // Create caster, smoother and resampleShrinker filters
270 
271  typedef ImageToImageFilter<TOutputImage,TOutputImage> ImageToImageType;
272  typedef ResampleImageFilter<TOutputImage,TOutputImage> ResampleShrinkerType;
274 
275  typename CasterType::Pointer caster = CasterType::New();
276  typename SmootherType::Pointer smoother = SmootherType::New();
277 
278  typename ImageToImageType::Pointer shrinkerFilter;
279  //
280  // only one of these pointers is going to be valid, depending on the
281  // value of UseShrinkImageFilter flag
282  typename ResampleShrinkerType::Pointer resampleShrinker;
283  typename ShrinkerType::Pointer shrinker;
284 
285  if(this->GetUseShrinkImageFilter())
286  {
287  shrinker = ShrinkerType::New();
288  shrinkerFilter = shrinker.GetPointer();
289  }
290  else
291  {
292  resampleShrinker = ResampleShrinkerType::New();
294  LinearInterpolatorType;
295  typename LinearInterpolatorType::Pointer interpolator =
296  LinearInterpolatorType::New();
297  resampleShrinker->SetInterpolator( interpolator );
298  resampleShrinker->SetDefaultPixelValue( 0 );
299  shrinkerFilter = resampleShrinker.GetPointer();
300  }
301  // Setup the filters
302  caster->SetInput( inputPtr );
303 
304  smoother->SetUseImageSpacing( false );
305  smoother->SetInput( caster->GetOutput() );
306  smoother->SetMaximumError( m_MaximumError );
307 
308  shrinkerFilter->SetInput( smoother->GetOutput() );
309 
310  unsigned int ilevel, idim;
311  unsigned int factors[ImageDimension];
312  double variance[ImageDimension];
313 
314  for( ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ )
315  {
316  this->UpdateProgress( static_cast<float>( ilevel ) /
317  static_cast<float>( m_NumberOfLevels ) );
318 
319  // Allocate memory for each output
320  OutputImagePointer outputPtr = this->GetOutput( ilevel );
321  outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() );
322  outputPtr->Allocate();
323 
324  // compute shrink factors and variances
325  for( idim = 0; idim < ImageDimension; idim++ )
326  {
327  factors[idim] = m_Schedule[ilevel][idim];
328  variance[idim] = vnl_math_sqr( 0.5 *
329  static_cast<float>( factors[idim] ) );
330  }
331 
332  if(!this->GetUseShrinkImageFilter())
333  {
335  IdentityTransformType;
336  typename IdentityTransformType::Pointer identityTransform =
337  IdentityTransformType::New();
338  resampleShrinker->SetOutputParametersFromImage( outputPtr );
339  resampleShrinker->SetTransform(identityTransform);
340  }
341  else
342  {
343  shrinker->SetShrinkFactors(factors);
344  }
345  // use mini-pipeline to compute output
346  smoother->SetVariance( variance );
347 
348  shrinkerFilter->GraftOutput( outputPtr );
349 
350  // force to always update in case shrink factors are the same
351  shrinkerFilter->Modified();
352  shrinkerFilter->UpdateLargestPossibleRegion();
353  this->GraftNthOutput( ilevel, shrinkerFilter->GetOutput() );
354  }
355 }
356 
360 template <class TInputImage, class TOutputImage>
361 void
363 ::PrintSelf(std::ostream& os, Indent indent) const
364 {
365  Superclass::PrintSelf(os,indent);
366 
367  os << indent << "MaximumError: " << m_MaximumError << std::endl;
368  os << indent << "No. levels: " << m_NumberOfLevels << std::endl;
369  os << indent << "Schedule: " << std::endl;
370  os << m_Schedule << std::endl;
371  os << "Use ShrinkImageFilter= " << m_UseShrinkImageFilter << std::endl;
372 }
373 
374 
375 /*
376  * GenerateOutputInformation
377  */
378 template <class TInputImage, class TOutputImage>
379 void
382 {
383 
384  // call the superclass's implementation of this method
385  Superclass::GenerateOutputInformation();
386 
387  // get pointers to the input and output
388  InputImageConstPointer inputPtr = this->GetInput();
389 
390  if ( !inputPtr )
391  {
392  itkExceptionMacro( << "Input has not been set" );
393  }
394 
395  const typename InputImageType::PointType&
396  inputOrigin = inputPtr->GetOrigin();
397  const typename InputImageType::SpacingType&
398  inputSpacing = inputPtr->GetSpacing();
399  const typename InputImageType::DirectionType&
400  inputDirection = inputPtr->GetDirection();
401  const typename InputImageType::SizeType& inputSize =
402  inputPtr->GetLargestPossibleRegion().GetSize();
403  const typename InputImageType::IndexType& inputStartIndex =
404  inputPtr->GetLargestPossibleRegion().GetIndex();
405 
406  typedef typename OutputImageType::SizeType SizeType;
407  typedef typename SizeType::SizeValueType SizeValueType;
408  typedef typename OutputImageType::IndexType IndexType;
409  typedef typename IndexType::IndexValueType IndexValueType;
410 
411  OutputImagePointer outputPtr;
412  typename OutputImageType::PointType outputOrigin;
413  typename OutputImageType::SpacingType outputSpacing;
414  SizeType outputSize;
415  IndexType outputStartIndex;
416 
417  // we need to compute the output spacing, the output image size,
418  // and the output image start index
419  for(unsigned int ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ )
420  {
421  outputPtr = this->GetOutput( ilevel );
422  if( !outputPtr ) { continue; }
423 
424  for(unsigned int idim = 0; idim < OutputImageType::ImageDimension; idim++ )
425  {
426  const double shrinkFactor = static_cast<double>( m_Schedule[ilevel][idim] );
427  outputSpacing[idim] = inputSpacing[idim] * shrinkFactor;
428 
429  outputSize[idim] = static_cast<SizeValueType>(
430  vcl_floor(static_cast<double>(inputSize[idim]) / shrinkFactor ) );
431  if( outputSize[idim] < 1 ) { outputSize[idim] = 1; }
432 
433  outputStartIndex[idim] = static_cast<IndexValueType>(
434  vcl_ceil(static_cast<double>(inputStartIndex[idim]) / shrinkFactor ) );
435  }
436  //Now compute the new shifted origin for the updated levels;
437  const typename OutputImageType::PointType::VectorType outputOriginOffset
438  =(inputDirection*(outputSpacing-inputSpacing))*0.5;
439  for(unsigned int idim = 0; idim < OutputImageType::ImageDimension; idim++ )
440  {
441  outputOrigin[idim]=inputOrigin[idim]+outputOriginOffset[idim];
442  }
443 
444  typename OutputImageType::RegionType outputLargestPossibleRegion;
445  outputLargestPossibleRegion.SetSize( outputSize );
446  outputLargestPossibleRegion.SetIndex( outputStartIndex );
447 
448  outputPtr->SetLargestPossibleRegion( outputLargestPossibleRegion );
449  outputPtr->SetOrigin ( outputOrigin );
450  outputPtr->SetSpacing( outputSpacing );
451  outputPtr->SetDirection( inputDirection );//Output Direction should be same as input.
452  }
453 }
454 
455 
456 /*
457  * GenerateOutputRequestedRegion
458  */
459 template <class TInputImage, class TOutputImage>
460 void
463 {
464  // call the superclass's implementation of this method
465  Superclass::GenerateOutputRequestedRegion( refOutput );
466 
467  // find the index for this output
468  unsigned int refLevel = refOutput->GetSourceOutputIndex();
469 
470  // compute baseIndex and baseSize
471  typedef typename OutputImageType::SizeType SizeType;
472  typedef typename SizeType::SizeValueType SizeValueType;
473  typedef typename OutputImageType::IndexType IndexType;
474  typedef typename IndexType::IndexValueType IndexValueType;
475  typedef typename OutputImageType::RegionType RegionType;
476 
477  TOutputImage * ptr = static_cast<TOutputImage*>( refOutput );
478  if( !ptr )
479  {
480  itkExceptionMacro( << "Could not cast refOutput to TOutputImage*." );
481  }
482 
483  unsigned int ilevel, idim;
484 
485  if ( ptr->GetRequestedRegion() == ptr->GetLargestPossibleRegion() )
486  {
487  // set the requested regions for the other outputs to their
488  // requested region
489 
490  for( ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ )
491  {
492  if( ilevel == refLevel ) { continue; }
493  if( !this->GetOutput(ilevel) ) { continue; }
494  this->GetOutput(ilevel)->SetRequestedRegionToLargestPossibleRegion();
495  }
496  }
497  else
498  {
499  // compute requested regions for the other outputs based on
500  // the requested region of the reference output
501  IndexType outputIndex;
502  SizeType outputSize;
503  RegionType outputRegion;
504  IndexType baseIndex = ptr->GetRequestedRegion().GetIndex();
505  SizeType baseSize = ptr->GetRequestedRegion().GetSize();
506 
507  for( idim = 0; idim < TOutputImage::ImageDimension; idim++ )
508  {
509  unsigned int factor = m_Schedule[refLevel][idim];
510  baseIndex[idim] *= static_cast<IndexValueType>( factor );
511  baseSize[idim] *= static_cast<SizeValueType>( factor );
512  }
513 
514  for( ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ )
515  {
516  if( ilevel == refLevel ) { continue; }
517  if( !this->GetOutput(ilevel) ) { continue; }
518 
519  for( idim = 0; idim < TOutputImage::ImageDimension; idim++ )
520  {
521 
522  double factor = static_cast<double>( m_Schedule[ilevel][idim] );
523 
524  outputSize[idim] = static_cast<SizeValueType>(
525  vcl_floor(static_cast<double>(baseSize[idim]) / factor ) );
526  if( outputSize[idim] < 1 ) { outputSize[idim] = 1; }
527 
528  outputIndex[idim] = static_cast<IndexValueType>(
529  vcl_ceil(static_cast<double>(baseIndex[idim]) / factor ) );
530 
531  }
532 
533  outputRegion.SetIndex( outputIndex );
534  outputRegion.SetSize( outputSize );
535 
536  // make sure the region is within the largest possible region
537  outputRegion.Crop( this->GetOutput( ilevel )->
538  GetLargestPossibleRegion() );
539  // set the requested region
540  this->GetOutput( ilevel )->SetRequestedRegion( outputRegion );
541  }
542 
543  }
544 }
545 
546 
550 template <class TInputImage, class TOutputImage>
551 void
554 {
555  // call the superclass' implementation of this method
556  Superclass::GenerateInputRequestedRegion();
557 
558  // get pointers to the input and output
559  InputImagePointer inputPtr =
560  const_cast< InputImageType * >( this->GetInput() );
561  if ( !inputPtr )
562  {
563  itkExceptionMacro( << "Input has not been set." );
564  }
565 
566  // compute baseIndex and baseSize
567  typedef typename OutputImageType::SizeType SizeType;
568  typedef typename SizeType::SizeValueType SizeValueType;
569  typedef typename OutputImageType::IndexType IndexType;
570  typedef typename IndexType::IndexValueType IndexValueType;
571  typedef typename OutputImageType::RegionType RegionType;
572 
573  unsigned int refLevel = m_NumberOfLevels - 1;
574  SizeType baseSize = this->GetOutput(refLevel)->GetRequestedRegion().GetSize();
575  IndexType baseIndex = this->GetOutput(refLevel)->GetRequestedRegion().GetIndex();
576  RegionType baseRegion;
577 
578  unsigned int idim;
579  for( idim = 0; idim < ImageDimension; idim++ )
580  {
581  unsigned int factor = m_Schedule[refLevel][idim];
582  baseIndex[idim] *= static_cast<IndexValueType>( factor );
583  baseSize[idim] *= static_cast<SizeValueType>( factor );
584  }
585  baseRegion.SetIndex( baseIndex );
586  baseRegion.SetSize( baseSize );
587 
588  // compute requirements for the smoothing part
589  typedef typename TOutputImage::PixelType OutputPixelType;
591 
592  OperatorType *oper = new OperatorType;
593 
594  typename TInputImage::SizeType radius;
595 
596  RegionType inputRequestedRegion = baseRegion;
597  refLevel = 0;
598 
599  for( idim = 0; idim < TInputImage::ImageDimension; idim++ )
600  {
601  oper->SetDirection(idim);
602  oper->SetVariance( vnl_math_sqr( 0.5 * static_cast<float>(
603  m_Schedule[refLevel][idim] ) ) );
604  oper->SetMaximumError( m_MaximumError );
605  oper->CreateDirectional();
606  radius[idim] = oper->GetRadius()[idim];
607  }
608  delete oper;
609 
610  inputRequestedRegion.PadByRadius( radius );
611 
612  // make sure the requested region is within the largest possible
613  inputRequestedRegion.Crop( inputPtr->GetLargestPossibleRegion() );
614 
615  // set the input requested region
616  inputPtr->SetRequestedRegion( inputRequestedRegion );
617 
618 }
619 
620 
621 } // namespace itk
622 
623 #endif

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