/*========================================================================= This code provided as part of Brooks, R., Arbel, T. "Improving the OrientedImage class for use in the Registration Framework", Insight Journal, October, 2007 Author: Rupert Brooks Institution: Centre for Intelligent Machines, McGill University This class based on itkOrientedImage =========================================================================*/ #ifndef __itkFastOrientedImage_h #define __itkFastOrientedImage_h #include "itkOrientedImage.h" #include "itkImageTransformHelper.h" #include "itkNumericTraits.h" #include "itkCovariantVector.h" // can define this to print the name of the function being used // for debugging purposes //#define PRINTFUNCS // cast to integer is really really slow... maybe rewrite in assembly later. #define RealToInt(A) static_cast(A) namespace itk { /** \class FastOrientedImage * \brief Templated n-dimensional oriented image class with optimized Pixel to world * methods for cases that can be computed faster. * * \ingroup ImageObjects */ template class ITK_EXPORT FastOrientedImage : public Image { public: /** Standard class typedefs */ typedef FastOrientedImage Self; typedef Image Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef WeakPointer ConstWeakPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(FastOrientedImage, Image); /** gradient typedef */ typedef typename NumericTraits::RealType RealType; typedef CovariantVector GradientPixelType; /** Index typedef support. An index is used to access pixel values. */ typedef typename Superclass::IndexType IndexType; typedef typename IndexType::IndexValueType IndexValueType; /** Direction typedef support. The direction cosines of the image. */ typedef typename Superclass::DirectionType DirectionType; /** Spacing typedef support. Spacing holds the size of a pixel. The * spacing is the geometric distance between image samples. */ typedef typename Superclass::SpacingType SpacingType; /** Origin typedef support. The origin of the image is a point */ typedef typename Superclass::PointType PointType; typedef typename Superclass::AccessorType AccessorType; typedef typename Superclass::AccessorFunctorType AccessorFunctorType; typedef typename Superclass::IOPixelType IOPixelType; /** Tyepdef for the functor used to access a neighborhood of pixel pointers.*/ typedef NeighborhoodAccessorFunctor< Self > NeighborhoodAccessorFunctorType; /** Return the NeighborhoodAccessor functor. This method is called by the * neighborhood iterators. */ NeighborhoodAccessorFunctorType GetNeighborhoodAccessor() { return NeighborhoodAccessorFunctorType(); } /** Return the NeighborhoodAccessor functor. This method is called by the * neighborhood iterators. */ const NeighborhoodAccessorFunctorType GetNeighborhoodAccessor() const { return NeighborhoodAccessorFunctorType(); } /* Function pointers */ typedef GradientPixelType (Self::*TransformImageGradientToSpatialGradientFunctionPointer)( const GradientPixelType & index ) const; typedef void (Self::*TransformIndexToPhysicalPointFunctionPointer)( const IndexType & index, Point& point ) const; typedef void (Self::*TransformContinuousIndexToPhysicalPointFunctionPointer)( const double * index, Point& point ) const; typedef void (Self::*TransformPhysicalPointToContinuousIndexFunctionPointer)( const Point& point, double* index) const; /** Set which function is to be used to compute pixel space to world space * conversions. This should be called by any function that changes spacing * origin or directions. The set methods for these functions call it already * the user should not have to. */ void SetIndexFunctions(); /** Set the origin of the image and precompute the transforms for * the image. */ virtual void SetOrigin (const PointType origin); virtual void SetOrigin (const double origin[VImageDimension]); virtual void SetOrigin (const float origin[VImageDimension]); /** Set the spacing of the image and precompute the transforms for * the image. */ virtual void SetSpacing (const SpacingType spacing); virtual void SetSpacing (const double spacing[VImageDimension]); virtual void SetSpacing (const float spacing[VImageDimension]); /** Set the direction of the image and precompute the transforms for * the image. */ virtual void SetDirection (const DirectionType direction); /** \brief Transform the gradient from the pixel coordinate system to the * physical coordinate system * */ virtual GradientPixelType TransformImageGradientToSpatialGradient(const GradientPixelType & din) const { return ((*this).*m_SelectedTransformImageGradientToSpatialGradientFunction)(din); } virtual GradientPixelType TransformImageGradientToSpatialGradientGeneric(const GradientPixelType & din) const; virtual GradientPixelType TransformImageGradientToSpatialGradientUD(const GradientPixelType & din) const ; virtual GradientPixelType TransformImageGradientToSpatialGradientDD(const GradientPixelType & din) const ; /** \brief Get the continuous index from a physical point * * Returns true if the resulting index is within the image, false otherwise. * \sa Transform */ #define TPPTCIARGS const Point& point, double* index bool TransformPhysicalPointToContinuousIndex(const Point& point, ContinuousIndex& index ) const { ((*this).*m_SelectedTransformPhysicalPointToContinuousIndexFunction)(point,index.GetDataPointer()); //TransformPhysicalPointToContinuousIndexGeneric(point,index); // Now, check to see if the index is within allowed bounds const bool isInside = this->GetLargestPossibleRegion().IsInside( index ); return isInside; } protected: void TransformPhysicalPointToContinuousIndexGeneric(TPPTCIARGS ) const; void TransformPhysicalPointToContinuousIndexZO(TPPTCIARGS ) const; void TransformPhysicalPointToContinuousIndexDD(TPPTCIARGS ) const; void TransformPhysicalPointToContinuousIndexUD(TPPTCIARGS ) const; void TransformPhysicalPointToContinuousIndexDDZO(TPPTCIARGS ) const; void TransformPhysicalPointToContinuousIndexUDZO(TPPTCIARGS ) const; public: /** Get the index (discrete) from a physical point. * Floating point index results are truncated to integers. * Returns true if the resulting index is within the image, false otherwise * \sa Transform */ bool TransformPhysicalPointToIndex( const Point& point, IndexType & index ) const { // the algorithm is simply to create a continuous index and then cast it anyway //ContinuousIndex rindex; double rindex[VImageDimension]; ((*this).*m_SelectedTransformPhysicalPointToContinuousIndexFunction)(point,rindex); if(VImageDimension>0) { index[0]=RealToInt(rindex[0]); if(VImageDimension>1) { index[1]=RealToInt(rindex[1]); if(VImageDimension>2) { index[2]=RealToInt(rindex[2]); if(VImageDimension>3) { for (unsigned int i = 3 ; i < VImageDimension ; i++) { index[i] = RealToInt(rindex[i]); } } } } } // Now, check to see if the index is within allowed bounds const bool isInside = this->GetLargestPossibleRegion().IsInside( index ); return isInside; } /** Get a physical point (in the space which * the origin and spacing infomation comes from) * from a continuous index (in the index space) * \sa Transform */ #define TCITPPARGS const double * index, Point& point void TransformContinuousIndexToPhysicalPoint(ContinuousIndex& index, Point& point ) const { ((*this).*m_SelectedTransformContinuousIndexToPhysicalPointFunction)(index.GetDataPointer(),point); } protected: void TransformContinuousIndexToPhysicalPointGeneric(TCITPPARGS) const; void TransformContinuousIndexToPhysicalPointZO(TCITPPARGS) const; void TransformContinuousIndexToPhysicalPointDDZO(TCITPPARGS) const ; void TransformContinuousIndexToPhysicalPointDD(TCITPPARGS) const ; void TransformContinuousIndexToPhysicalPointUDZO(TCITPPARGS) const ; void TransformContinuousIndexToPhysicalPointUD(TCITPPARGS) const ; public: /** Get a physical point (in the space which * the origin and spacing infomation comes from) * from a discrete index (in the index space) * * \sa Transform */ #define TITPPARGS const IndexType & index, Point& point void TransformIndexToPhysicalPoint(TITPPARGS ) const { ((*this).*m_SelectedTransformIndexToPhysicalPointFunction)(index,point); } protected: void TransformIndexToPhysicalPointGeneric(TITPPARGS ) const ; void TransformIndexToPhysicalPointZO(TITPPARGS ) const ; void TransformIndexToPhysicalPointDDZO(TITPPARGS ) const ; void TransformIndexToPhysicalPointUDZO(TITPPARGS ) const ; void TransformIndexToPhysicalPointDD(TITPPARGS ) const ; void TransformIndexToPhysicalPointUD(TITPPARGS ) const ; protected: FastOrientedImage(){ m_IndexToPhysicalPoint.SetIdentity(); m_PhysicalPointToIndex.SetIdentity(); m_DirectionInverse.SetIdentity(); m_SelectedTransformImageGradientToSpatialGradientFunction= &Self::TransformImageGradientToSpatialGradientGeneric; m_SelectedTransformIndexToPhysicalPointFunction= &Self::TransformIndexToPhysicalPointGeneric; m_SelectedTransformContinuousIndexToPhysicalPointFunction= &Self::TransformContinuousIndexToPhysicalPointGeneric; m_SelectedTransformPhysicalPointToContinuousIndexFunction= &Self::TransformPhysicalPointToContinuousIndexGeneric; m_ZeroOrigin=false; m_DiagonalDirections=false; m_UnitDirections=false; } TransformImageGradientToSpatialGradientFunctionPointer m_SelectedTransformImageGradientToSpatialGradientFunction; TransformIndexToPhysicalPointFunctionPointer m_SelectedTransformIndexToPhysicalPointFunction; TransformContinuousIndexToPhysicalPointFunctionPointer m_SelectedTransformContinuousIndexToPhysicalPointFunction; TransformPhysicalPointToContinuousIndexFunctionPointer m_SelectedTransformPhysicalPointToContinuousIndexFunction; DirectionType m_IndexToPhysicalPoint; DirectionType m_PhysicalPointToIndex; DirectionType m_DirectionInverse; bool m_ZeroOrigin; bool m_DiagonalDirections; bool m_UnitDirections; virtual ~FastOrientedImage() {}; private: FastOrientedImage(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } // end namespace itk #include "itkFastOrientedImage.txx" // undefine the arguments for the Pixel/world functions lest they cause // problems later #undef TCITPPARGS #undef TITPPARGS #undef TPPTCIARGS // Define instantiation macro for this template. #define ITK_TEMPLATE_FastOrientedImage(_, EXPORT, x, y) namespace itk { \ _(2(class EXPORT FastOrientedImage< ITK_TEMPLATE_2 x >)) \ namespace Templates { typedef Image< ITK_TEMPLATE_2 x > FastOrientedImage##y; } \ } #if ITK_TEMPLATE_EXPLICIT # include "Templates/itkFastOrientedImage+-.h" #endif #endif