From 58f865fc78f497746bf543039fc3d60d7e93d2f1 Mon Sep 17 00:00:00 2001 From: Emmanuel Christophe <emmanuel.christophe@orfeo-toolbox.org> Date: Thu, 5 Mar 2009 10:22:31 +0800 Subject: [PATCH] ENH: makes resample filters more generics (non-optimized filter) --- .../BasicFilters/itkResampleImageFilter.h | 43 +++--- .../BasicFilters/itkResampleImageFilter.txx | 126 ++++++++---------- 2 files changed, 78 insertions(+), 91 deletions(-) diff --git a/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.h b/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.h index 1e23b3de88..bf8b206f20 100644 --- a/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.h +++ b/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.h @@ -9,8 +9,8 @@ Copyright (c) Insight Software Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ @@ -69,7 +69,7 @@ namespace itk * ProcessObject::GenerateInputRequestedRegion() and * ProcessObject::GenerateOutputInformation(). * - * This filter is implemented as a multithreaded filter. It provides a + * This filter is implemented as a multithreaded filter. It provides a * ThreadedGenerateData() method for its implementation. * * \ingroup GeometricTransforms @@ -94,7 +94,7 @@ public: typedef typename InputImageType::RegionType InputImageRegionType; /** Method for creation through the object factory. */ - itkNewMacro(Self); + itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(ResampleImageFilter, ImageToImageFilter); @@ -107,13 +107,14 @@ public: /** Transform typedef. */ - typedef Transform<TInterpolatorPrecisionType, - itkGetStaticConstMacro(ImageDimension), + typedef double CoordRepType; + typedef Transform<CoordRepType, + itkGetStaticConstMacro(ImageDimension), itkGetStaticConstMacro(ImageDimension)> TransformType; typedef typename TransformType::ConstPointer TransformPointerType; /** Interpolator typedef. */ - typedef InterpolateImageFunction<InputImageType, TInterpolatorPrecisionType> InterpolatorType; + typedef InterpolateImageFunction<InputImageType,CoordRepType > InterpolatorType; typedef typename InterpolatorType::Pointer InterpolatorPointerType; /** Image size typedef. */ @@ -129,7 +130,7 @@ public: /** Image pixel value typedef. */ typedef typename TOutputImage::PixelType PixelType; typedef typename TInputImage::PixelType InputPixelType; - + /** Typedef to describe the output image region type. */ typedef typename TOutputImage::RegionType OutputImageRegionType; @@ -137,7 +138,7 @@ public: typedef typename TOutputImage::SpacingType SpacingType; typedef typename TOutputImage::PointType OriginPointType; typedef typename TOutputImage::DirectionType DirectionType; - + /** Set the coordinate transformation. * Set the coordinate transform to use for resampling. Note that this must * be in physical coordinates and it is the output-to-input transform, NOT @@ -145,7 +146,7 @@ public: * the filter uses an Identity transform. You must provide a different * transform here, before attempting to run the filter, if you do not want to * use the default Identity transform. */ - itkSetConstObjectMacro( Transform, TransformType ); + itkSetConstObjectMacro( Transform, TransformType ); /** Get a pointer to the coordinate transform. */ itkGetConstObjectMacro( Transform, TransformType ); @@ -166,7 +167,7 @@ public: /** Get the size of the output image. */ itkGetConstReferenceMacro( Size, SizeType ); - + /** Set the pixel value when a transformed pixel is outside of the * image. The default default pixel value is 0. */ itkSetMacro( DefaultPixelValue, PixelType ); @@ -211,7 +212,7 @@ public: this->SetOutputStartIndex ( Image->GetLargestPossibleRegion().GetIndex() ); this->SetSize ( Image->GetLargestPossibleRegion().GetSize() ); } - /** Set the start index of the output largest possible region. + /** Set the start index of the output largest possible region. * The default is an index of all zeros. */ itkSetMacro( OutputStartIndex, IndexType ); @@ -222,7 +223,7 @@ public: * the information is specified with the SetOutputSpacing, Origin, * and Direction methods. UseReferenceImage must be On and a * Reference image must be present to override the defaul behavior. - * NOTE: This function seems redundant with the + * NOTE: This function seems redundant with the * SetOutputParametersFromImage( image ) function */ void SetReferenceImage ( const TOutputImage *image ); const TOutputImage * GetReferenceImage( void ) const; @@ -245,11 +246,11 @@ public: * \sa ProcessObject::GenerateInputRequestedRegion() */ virtual void GenerateInputRequestedRegion( void ); - /** This method is used to set the state of the filter before + /** This method is used to set the state of the filter before * multi-threading. */ virtual void BeforeThreadedGenerateData( void ); - /** This method is used to set the state of the filter after + /** This method is used to set the state of the filter after * multi-threading. */ virtual void AfterThreadedGenerateData( void ); @@ -286,12 +287,12 @@ protected: int threadId ); /** Implementation for resampling that works for with linear - * transformation types. + * transformation types. */ void LinearThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, int threadId ); - + private: ResampleImageFilter( const Self& ); //purposely not implemented @@ -312,13 +313,13 @@ private: }; - + } // end namespace itk - + #ifndef ITK_MANUAL_INSTANTIATION #include "itkResampleImageFilter.txx" #endif - + #endif - + #endif diff --git a/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.txx b/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.txx index d7c9396899..17777312d8 100644 --- a/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.txx +++ b/Utilities/ITK/Code/BasicFilters/itkResampleImageFilter.txx @@ -9,8 +9,8 @@ Copyright (c) Insight Software Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ @@ -54,9 +54,10 @@ ResampleImageFilter<TInputImage, TOutputImage,TInterpolatorPrecisionType> m_Size.Fill( 0 ); m_OutputStartIndex.Fill( 0 ); - - m_Transform = IdentityTransform<TInterpolatorPrecisionType, ImageDimension>::New(); - m_Interpolator = LinearInterpolateImageFunction<InputImageType, TInterpolatorPrecisionType>::New(); + + typedef double CoordRepType; + m_Transform = IdentityTransform<CoordRepType, ImageDimension>::New(); + m_Interpolator = LinearInterpolateImageFunction<InputImageType, CoordRepType>::New(); m_DefaultPixelValue = 0; } @@ -67,12 +68,12 @@ ResampleImageFilter<TInputImage, TOutputImage,TInterpolatorPrecisionType> * \todo Add details about this class */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage, TOutputImage,TInterpolatorPrecisionType> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); - + os << indent << "DefaultPixelValue: " << static_cast<typename NumericTraits<PixelType>::PrintType>(m_DefaultPixelValue) << std::endl; @@ -91,7 +92,7 @@ ResampleImageFilter<TInputImage, TOutputImage,TInterpolatorPrecisionType> * Set the output image spacing. */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::SetOutputSpacing( const double* spacing) @@ -105,7 +106,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> * Set the output image origin. */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::SetOutputOrigin( const double* origin) @@ -121,7 +122,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> * has to be set up before ThreadedGenerateData */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::BeforeThreadedGenerateData() { @@ -144,7 +145,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> * Set up state of filter after multi-threading. */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::AfterThreadedGenerateData() { @@ -157,7 +158,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> * ThreadedGenerateData */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, @@ -183,7 +184,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> this->NonlinearThreadedGenerateData(outputRegionForThread, threadId); return; } - + // Check whether we can use a fast path for resampling. Fast path // can be used if the transformation is linear. Transform respond // to the IsLinear() call. @@ -196,12 +197,12 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> // Otherwise, we use the normal method where the transform is called // for computing the transformation of every point. this->NonlinearThreadedGenerateData(outputRegionForThread, threadId); - + } template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::NonlinearThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, @@ -223,12 +224,13 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> PointType outputPoint; // Coordinates of current output pixel PointType inputPoint; // Coordinates of current input pixel - typedef ContinuousIndex<TInterpolatorPrecisionType, ImageDimension> ContinuousIndexType; + typedef double CoordRepType; + typedef ContinuousIndex<CoordRepType, ImageDimension> ContinuousIndexType; ContinuousIndexType inputIndex; // Support for progress methods/callbacks ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); - + typedef typename InterpolatorType::OutputType OutputType; // Min/max values of the output pixel type AND these values @@ -238,7 +240,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> const OutputType minOutputValue = static_cast<OutputType>(minValue); const OutputType maxOutputValue = static_cast<OutputType>(maxValue); - + // Walk the output region outIt.GoToBegin(); @@ -258,7 +260,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> inputPtr->TransformPhysicalPointToContinuousIndex(inputPoint, inputIndex); // The inputIndex is precise to many decimal points, but this precision - // involves some error in the last bits. + // involves some error in the last bits. // Sometimes, when an index should be inside of the image, the // index will be slightly // greater than the largest index in the image, like 255.00000000002 @@ -274,25 +276,16 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> double newInputIndexFrac = vcl_floor(precisionConstant * inputIndexFrac)/precisionConstant; inputIndex[i] = roundedInputIndex + newInputIndexFrac; } - + // Evaluate input at right position and copy to the output if( m_Interpolator->IsInsideBuffer(inputIndex) ) { PixelType pixval; const OutputType value = m_Interpolator->EvaluateAtContinuousIndex(inputIndex); - if( value < minOutputValue ) - { - pixval = minValue; - } - else if( value > maxOutputValue ) - { - pixval = maxValue; - } - else - { - pixval = static_cast<PixelType>( value ); - } + pixval = static_cast<PixelType>( + NumericTraits<OutputType>::Clamp(value,minOutputValue,maxOutputValue) + ); outIt.Set( pixval ); } else @@ -308,7 +301,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> } template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::LinearThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, @@ -333,17 +326,18 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> PointType tmpOutputPoint; PointType tmpInputPoint; - typedef ContinuousIndex<TInterpolatorPrecisionType, ImageDimension> ContinuousIndexType; + typedef double CoordRepType; + typedef ContinuousIndex<CoordRepType, ImageDimension> ContinuousIndexType; ContinuousIndexType inputIndex; ContinuousIndexType tmpInputIndex; - + typedef typename PointType::VectorType VectorType; VectorType delta; // delta in input continuous index coordinate frame IndexType index; // Support for progress methods/callbacks ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); - + typedef typename InterpolatorType::OutputType OutputType; // Cache information from the superclass @@ -356,34 +350,34 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> const OutputType minOutputValue = static_cast<OutputType>(minValue); const OutputType maxOutputValue = static_cast<OutputType>(maxValue); - - + + // Determine the position of the first pixel in the scanline index = outIt.GetIndex(); outputPtr->TransformIndexToPhysicalPoint( index, outputPoint ); - + // Compute corresponding input pixel position inputPoint = m_Transform->TransformPoint(outputPoint); inputPtr->TransformPhysicalPointToContinuousIndex(inputPoint, inputIndex); - + // As we walk across a scan line in the output image, we trace // an oriented/scaled/translated line in the input image. Cache // the delta along this line in continuous index space of the input // image. This allows us to use vector addition to model the // transformation. // - // To find delta, we take two pixels adjacent in a scanline - // and determine the continuous indices of these pixels when + // To find delta, we take two pixels adjacent in a scanline + // and determine the continuous indices of these pixels when // mapped to the input coordinate frame. We use the difference // between these two continuous indices as the delta to apply - // to an index to trace line in the input image as we move + // to an index to trace line in the input image as we move // across the scanline of the output image. // // We determine delta in this manner so that Images and // OrientedImages are both handled properly (with the delta for // OrientedImages taking into account the direction cosines). - // + // ++index[0]; outputPtr->TransformIndexToPhysicalPoint( index, tmpOutputPoint ); tmpInputPoint = m_Transform->TransformPoint( tmpOutputPoint ); @@ -432,7 +426,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> // will incremented in the scanline loop inputPoint = m_Transform->TransformPoint(outputPoint); inputPtr->TransformPhysicalPointToContinuousIndex(inputPoint, inputIndex); - + // The inputIndex is precise to many decimal points, but this precision // involves some error in the last bits. // Sometimes, when an index should be inside of the image, the @@ -460,25 +454,17 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> PixelType pixval; const OutputType value = m_Interpolator->EvaluateAtContinuousIndex(inputIndex); - if( value < minOutputValue ) - { - pixval = minValue; - } - else if( value > maxOutputValue ) - { - pixval = maxValue; - } - else - { - pixval = static_cast<PixelType>( value ); - } + + pixval = static_cast<PixelType>( + NumericTraits<OutputType>::Clamp(value,minOutputValue,maxOutputValue) + ); outIt.Set( pixval ); } else { outIt.Set(defaultValue); // default background value } - + progress.CompletedPixel(); ++outIt; inputIndex += delta; @@ -490,7 +476,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> } -/** +/** * Inform pipeline of necessary input image region * * Determining the actual input region is non-trivial, especially @@ -498,7 +484,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> * So we do the easy thing and request the entire input image. */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::GenerateInputRequestedRegion() { @@ -511,7 +497,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> } // get pointers to the input and output - InputImagePointer inputPtr = + InputImagePointer inputPtr = const_cast< TInputImage *>( this->GetInput() ); // Request the entire input image @@ -523,7 +509,7 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> } -/** +/** * Set the smart pointer to the reference image that will provide * the grid parameters for the output image. */ @@ -533,18 +519,18 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::GetReferenceImage() const { Self * surrogate = const_cast< Self * >( this ); - const OutputImageType * referenceImage = + const OutputImageType * referenceImage = static_cast<const OutputImageType *>(surrogate->ProcessObject::GetInput(1)); return referenceImage; } -/** +/** * Set the smart pointer to the reference image that will provide * the grid parameters for the output image. */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::SetReferenceImage( const TOutputImage *image ) { @@ -556,11 +542,11 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> } } -/** +/** * Inform pipeline of required output region */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -void +void ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::GenerateOutputInformation() { @@ -605,15 +591,15 @@ ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> return; } -/** +/** * Verify if any of the components has been modified. */ template <class TInputImage, class TOutputImage, class TInterpolatorPrecisionType> -unsigned long +unsigned long ResampleImageFilter<TInputImage,TOutputImage,TInterpolatorPrecisionType> ::GetMTime( void ) const { - unsigned long latestTime = Object::GetMTime(); + unsigned long latestTime = Object::GetMTime(); if( m_Transform ) { -- GitLab