1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkResampleImageFilter_hxx
19 #define itkResampleImageFilter_hxx
20 
21 #include "itkResampleImageFilter.h"
22 #include "itkObjectFactory.h"
23 #include "itkIdentityTransform.h"
24 #include "itkProgressReporter.h"
25 #include "itkImageRegionIteratorWithIndex.h"
26 #include "itkImageScanlineIterator.h"
27 #include "itkSpecialCoordinatesImage.h"
28 #include "itkDefaultConvertPixelTraits.h"
29 #include "itkImageAlgorithm.h"
30 
31 #include <type_traits>  // For is_same.
32 
33 namespace itk
34 {
35 
36 template< typename TInputImage,
37           typename TOutputImage,
38           typename TInterpolatorPrecisionType,
39           typename TTransformPrecisionType >
40 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
ResampleImageFilter()41 ::ResampleImageFilter() :
42   m_Extrapolator( nullptr ),
43   m_OutputSpacing( 1.0 ),
44   m_OutputOrigin( 0.0 )
45 
46 {
47 
48   m_Size.Fill( 0 );
49   m_OutputStartIndex.Fill( 0 );
50 
51   m_OutputDirection.SetIdentity();
52 
53   // Pipeline input configuration
54 
55   // implicit:
56   // #0 "Primary" required
57 
58   // #1 "ReferenceImage" optional
59   Self::AddRequiredInputName("ReferenceImage",1);
60   Self::RemoveRequiredInputName("ReferenceImage");
61 
62   // "Transform" required ( not numbered )
63   Self::AddRequiredInputName("Transform");
64   Self::SetTransform(IdentityTransform< TTransformPrecisionType, ImageDimension >::New());
65 
66   m_Interpolator = dynamic_cast< InterpolatorType * >
67     ( LinearInterpolatorType::New().GetPointer() );
68 
69   m_DefaultPixelValue = NumericTraits<PixelType>::ZeroValue( m_DefaultPixelValue );
70   this->DynamicMultiThreadingOn();
71 }
72 
73 template< typename TInputImage,
74           typename TOutputImage,
75           typename TInterpolatorPrecisionType,
76           typename TTransformPrecisionType >
77 void
78 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
SetOutputSpacing(const double * spacing)79 ::SetOutputSpacing(const double *spacing)
80 {
81   SpacingType s;
82   for(unsigned int i = 0; i < TOutputImage::ImageDimension; ++i)
83     {
84     s[i] = static_cast< typename SpacingType::ValueType >(spacing[i]);
85     }
86   this->SetOutputSpacing(s);
87 }
88 
89 template< typename TInputImage,
90           typename TOutputImage,
91           typename TInterpolatorPrecisionType,
92           typename TTransformPrecisionType >
93 void
94 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
SetOutputOrigin(const double * origin)95 ::SetOutputOrigin(const double *origin)
96 {
97   OriginPointType p(origin);
98 
99   this->SetOutputOrigin(p);
100 }
101 
102 template< typename TInputImage,
103           typename TOutputImage,
104           typename TInterpolatorPrecisionType,
105           typename TTransformPrecisionType >
106 void
107 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
SetOutputParametersFromImage(const ImageBaseType * image)108 ::SetOutputParametersFromImage(const ImageBaseType *image)
109 {
110   this->SetOutputOrigin ( image->GetOrigin() );
111   this->SetOutputSpacing ( image->GetSpacing() );
112   this->SetOutputDirection ( image->GetDirection() );
113   this->SetOutputStartIndex ( image->GetLargestPossibleRegion().GetIndex() );
114   this->SetSize ( image->GetLargestPossibleRegion().GetSize() );
115 }
116 
117 template< typename TInputImage,
118           typename TOutputImage,
119           typename TInterpolatorPrecisionType,
120           typename TTransformPrecisionType >
121 void
122 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
BeforeThreadedGenerateData()123 ::BeforeThreadedGenerateData()
124 {
125   m_Interpolator->SetInputImage( this->GetInput() );
126 
127   // Connect input image to extrapolator
128   if( !m_Extrapolator.IsNull() )
129     {
130     m_Extrapolator->SetInputImage( this->GetInput() );
131     }
132 
133   unsigned int nComponents
134     = DefaultConvertPixelTraits<PixelType>::GetNumberOfComponents(
135         m_DefaultPixelValue );
136 
137   if (nComponents == 0)
138     {
139     PixelComponentType zeroComponent
140       = NumericTraits<PixelComponentType>::ZeroValue( zeroComponent );
141     nComponents = this->GetInput()->GetNumberOfComponentsPerPixel();
142     NumericTraits<PixelType>::SetLength(m_DefaultPixelValue, nComponents );
143     for (unsigned int n=0; n<nComponents; n++)
144       {
145       PixelConvertType::SetNthComponent( n, m_DefaultPixelValue,
146                                          zeroComponent );
147       }
148     }
149 }
150 
151 template< typename TInputImage,
152           typename TOutputImage,
153           typename TInterpolatorPrecisionType,
154           typename TTransformPrecisionType >
155 void
156 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
AfterThreadedGenerateData()157 ::AfterThreadedGenerateData()
158 {
159   // Disconnect input image from the interpolator
160   m_Interpolator->SetInputImage(nullptr);
161   if( !m_Extrapolator.IsNull() )
162     {
163     // Disconnect input image from the extrapolator
164     m_Extrapolator->SetInputImage(nullptr);
165     }
166 }
167 
168 template< typename TInputImage,
169           typename TOutputImage,
170           typename TInterpolatorPrecisionType,
171           typename TTransformPrecisionType >
172 void
173 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)174 ::DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)
175 {
176   // Check whether the input or the output is a
177   // SpecialCoordinatesImage. If either are, then we cannot use the
178   // fast path since index mapping will definitely not be linear.
179   using OutputSpecialCoordinatesImageType = SpecialCoordinatesImage< PixelType, ImageDimension >;
180   using InputSpecialCoordinatesImageType = SpecialCoordinatesImage< InputPixelType, InputImageDimension >;
181 
182   if( outputRegionForThread.GetNumberOfPixels() == 0 )
183     {
184     return;
185     }
186 
187   const bool isSpecialCoordinatesImage = ( dynamic_cast< const InputSpecialCoordinatesImageType * >( this->GetInput() )
188        || dynamic_cast< const OutputSpecialCoordinatesImageType * >( this->GetOutput() ) );
189 
190 
191   // Check whether we can use a fast path for resampling. Fast path
192   // can be used if the transformation is linear. Transform respond
193   // to the IsLinear() call.
194   if ( !isSpecialCoordinatesImage && this->GetTransform()->GetTransformCategory() == TransformType::Linear )
195     {
196     this->LinearThreadedGenerateData(outputRegionForThread);
197     return;
198     }
199 
200   // Otherwise, we use the normal method where the transform is called
201   // for computing the transformation of every point.
202   this->NonlinearThreadedGenerateData(outputRegionForThread);
203 }
204 
205 
206 #ifndef ITK_LEGACY_REMOVE
207 template< typename TInputImage,
208           typename TOutputImage,
209           typename TInterpolatorPrecisionType,
210           typename TTransformPrecisionType >
211 typename ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
212 ::PixelType
213 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
CastPixelWithBoundsChecking(const InterpolatorOutputType value,const ComponentType minComponent,const ComponentType maxComponent) const214 ::CastPixelWithBoundsChecking(const InterpolatorOutputType value,
215                               const ComponentType minComponent,
216                               const ComponentType maxComponent ) const
217 {
218   const unsigned int nComponents = InterpolatorConvertType::GetNumberOfComponents(value);
219   PixelType          outputValue;
220 
221   NumericTraits<PixelType>::SetLength( outputValue, nComponents );
222 
223   for (unsigned int n = 0; n < nComponents; n++)
224     {
225     ComponentType component = InterpolatorConvertType::GetNthComponent( n, value );
226 
227     if ( component < minComponent )
228       {
229       PixelConvertType::SetNthComponent( n, outputValue, static_cast<PixelComponentType>( minComponent ) );
230       }
231     else if ( component > maxComponent )
232       {
233       PixelConvertType::SetNthComponent( n, outputValue, static_cast<PixelComponentType>( maxComponent ) );
234       }
235     else
236       {
237       PixelConvertType::SetNthComponent(n, outputValue,
238                                         static_cast<PixelComponentType>( component ) );
239       }
240     }
241 
242   return outputValue;
243 }
244 #endif // ITK_LEGACY_REMOVE
245 
246 
247 template< typename TInputImage,
248           typename TOutputImage,
249           typename TInterpolatorPrecisionType,
250           typename TTransformPrecisionType >
251 auto ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
CastComponentWithBoundsChecking(const PixelComponentType value)252 ::CastComponentWithBoundsChecking(const PixelComponentType value) -> PixelComponentType
253 {
254   // Just return the argument. In this case, there is no need to cast or clamp its value.
255   return value;
256 }
257 
258 
259 template< typename TInputImage,
260           typename TOutputImage,
261           typename TInterpolatorPrecisionType,
262           typename TTransformPrecisionType >
263 template <typename TComponent>
264 auto ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
CastComponentWithBoundsChecking(const TComponent value)265 ::CastComponentWithBoundsChecking(const TComponent value) -> PixelComponentType
266 {
267   static_assert(std::is_same<TComponent, ComponentType>::value,
268     "TComponent should just be the same as the ComponentType!");
269   static_assert(!std::is_same<TComponent, PixelComponentType>::value,
270     "For PixelComponentType there is a more appropriate overload, that should be called instead!");
271 
272   // Retrieve minimum and maximum values at compile-time:
273   constexpr auto minPixelComponent = NumericTraits< PixelComponentType >::NonpositiveMin();
274   constexpr auto maxPixelComponent = NumericTraits< PixelComponentType >::max();
275   constexpr auto minComponent = static_cast<ComponentType>(minPixelComponent);
276   constexpr auto maxComponent = static_cast<ComponentType>(maxPixelComponent);
277 
278   // Clamp the value between minPixelComponent and maxPixelComponent:
279   return (value <= minComponent) ? minPixelComponent :
280     (value >= maxComponent) ? maxPixelComponent : static_cast<PixelComponentType>(value);
281 }
282 
283 
284 template< typename TInputImage,
285           typename TOutputImage,
286           typename TInterpolatorPrecisionType,
287           typename TTransformPrecisionType >
288 auto ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
CastPixelWithBoundsChecking(const ComponentType value)289 ::CastPixelWithBoundsChecking(const ComponentType value) -> PixelType
290 {
291   return CastComponentWithBoundsChecking(value);
292 }
293 
294 
295 template< typename TInputImage,
296           typename TOutputImage,
297           typename TInterpolatorPrecisionType,
298           typename TTransformPrecisionType >
299 template <typename TPixel>
300 auto ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
CastPixelWithBoundsChecking(const TPixel value)301 ::CastPixelWithBoundsChecking(const TPixel value) -> PixelType
302 {
303   static_assert(std::is_same<TPixel, InterpolatorOutputType>::value,
304     "TPixel should just be the same as the InterpolatorOutputType!");
305   static_assert(!std::is_same<TPixel, ComponentType>::value,
306     "For ComponentType there is a more efficient overload, that should be called instead!");
307 
308   const unsigned int nComponents = InterpolatorConvertType::GetNumberOfComponents(value);
309   PixelType          outputValue;
310 
311   NumericTraits<PixelType>::SetLength(outputValue, nComponents);
312 
313   for (unsigned int n = 0; n < nComponents; ++n)
314   {
315     const ComponentType component = InterpolatorConvertType::GetNthComponent(n, value);
316     PixelConvertType::SetNthComponent(n, outputValue,
317       Self::CastComponentWithBoundsChecking(component));
318   }
319 
320   return outputValue;
321 }
322 
323 
324 template< typename TInputImage,
325           typename TOutputImage,
326           typename TInterpolatorPrecisionType,
327           typename TTransformPrecisionType >
328 void
329 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
NonlinearThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)330 ::NonlinearThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)
331 {
332   OutputImageType *outputPtr = this->GetOutput();
333   const InputImageType *inputPtr = this->GetInput();
334   const TransformType *transformPtr = this->GetTransform();
335 
336   // Honor the SpecialCoordinatesImage isInside value returned
337   // by TransformPhysicalPointToContinuousIndex
338   using InputSpecialCoordinatesImageType = SpecialCoordinatesImage< InputPixelType, InputImageDimension >;
339   const bool isSpecialCoordinatesImage = dynamic_cast< const InputSpecialCoordinatesImageType * >( inputPtr );
340 
341 
342   // Create an iterator that will walk the output region for this thread.
343   using OutputIterator = ImageRegionIteratorWithIndex< TOutputImage >;
344   OutputIterator outIt(outputPtr, outputRegionForThread);
345 
346   // Define a few indices that will be used to translate from an input pixel
347   // to an output pixel
348   PointType outputPoint;         // Coordinates of current output pixel
349   PointType inputPoint;          // Coordinates of current input pixel
350 
351   ContinuousInputIndexType inputIndex;
352 
353   using OutputType = typename InterpolatorType::OutputType;
354 
355   // Walk the output region
356   outIt.GoToBegin();
357 
358   while ( !outIt.IsAtEnd() )
359     {
360     // Determine the index of the current output pixel
361     outputPtr->TransformIndexToPhysicalPoint(outIt.GetIndex(), outputPoint);
362 
363     // Compute corresponding input pixel position
364     inputPoint = transformPtr->TransformPoint(outputPoint);
365     const bool isInsideInput = inputPtr->TransformPhysicalPointToContinuousIndex(inputPoint, inputIndex);
366 
367     OutputType value;
368     // Evaluate input at right position and copy to the output
369     if( m_Interpolator->IsInsideBuffer(inputIndex) && ( !isSpecialCoordinatesImage || isInsideInput ) )
370       {
371       value = m_Interpolator->EvaluateAtContinuousIndex(inputIndex);
372       outIt.Set( Self::CastPixelWithBoundsChecking(value) );
373       }
374     else
375       {
376       if( m_Extrapolator.IsNull() )
377         {
378         outIt.Set( m_DefaultPixelValue ); // default background value
379         }
380       else
381         {
382         value = m_Extrapolator->EvaluateAtContinuousIndex( inputIndex );
383         outIt.Set( Self::CastPixelWithBoundsChecking(value) );
384         }
385       }
386 
387     ++outIt;
388     }
389 }
390 
391 template< typename TInputImage,
392           typename TOutputImage,
393           typename TInterpolatorPrecisionType,
394           typename TTransformPrecisionType >
395 void
396 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
LinearThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)397 ::LinearThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)
398 {
399   OutputImageType *outputPtr = this->GetOutput();
400   const InputImageType *inputPtr = this->GetInput();
401   const TransformType *transformPtr = this->GetTransform();
402 
403   // Create an iterator that will walk the output region for this thread.
404   using OutputIterator = ImageScanlineIterator< TOutputImage >;
405   OutputIterator outIt(outputPtr, outputRegionForThread);
406 
407   // Define a few indices that will be used to translate from an input pixel
408   // to an output pixel
409   PointType outputPoint;         // Coordinates of current output pixel
410   PointType inputPoint;          // Coordinates of current input pixel
411 
412   const InputImageRegionType &largestPossibleRegion = outputPtr->GetLargestPossibleRegion();
413 
414   using OutputType = typename InterpolatorType::OutputType;
415 
416   // Cache information from the superclass
417   PixelType defaultValue = this->GetDefaultPixelValue();
418 
419   using OutputType = typename InterpolatorType::OutputType;
420 
421   // As we walk across a scan line in the output image, we trace
422   // an oriented/scaled/translated line in the input image. Each scan
423   // line has a starting and ending point. Since all transforms
424   // are linear, the path between the points is linear and can be
425   // defined by interpolating between the two points. By using
426   // interpolation we avoid accumulation errors, and by using the
427   // whole scan line from the largest possible region we make the
428   // computation independent for each point and independent of the
429   // region we are processing which makes the method independent of
430   // how the whole image is split for processing ( threading,
431   // streaming, etc ).
432   //
433 
434   while ( !outIt.IsAtEnd() )
435     {
436     // Determine the continuous index of the first and end pixel of output
437     // scan line when mapped to the input coordinate frame.
438 
439     IndexType index = outIt.GetIndex();
440     index[0] = largestPossibleRegion.GetIndex(0);
441 
442     ContinuousInputIndexType startIndex;
443     outputPtr->TransformIndexToPhysicalPoint(index, outputPoint);
444     inputPoint = transformPtr->TransformPoint(outputPoint);
445     inputPtr->TransformPhysicalPointToContinuousIndex(inputPoint, startIndex);
446 
447     ContinuousInputIndexType endIndex;
448     index[0] += largestPossibleRegion.GetSize(0);
449     outputPtr->TransformIndexToPhysicalPoint(index, outputPoint);
450     inputPoint = transformPtr->TransformPoint(outputPoint);
451     inputPtr->TransformPhysicalPointToContinuousIndex(inputPoint, endIndex);
452 
453     IndexValueType scanlineIndex = outIt.GetIndex()[0];
454 
455 
456     while ( !outIt.IsAtEndOfLine() )
457       {
458 
459       // Perform linear interpolation between startIndex and endIndex
460       const double alpha = (scanlineIndex - largestPossibleRegion.GetIndex(0)) / (double)(largestPossibleRegion.GetSize(0));
461 
462       ContinuousInputIndexType inputIndex( startIndex );
463       for (unsigned int i = 0; i < ImageDimension; ++i)
464         {
465         inputIndex[i] += alpha * ( endIndex[i] - startIndex[i] );
466         }
467 
468       OutputType value;
469       // Evaluate input at right position and copy to the output
470       if ( m_Interpolator->IsInsideBuffer(inputIndex) )
471         {
472         value = m_Interpolator->EvaluateAtContinuousIndex(inputIndex);
473         outIt.Set( Self::CastPixelWithBoundsChecking(value) );
474         }
475       else
476         {
477         if( m_Extrapolator.IsNull() )
478           {
479           outIt.Set(defaultValue); // default background value
480           }
481         else
482           {
483           value = m_Extrapolator->EvaluateAtContinuousIndex( inputIndex );
484           outIt.Set( Self::CastPixelWithBoundsChecking(value) );
485           }
486         }
487 
488       ++outIt;
489       ++scanlineIndex;
490       }
491     outIt.NextLine();
492     }
493 }
494 
495 template< typename TInputImage,
496           typename TOutputImage,
497           typename TInterpolatorPrecisionType,
498           typename TTransformPrecisionType >
499 void
500 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
GenerateInputRequestedRegion()501 ::GenerateInputRequestedRegion()
502 {
503   if ( !m_Interpolator )
504     {
505     itkExceptionMacro(<< "Interpolator not set");
506     }
507 
508   // Get pointers to the input and output
509   InputImageType * input  = const_cast< InputImageType * >( this->GetInput() );
510 
511   // Some interpolators need to look at their images in GetRadius()
512   m_Interpolator->SetInputImage( input );
513 
514 #if !defined(ITKV4_COMPATIBILITY)
515   // Check whether the input or the output is a
516   // SpecialCoordinatesImage. If either are, then we cannot use the
517   // fast path since index mapping will definitely not be linear.
518   typedef SpecialCoordinatesImage< PixelType, ImageDimension >           OutputSpecialCoordinatesImageType;
519   typedef SpecialCoordinatesImage< InputPixelType, InputImageDimension > InputSpecialCoordinatesImageType;
520 
521   const bool isSpecialCoordinatesImage = ( dynamic_cast< const InputSpecialCoordinatesImageType * >( this->GetInput() )
522        || dynamic_cast< const OutputSpecialCoordinatesImageType * >( this->GetOutput() ) );
523 
524   const OutputImageType *output = this->GetOutput();
525   // Get the input transform
526   const TransformType *transform = this->GetTransform();
527 
528   // Check whether we can use upstream streaming for resampling. Upstream streaming
529   // can be used if the transformation is linear. Transform respond
530   // to the IsLinear() call.
531   if ( !isSpecialCoordinatesImage && transform->GetTransformCategory() == TransformType::Linear )
532     {
533     typename TInputImage::RegionType inputRequestedRegion;
534     inputRequestedRegion = ImageAlgorithm::EnlargeRegionOverBox(output->GetRequestedRegion(),
535         output,
536         input,
537         transform);
538 
539     const typename TInputImage::RegionType inputLargestRegion( input->GetLargestPossibleRegion() );
540     if( inputLargestRegion.IsInside( inputRequestedRegion.GetIndex() ) || inputLargestRegion.IsInside( inputRequestedRegion.GetUpperIndex() ) )
541       {
542       // Input requested region is partially outside the largest possible region.
543       //   or
544       // Input requested region is completely inside the largest possible region.
545       inputRequestedRegion.PadByRadius( m_Interpolator->GetRadius() );
546       inputRequestedRegion.Crop( inputLargestRegion );
547       input->SetRequestedRegion( inputRequestedRegion );
548       }
549     else if( inputRequestedRegion.IsInside( inputLargestRegion ) )
550       {
551       // Input requested region completely surrounds the largest possible region.
552       input->SetRequestedRegion( inputLargestRegion );
553       }
554     else
555       {
556       // Input requested region is completely outside the largest possible region. Do not set the requested region in this case.
557       }
558     return;
559     }
560 #endif
561 
562   // Otherwise, determining the actual input region is non-trivial, especially
563   // when we cannot assume anything about the transform being used.
564   // So we do the easy thing and request the entire input image.
565   //
566   input->SetRequestedRegionToLargestPossibleRegion();
567 }
568 
569 template< typename TInputImage,
570           typename TOutputImage,
571           typename TInterpolatorPrecisionType,
572           typename TTransformPrecisionType >
573 void
574 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
GenerateOutputInformation()575 ::GenerateOutputInformation()
576 {
577   // Call the superclass' implementation of this method
578   Superclass::GenerateOutputInformation();
579 
580   // Get pointers to the input and output
581   OutputImageType *outputPtr = this->GetOutput();
582 
583   const ReferenceImageBaseType *referenceImage = this->GetReferenceImage();
584 
585   // Set the size of the output region
586   if ( m_UseReferenceImage && referenceImage )
587     {
588     outputPtr->SetLargestPossibleRegion(
589       referenceImage->GetLargestPossibleRegion() );
590     }
591   else
592     {
593     typename TOutputImage::RegionType outputLargestPossibleRegion;
594     outputLargestPossibleRegion.SetSize(m_Size);
595     outputLargestPossibleRegion.SetIndex(m_OutputStartIndex);
596     outputPtr->SetLargestPossibleRegion(outputLargestPossibleRegion);
597     }
598 
599   // Set spacing and origin
600   if ( m_UseReferenceImage && referenceImage )
601     {
602     outputPtr->SetSpacing( referenceImage->GetSpacing() );
603     outputPtr->SetOrigin( referenceImage->GetOrigin() );
604     outputPtr->SetDirection( referenceImage->GetDirection() );
605     }
606   else
607     {
608     outputPtr->SetSpacing(m_OutputSpacing);
609     outputPtr->SetOrigin(m_OutputOrigin);
610     outputPtr->SetDirection(m_OutputDirection);
611     }
612 }
613 
614 template< typename TInputImage,
615           typename TOutputImage,
616           typename TInterpolatorPrecisionType,
617           typename TTransformPrecisionType >
618 ModifiedTimeType
619 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
GetMTime() const620 ::GetMTime() const
621 {
622   ModifiedTimeType latestTime = Object::GetMTime();
623 
624   if ( m_Interpolator )
625     {
626     if ( latestTime < m_Interpolator->GetMTime() )
627       {
628       latestTime = m_Interpolator->GetMTime();
629       }
630     }
631 
632   return latestTime;
633 }
634 
635 template< typename TInputImage,
636           typename TOutputImage,
637           typename TInterpolatorPrecisionType,
638           typename TTransformPrecisionType >
639 void
640 ResampleImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >
PrintSelf(std::ostream & os,Indent indent) const641 ::PrintSelf(std::ostream & os, Indent indent) const
642 {
643   Superclass::PrintSelf(os, indent);
644 
645   os << indent << "DefaultPixelValue: "
646      << static_cast< typename NumericTraits< PixelType >::PrintType >
647   ( m_DefaultPixelValue )
648      << std::endl;
649   os << indent << "Size: " << m_Size << std::endl;
650   os << indent << "OutputStartIndex: " << m_OutputStartIndex << std::endl;
651   os << indent << "OutputSpacing: " << m_OutputSpacing << std::endl;
652   os << indent << "OutputOrigin: " << m_OutputOrigin << std::endl;
653   os << indent << "OutputDirection: " << m_OutputDirection << std::endl;
654   os << indent << "Transform: " << this->GetTransform() << std::endl;
655   os << indent << "Interpolator: " << m_Interpolator.GetPointer() << std::endl;
656   os << indent << "Extrapolator: " << m_Extrapolator.GetPointer() << std::endl;
657   os << indent << "UseReferenceImage: " << ( m_UseReferenceImage ? "On" : "Off" )
658      << std::endl;
659 }
660 } // end namespace itk
661 
662 #endif
663