ITK Release 4/Image Class Hierarchy Refactoring: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
 
(183 intermediate revisions by 2 users not shown)
Line 1: Line 1:
= Image Class Hierarchy Refactoring =


== Image Class Hierarchy Refactoring ==
The goal of this proposal is to refactor ITK's image class hierarchy to make adding other image types to ITK easier and to simplify the interface of image classes wherever possible.


= Motivation =
== Motivation ==
 
The goal of this proposal is to add support for additional image types in ITK.


ITK currently supports several types of image:
ITK currently supports several types of image:
Line 12: Line 11:
** [http://www.itk.org/Doxygen320/html/classitk_1_1PhasedArray3DSpecialCoordinatesImage.html PhasedArray3DSpecialCoordinatesImage]
** [http://www.itk.org/Doxygen320/html/classitk_1_1PhasedArray3DSpecialCoordinatesImage.html PhasedArray3DSpecialCoordinatesImage]
* [http://www.itk.org/Doxygen320/html/classitk_1_1BloxImage.html BloxImage]
* [http://www.itk.org/Doxygen320/html/classitk_1_1BloxImage.html BloxImage]
** [http://www.itk.org/Doxygen320/html/classitk_1_1BloxCoreAtomImage.html BloxCoreAtomImage]
** [http://www.itk.org/Doxygen320/html/classitk_1_1BloxBoundaryProfileImage.html BloxBoundaryProfileImage]
** [http://www.itk.org/Doxygen320/html/classitk_1_1BloxBoundaryPointImage.html BloxBoundaryPointImage]
* [http://www.itk.org/Doxygen320/html/classitk_1_1SparseImage.html SparseImage]
* [http://www.itk.org/Doxygen320/html/classitk_1_1SparseImage.html SparseImage]
* [http://www.itk.org/Doxygen320/html/classitk_1_1LabelMap.html LabelMap]
* [http://www.itk.org/Doxygen320/html/classitk_1_1LabelMap.html LabelMap]
* [http://www.itk.org/Doxygen320/html/classitk_1_1ImageAdaptor.html ImageAdaptors] and subclasses
* [http://www.itk.org/Doxygen320/html/classitk_1_1ImageAdaptor.html ImageAdaptors] and subclasses
* [http://www.insight-journal.org/browse/publication/646 Slice contiguous, sparse, and single-bit binary images] - Insight Journal article from Dan Mueller


With the exception of the PhasedArray3DSpecialCoordinatesImage, all the image types assume that the image topology is an n-dimensional lattice and that voxels have regular spacing in each dimension. While it makes sense to preserve the topology assumption in this refactoring, the assumption of regular spacing should be relaxed wherever possible. The regular spacing assumption covers many cases in biomedical imaging, but it hinders ITK's use in certain applications such as microscopy and remote sensing images. For example, certain motorized stages used in confocal microscopes fail to achieve regular spacing in z when acquiring a 3D image (often called a stack of 2D images at different focal depths). Helpfully, these stages report the positions of z-planes acquired during image stack collection. Assuming a regular z-spacing in place of the actual z-plane positions may result in significant errors in image analysis algorithms run on the image.
Most of the image types supported by ITK assume that the image topology is an n-dimensional lattice and that voxels have regular physical spacing in each dimension. While it makes sense to preserve the topology assumption in a library focused on image analysis, the regular spacing assumption should be relaxed wherever possible. The regular spacing assumption covers many cases in biomedical imaging, but it is insufficient for certain types of images in other applications. For example, certain motorized stages used in fluorescence microscopes fail to achieve regular spacing in z when acquiring a 3D image. Helpfully, these stages report the positions of z-planes acquired during image stack collection. Assuming a regular z-spacing in place of the actual z-plane positions may result in significant errors in image analysis algorithms run on the image.


In particular, this proposal aims to provide several new kinds of image classes:
It is possible to create image types in ITK that do not assume regular spacing: [http://www.itk.org/Doxygen320/html/classitk_1_1PhasedArray3DSpecialCoordinatesImage.html PhasedArray3DSpecialCoordinatesImage] is an example. Nevertheless, its interface still has the SetSpacing() and GetSpacing() methods defined in the ImageBase class (and overriden in SpecialCoordinatesImage). These methods are required for compatibility in filter pipelines, but their presence in this class is misleading; they do nothing. Other types of images may consist of samples not associated with a physical space. For these image types, class methods for setting metadata about the physical embedding of the image are not needed.


* Digital Image
== Goals ==


* Regular Image
The primary goal in this refactoring is to produce a logical image class hierarchy in ITK that removes methods in image types where they are not needed.


* Rectilinear Image
The secondary goal is to add a RectilinearImage class, a physically embedded image with origin, irregular spacing in each dimension, and orientation.


= Goals =
== Requirements ==


= Secondary Goals =
* Make changes fully backwards compatible with examples and tests (all examples and tests should compile and run without modification and all tests should pass)
* Each of the physically embedded image types will properly calculate transforms from indices to physical coordinates and back.
* All physically embedded images should support orientations.
* ImageAdaptors should work on all image types
* Resampling should be supported for all physically embedded image types
* Conversion of new image types to appropriate VTK classes for visualization
 
== Challenges and Potential Pitfalls ==
 
* ImageAdaptors should present the correct interface for the image type they adapt. This can be accomplished with partial template specialization of the ImageAdaptor class to avoid modifying any of the existing adaptors.
* Numerous classes use regular spacing of images (they call GetSpacing()) directly and will need to be modified to handle the new image types or be restricted to work with only image types with regular sample spacing. A list of these classes can be found at the appendix at the end of this page.
* Filters that require voxel positions should ideally use methods TransformIndexToPhysicalPoint, etc., but this may not be optimal for performance.
* Adding image types will add significant compilation time to wrapping


= Design =
= Design =
ImageBase will be stripped to the bare minimum functionality required to support images with lattice topology. Other image types will have more specialized base classes, all descended (perhaps indirectly) from ImageBase. The base classes will provide support for additional image metadata.
== Class Hierarchy ==
The class hierarchy will look like this:
* ImageBase< unsigned int VDimension >
** PhysicalImageBase< unsigned int VDimension >
*** RegularImageBase< unsigned int VDimension >
**** Image< class TPixel, unsigned int VDimension >
***** BloxImage< class TPixel, unsigned int VDimension >
****** BloxImage subclasses
***** SparseImage< class TNode, unsigned int VDimension >
**** VectorImage< class TPixel, unsigned int VDimension >
**** LabelMap< class TPixel, unsigned int VDimension >
*** RectilinearImageBase < unsigned int VDimension >
**** RectilinearImage <class TPixel, unsigned in VDimension >
*** PhasedArray3DSpecialCoordinatesImage< class TPixel >
All base image classes specify the interface for only the metadata of the image. This design is required to support the method CopyInformation(). For example, you may encounter a situation where you copy information from a RectilinearImage<float, 3> to a RectilinearImage<double, 3>. Dynamic casting from a RectilinearImage<float, 3> to a RectilinearImage<double, 3> won't work, so the method will throw an exception. Casting a RectilinearImage<float, 3> to a RectilinearImageBase< 3 > will work, enabling access to the metadata methods (GetSpacing(), GetOrigin(), etc.) from the source image.
Specific methods defined or overridden in each class are provided below.
=== Class Diagram ===
<graphviz>
digraph G {
ImageBase
PhysicalImageBase
RegularImageBase
Image [shape=box];
BloxImage [shape=box];
BloxImageDerived [shape=box];
LabelMap [shape=box];
VectorImage [shape=box];
RectilinearImage [shape=box];
SparseImage [shape=box];
PhasedArray3DSpecialCoordinatesImage [shape=box];
ImageBase -> PhysicalImageBase
PhysicalImageBase -> RegularImageBase
RegularImageBase -> Image
Image -> BloxImage
BloxImage -> BloxImageDerived
Image -> SparseImage
RegularImageBase -> VectorImage
RegularImageBase -> LabelMap
PhysicalImageBase -> RectilinearImageBase
RectilinearImageBase -> RectilinearImage
PhysicalImageBase -> PhasedArray3DSpecialCoordinatesImage
}
</graphviz>
== Image Types ==
=== ImageBase ===
Methods:
* Allocate()
* ComputeIndex()
* ComputeOffset()
* ComputeOffsetTable()
* CopyInformation()
* GetBufferedRegion()
* GetImageDimension()
* GetLargestPossibleRegion()
* GetNumberOfComponentsPerPixel()
* GetOffsetTable()
* GetRequestedRegion()
* Graft()
* Initialize()
* InitializeBufferedRegion()
* RequestedRegionIsOutsideOfTheBufferedRegion()
* SetBufferedRegion()
* SetLargestPossibleRegion()
* SetNumberOfComponentsPerPixel()
* SetRequestedRegion(const RegionType &region)
* SetRequestedRegion(DataObject *data)
* SetRequestedRegionToLargestPossibleRegion()
* UpdateOutputData()
* UpdateOutputInformation()
=== PhysicalImageBase ===
Methods overridden from ImageBase
* CopyInformation()
Additional methods
* GetOrigin()
* SetOrigin()
* GetDirection()
* SetDirection()
=== RegularImageBase ===
Methods overridden from PhysicalImageBase
* CopyInformation()
Additional methods
* ComputeIndexToPhysicalPointMatrices()
* GetSpacing()
* SetSpacing()
* TransformContinuousIndexToPhysicalPoint(const ContinuousIndex< TCoordRep, VImageDimension > &index, Point< TCoordRep, VImageDimension > &point) const
* TransformIndexToPhysicalPoint(const IndexType &index, Point< TCoordRep, VImageDimension > &point) const
* TransformLocalVectorToPhysicalVector(const FixedArray< TCoordRep, VImageDimension > &inputGradient, FixedArray< TCoordRep, VImageDimension > &outputGradient) const
* TransformPhysicalPointToContinuousIndex(const Point< TCoordRep, VImageDimension > &point, ContinuousIndex< TCoordRep, VImageDimension > &index) const
* TransformPhysicalPointToIndex(const Point< TCoordRep, VImageDimension > &point, IndexType &index) const
=== Image (subclass of itkRegularImageBase) ===
Methods overridden from RegularImageBase
* Allocate()
* Graft()
* Initialize()
Additional methods
* operator[]
* FillBuffer()
* GetBufferPointer()
* GetNeighborhoodAccessor()
* GetPixel(const IndexType &index) const
* GetPixel(const IndexType &index)
* GetPixelAccessor(void)
* GetPixelAccessor(void) const
* GetPixelContainer()
* GetPixelContainer() const
* SetNeighborhoodAccessor()
* SetPixel(const IndexType &index, const TPixel &value)
* SetPixelContainer(PixelContainer *container)
=== RectilinearImageBase ===
Methods overridden from PhysicalImageBase
* CopyInformation()
* SetLargestPossibleRegion()
Additional methods
* ComputeSpacingPrefixSum()
* GetDefaultSpacing()
* GetDimensionSpacing(unsigned int dimension)
* InitializeWithDefaultSpacings()
* SetDefaultSpacing()
* SetSpacing(unsigned int dimension, long index, Array<PointValueType>)
* TransformContinuousIndexToPhysicalPoint(const ContinuousIndex< TCoordRep, VImageDimension > &index, Point< TCoordRep, VImageDimension > &point) const
* TransformIndexToPhysicalPoint(const IndexType &index, Point< TCoordRep, VImageDimension > &point) const
* TransformLocalVectorToPhysicalVector(const FixedArray< TCoordRep, VImageDimension > &inputGradient, FixedArray< TCoordRep, VImageDimension > &outputGradient) const
* TransformPhysicalPointToContinuousIndex(const Point< TCoordRep, VImageDimension > &point, ContinuousIndex< TCoordRep, VImageDimension > &index) const
* TransformPhysicalPointToIndex(const Point< TCoordRep, VImageDimension > &point, IndexType &index) const
=== RectilinearImage ===
Methods overridden from RectilinearImageBase
* Allocate()
* Graft()
* Initialize()
Additional methods
* operator[]
* FillBuffer()
* GetBufferPointer()
* GetPixel(const IndexType &index) const
* GetPixel(const IndexType &index)
* GetPixelAccessor(void)
* GetPixelAccessor(void) const
* GetPixelContainer()
* GetPixelContainer() const
* GetNeighborhoodAccessor()
* GetNeighborhoodAccessor() const
* SetPixel(const IndexType &index, const TPixel &value)
* SetPixelContainer(PixelContainer *container)
=== LabelMap ===
No change needed, but the new interface will not have the methods:
* GetDirection()
* GetSpacing()
* SetDirection()
* SetSpacing()
If LabelMaps have a physical embedding, then the LabelMap class should be changed to inherit from PhysicalImageBase.
=== BloxImage ===
This class currently descends from Image. If it has no spatial embedding, then it could be changed to descend from a new DigitalImage class.
=== SparseImage ===
This class currently descends from Image. If it has no spatial embedding, then it could be changed to descend from a new DigitalImage class.
== ImageAdaptors ==
The ImageAdaptor class should be designed to present the proper API for each of the new image types. This requires partial template specialization of the ImageAdaptor template class to maintain backwards compatibility. Specifically, several definitions of the ImageAdaptor class will need to be defined, one for each image type.
To work with the CopyInformation() method in the various Image subclasses, each ImageBase type (RegularImageBase, RectilinearImageBase, etc.) will need to have a corresponding ImageAdaptor type (RegularImageAdaptor, RectilinearImageAdaptor, etc.), each of which is a subclass of its corresponding image base type. They CANNOT be subclasses of the image types with pixel containers because of the problem with dynamic casting in the CopyInformation() method mentioned above.
== ResampleImageFilter and WarpImageFilter ==
The method SetOutputParametersFromImage() takes an ImageBase as input. Now that the metadata is stored in subclasses of ImageBase, this may be suboptimal.
One solution is to try to dynamic_cast the ImageBase input to the various descendants of ImageBase (PhysicalImageBase, RegularImageBase, RectilinearImageBase, etc.). Upon successful casting, the relevant parameters from the ImageBase input can be copied over to the filter. However, say we're resampling to a RectilinearImage with the ResampleImageFilter. The ResampleImageFilter would need to have a method to support individual voxel spacings. But this method isn't needed for resampling to an Image, so it would go to waste.
Alternatively, these classes could be specialized for the output image type much like the ImageAdaptor is specialized. This seems like the best option.
== Outstanding Questions ==
* Are BloxImages and SparseImages physically embedded images?
* Should image sources be specialized for different image types?
* Will interpolators work out-of-the-box for Images with implementations of TransformIndexToPhysicalPoint, etc?
* File readers?
* Use concept checking in filters and image sources to check support for input/output image types?


= Implementation Plan =
= Implementation Plan =
After all phases of implementation, existing tests must compile and pass.
A sample implementation encompassing phases 1-3 is available at [http://github.com/cquammen/ITK/tree/image-hierarchy-refactoring GitHub].
== Phase 1 ==
* Implement PhysicalImageBase< unsigned int VDimension >
* Implement RegularImageBase
* Make Image and VectorImage subclasses of RegularImageBase
* Make SpecialCoordinatesImage a subclass of RegularImageBase
'''Example implementation complete'''
== Phase 2 ==
* Write RegularImageAdaptor
* Specialize the ImageAdaptor template for Image, VectorImage, and PhasedArray3DSpecialCoordinatesImage classes.
* Remove unnecessary methods from adaptor classes.
* Remove unnecessary methods, typedefs, and member variables from ImageBase, PhysicalImageBase, and RegularImageBase.
'''Example implementation complete'''
== Phase 3 ==
* Implement RectilinearImageBase and RectilinearImage
* Specialize the ImageAdaptor template for RectilinearImages
* Add example tests for rectilinear images
'''Example implementation complete'''
== Phase 4 ==
* Specialize ResampleImageFilter
* Specialize WarpImageFilter
= Participants =
* Cory Quammen (UNC Chapel Hill)
= Appendix: Classes that use Regular Spacing of Images =
== Algorithms ==
** Algorithms/itkBinaryMask3DMeshSource.txx
*** Should be easily modified to use TransformIndexToPhysicalPoint
** Algorithms/itkCollidingFrontsImageFilter.txx
*** GetSpacing() required by FastMarchingUpwindGradientImageFilter->GetOutputSpacing()
** Algorithms/itkDeformableSimplexMesh3DGradientConstraintForceFilter.txx
*** Should be easily modified to use TransformIndexToPhysicalPoint
** Algorithms/itkDemonsRegistrationFunction.txx
*** Should be able to calculate m_Normalizer by getting the volume of a voxel
** Algorithms/itkFastMarchingImageFilter.txx
*** ?
** Algorithms/itkFastMarchingUpwindGradientImageFilter.txx
*** Spacing in finite difference calculation should be replaceable by more general image spacing; images with curvilinear coordinate systems won't work
** Algorithms/itkFastSymmetricForcesDemonsRegistrationFunction.txx
*** Should be able to calculate m_Normalizer by getting the volume of a voxel
** Algorithms/itkFEMRegistrationFilter.txx
*** Spacing is passed to WarpImageFilter; could be resolved by calling SetOutputParametersFromImage()
** Algorithms/itkGradientDifferenceImageToImageMetric.txx
*** Spacing is passed to ResampleImageFilter; could be resolved by calling SetOutputParametersFromImage()
** Algorithms/itkImageToImageMetric.txx
*** Uses the largest voxel size as the sigma in an internal gradient filter
** Algorithms/itkIsoContourDistanceImageFilter.txx
*** ?
** Algorithms/itkKLMRegionGrowImageFilter.txx
*** Uses spacing to compute region border lengths; could be replaced with a method in an image class
** Algorithms/itkLevelSetMotionRegistrationFunction.txx
*** Uses spacing for forward difference calculation
** Algorithms/itkMeanSquareRegistrationFunction.txx
*** ?
** Algorithms/itkMultiResolutionPDEDeformableRegistration.txx
*** ?
** Algorithms/itkMultiResolutionPyramidImageFilter.txx
*** Sets spacing of output images at each level; it seems unlikely to want to generate irregular images for a multi-resolution pyramid
** Algorithms/itkNCCRegistrationFunction.txx;
*** Uses spacings in computing the gradient squared magnitude for the fixed image
** Algorithms/itkPDEDeformableRegistrationFilter.txx
*** Forwards spacing from output to a temporary deformation field
** Algorithms/itkPointSetToImageMetric.txx
*** Uses the largest voxel size as the sigma in an internal gradient filter
** Algorithms/itkRayCastInterpolateImageFunction.txx
*** This class is heavily tied to the assumption of regular spacing
** Algorithms/itkReinitializeLevelSetImageFilter.txx
*** Forwards spacing from input image to the FastMarchingImageFilterType
** Algorithms/itkSymmetricForcesDemonsRegistrationFunction.txx
*** Should be able to calculate m_Normalizer by getting the volume of a voxel
== BasicFilters ==
** BasicFilters/itkAccumulateImageFilter.txx
*** Essentially forwards the spacing to the output, except for the collapsed dimension which has the spacing set to the size of the original image in the collapsed dimension
** BasicFilters/itkAnisotropicDiffusionImageFilter.txx
*** Uses spacing to determine a timestep that produces stable solutions
** BasicFilters/itkBilateralImageFilter.txx
*** ?
** BasicFilters/itkBSplineDownsampleImageFilter.txx
*** Output image spacing is twice that of the input; should be able to do something for images with non-regular spacing
** BasicFilters/itkBSplineInterpolateImageFunction.txx
*** Used in derivative calculation
** BasicFilters/itkBSplineUpsampleImageFilter.txx
*** Output image spacing is half that of the input; should be able to do something for images with non-regular spacing
** BasicFilters/itkChangeInformationImageFilter.txx
*** Should probably have a special ChangeInformationImageFilter for other image types
** BasicFilters/itkDanielssonDistanceMapImageFilter.txx
*** ?
** BasicFilters/itkDerivativeImageFilter.txx
*** Used for scaling coefficient in DerivativeOperator; this may not work well for images with irregular spacing
** BasicFilters/itkDiscreteGaussianImageFilter.txx
*** Depends on GaussianOperator supporting irregular spacing
** BasicFilters/itkDisplacementFieldJacobianDeterminantFilter.txx
*** Used in m_DerivativeWeights and m_HalfDerivativeWeights, which themselves don't seem to be used anywhere
** BasicFilters/itkExpandImageFilter.txx
*** Should be straightforward to implement for images of irregular spacing
** BasicFilters/itkExtractImageFilter.txx
*** Should be straightforward to implement for images of irregular spacing
** BasicFilters/itkGradientImageFilter.txx
*** Depends on DerivativeOperator supporting irregular spacing
** BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx
*** Sets output image spacing to multiple of the input image spacing
** BasicFilters/itkGradientMagnitudeImageFilter.txx
*** Depends on DerivativeOperator supporting irregular spacing
** BasicFilters/itkGradientMagnitudeRecursiveGaussianImageFilter.txx
*** ?
** BasicFilters/itkGradientRecursiveGaussianImageFilter.txx
*** Spacing used to divide output scalar values
** BasicFilters/itkHessianRecursiveGaussianImageFilter.txx
*** Used to normalize output values
** BasicFilters/itkHoughTransform2DCirclesImageFilter.txx
*** Forwards spacing from input image to radius image
** BasicFilters/itkHoughTransform2DLinesImageFilter.txx
*** Forwards spacing from input image to m_SimplifyAccumulator image
** BasicFilters/itkImportImageFilter.h
*** Would need to write a version for images with irregular spacing
** BasicFilters/itkInterpolateImagePointsFilter.txx
*** Spacing of the image specifying the x-coordinates of the interpolation points is used as the spacing of the output image; this is rather arbitrary as the output image sample coordinates are arbitrary
** BasicFilters/itkInverseDeformationFieldImageFilter.txx
*** A scale factor of the input image spacing is used as the output image spacing
** BasicFilters/itkIterativeInverseDeformationFieldImageFilter.txx
*** Sets output spacing to that of the input image
** BasicFilters/itkJoinSeriesImageFilter.txx
*** Spacing of new dimension is set by the filter; this would have to be an array of spacings for a RectilinearImage
** BasicFilters/itkLaplacianImageFilter.txx
*** Depends on LaplacianOperator supporting irregular spacing
** BasicFilters/itkLaplacianRecursiveGaussianImageFilter.txx
*** Uses spacing as normalizer
** BasicFilters/itkLaplacianSharpeningImageFilter.txx
*** Depends on LaplacianOperator supporting irregular spacing
** BasicFilters/itkParallelSparseFieldLevelSetImageFilter.txx
*** ?
** BasicFilters/itkPermuteAxesImageFilter.txx
*** Forwards spacing of input image to the output image
** BasicFilters/itkPolylineMask2DImageFilter.txx
*** Forwards spacing from input to output image
** BasicFilters/itkPolylineMaskImageFilter.txx
*** Forwards spacing from input to output image
** BasicFilters/itkProjectionImageFilter.txx
*** Forwards spacing from input to output image
** BasicFilters/itkRecursiveSeparableImageFilter.txx
*** Regular spacing assumption is encoded as a parameter in the SetUp pure virtual method
** BasicFilters/itkRelabelComponentImageFilter.txx
*** Spacing used to compute volume of voxels
** BasicFilters/itkResampleImageFilter.txx
*** Discussed in more detail below
** BasicFilters/itkShrinkImageFilter.txx
*** Filter shrinks an image to an integer multiple of the original image size
** BasicFilters/itkSignedMaurerDistanceMapImageFilter.txx
*** Uses spacing to map index of voxel position to physical space
** BasicFilters/itkSparseFieldLevelSetImageFilter.txx
*** ?
** BasicFilters/itkSpatialObjectToImageStatisticsCalculator.txx
*** Used to remove spacing considerations from an internal FloodFill iterator
** BasicFilters/itkTileImageFilter.txx
*** Forwards spacing from input to output image
** BasicFilters/itkTriangleMeshToBinaryImageFilter.txx
*** Generates image with a given spacing
** BasicFilters/itkUnaryFunctorImageFilter.txx
*** Forwards spacing from input to output image
** BasicFilters/itkVectorExpandImageFilter.txx
*** Output image spacing is an integer multiple of input image spacing
** BasicFilters/itkVectorGradientMagnitudeImageFilter.txx
*** Spacing used as derivative weights
** BasicFilters/itkWarpImageFilter.txx
*** See discussion below
== Common ==
** Common/itkAnnulusOperator.h
*** Uses spacing to ensure annulus is spherical
** Common/itkBSplineDeformableTransform.txx
*** Used to set the coefficient grid spacing
** Common/itkCentralDifferenceImageFunction.txx
*** Used in finite difference calculation
** Common/itkDenseFiniteDifferenceImageFilter.txx
*** Used to set spacing of output image
** Common/itkFiniteDifferenceImageFilter.txx
*** Spacing used in finite difference coefficients
** Common/itkFloodFilledFunctionConditionalConstIterator.txx
*** Not clear where the spacing is used.
** Common/itkGaussianBlurImageFunction.txx
*** Depends on irregular spacing support in GaussianOperator
** Common/itkGaussianDerivativeImageFunction.txx
*** Depends on irregular spacing support in GaussianOperator
** Common/itkImageDuplicator.txx
*** Forwards spacing of input image to output image
** Common/itkPathConstIterator.txx
*** Not clear where the spacing is used.
== IO ==
** IO/itkGDCMImageIO.cxx
*** Sets spacing from image
** IO/itkImageFileReader.txx
*** Sets spacing from image
** IO/itkImageFileWriter.txx
*** Writes spacing to file
** IO/itkImageIOBase.h
*** Spacing goes to/comes from image file
** IO/itkImageSeriesReader.txx
*** Produces regular image
** IO/itkImageSeriesWriter.txx
*** Geared to images with regular spacing
** IO/itkMetaImageIO.cxx
*** Geared to images with regular spacing
** IO/itkNiftiImageIO.cxx
*** Geared to images with regular spacing
** IO/itkNrrdImageIO.cxx
*** Geared to images with regular spacing
== Numerics ==
** Numerics/Statistics/itkHistogramToImageFilter.h
*** Sets size of output image
== Review ==
** Review/itkAreaClosingImageFilter.h
*** Can optionally use spacing to compute area.
** Review/itkAreaOpeningImageFilter.h
*** Can optionally use spacing to compute area.
** Review/itkBSplineDeformableTransformInitializer.txx
*** Uses image spacing to calculate grid spacing
** Review/itkBSplineScatteredDataPointSetToImageFilter.txx
*** ?
** Review/itkConstrainedRegionBasedLevelSetFunctionSharedData.h
*** Spacing used to determine query points
** Review/itkDiffeomorphicDemonsRegistrationFilter.txx
*** Sets output spacing to that of input
** Review/itkDirectFourierReconstructionImageToImageFilter.txx
*** Spacing of output image set from input image
** Review/itkDiscreteGaussianDerivativeImageFilter.txx
*** Depends on GaussianDerivativeOperator
** Review/itkDiscreteGaussianDerivativeImageFunction.txx
*** Depends on GaussianDerivativeOperator
** Review/itkDiscreteGradientMagnitudeGaussianImageFunction.txx
*** Depends on GaussianDerivativeOperator
** Review/itkDiscreteHessianGaussianImageFunction.txx
*** Used by NeighborhoodOperatorImageFunction
** Review/itkESMDemonsRegistrationFunction.txx
*** Spacing is used to computer normalizer
** Review/itkExponentialDeformationFieldImageFilter.txx
*** Used to calculate number of iterations
** Review/itkFastSymmetricForcesDemonsRegistrationFilter.txx
*** Copies input spacing to output image
** Review/itkGaborImageSource.txx
*** User sets spacing
** Review/itkGridForwardWarpImageFilter.txx
*** Copies input spacing to output image
** Review/itkGridImageSource.txx
*** User sets spacing
** Review/itkJPEG2000ImageIO.cxx
*** Produces regular images
** Review/itkLabelGeometryImageFilter.txx
*** Copies input spacing to output spacing
** Review/itkLabelPerimeterEstimationCalculator.txx
*** Uses spacing to compute physical size of voxels
** Review/itkMINC2ImageIO.cxx
*** Produces regular images
** Review/itkMultiphaseFiniteDifferenceImageFilter.txx
*** Spacing used for scale coefficients  in the difference functions
** Review/itkMultiphaseSparseFiniteDifferenceImageFilter.txx
*** ?
** Review/itkRegionBasedLevelSetFunction.h
*** Spacing used in gradient computation
** Review/itkShapedFloodFilledFunctionConditionalConstIterator.txx
*** ?
** Review/itkShapeLabelMapFilter.txx
*** Spacing used for physical volume measurements
** Review/itkStatisticsLabelMapFilter.txx
*** Used for statistics of physical dimensions of voxels
** Review/itkStochasticFractalDimensionImageFilter.txx
*** ?
** Review/itkStreamingImageIOBase.cxx
*** Produces images with regular spacing
** Review/itkTransformToDeformationFieldSource.txx
*** Can optionally use spacing from reference image
** Review/itkVectorCentralDifferenceImageFunction.txx
*** Used in derivative weights
** Review/itkVTKImageIO2.cxx
*** Produces images with regular spacing
** Review/itkWarpHarmonicEnergyCalculator.txx
*** Used in derivative weights
== Spatial Object ==
** SpatialObject/itkImageSpatialObject.txx
*** spacing doesn't seem to be used
** SpatialObject/itkMetaImageConverter.txx
*** Spacing is set on the metaimage.
** SpatialObject/itkSpatialObject.h
*** spacing is essentially a geometric scaling factor

Latest revision as of 18:32, 16 October 2010

Image Class Hierarchy Refactoring

The goal of this proposal is to refactor ITK's image class hierarchy to make adding other image types to ITK easier and to simplify the interface of image classes wherever possible.

Motivation

ITK currently supports several types of image:

Most of the image types supported by ITK assume that the image topology is an n-dimensional lattice and that voxels have regular physical spacing in each dimension. While it makes sense to preserve the topology assumption in a library focused on image analysis, the regular spacing assumption should be relaxed wherever possible. The regular spacing assumption covers many cases in biomedical imaging, but it is insufficient for certain types of images in other applications. For example, certain motorized stages used in fluorescence microscopes fail to achieve regular spacing in z when acquiring a 3D image. Helpfully, these stages report the positions of z-planes acquired during image stack collection. Assuming a regular z-spacing in place of the actual z-plane positions may result in significant errors in image analysis algorithms run on the image.

It is possible to create image types in ITK that do not assume regular spacing: PhasedArray3DSpecialCoordinatesImage is an example. Nevertheless, its interface still has the SetSpacing() and GetSpacing() methods defined in the ImageBase class (and overriden in SpecialCoordinatesImage). These methods are required for compatibility in filter pipelines, but their presence in this class is misleading; they do nothing. Other types of images may consist of samples not associated with a physical space. For these image types, class methods for setting metadata about the physical embedding of the image are not needed.

Goals

The primary goal in this refactoring is to produce a logical image class hierarchy in ITK that removes methods in image types where they are not needed.

The secondary goal is to add a RectilinearImage class, a physically embedded image with origin, irregular spacing in each dimension, and orientation.

Requirements

  • Make changes fully backwards compatible with examples and tests (all examples and tests should compile and run without modification and all tests should pass)
  • Each of the physically embedded image types will properly calculate transforms from indices to physical coordinates and back.
  • All physically embedded images should support orientations.
  • ImageAdaptors should work on all image types
  • Resampling should be supported for all physically embedded image types
  • Conversion of new image types to appropriate VTK classes for visualization

Challenges and Potential Pitfalls

  • ImageAdaptors should present the correct interface for the image type they adapt. This can be accomplished with partial template specialization of the ImageAdaptor class to avoid modifying any of the existing adaptors.
  • Numerous classes use regular spacing of images (they call GetSpacing()) directly and will need to be modified to handle the new image types or be restricted to work with only image types with regular sample spacing. A list of these classes can be found at the appendix at the end of this page.
  • Filters that require voxel positions should ideally use methods TransformIndexToPhysicalPoint, etc., but this may not be optimal for performance.
  • Adding image types will add significant compilation time to wrapping

Design

ImageBase will be stripped to the bare minimum functionality required to support images with lattice topology. Other image types will have more specialized base classes, all descended (perhaps indirectly) from ImageBase. The base classes will provide support for additional image metadata.

Class Hierarchy

The class hierarchy will look like this:

  • ImageBase< unsigned int VDimension >
    • PhysicalImageBase< unsigned int VDimension >
      • RegularImageBase< unsigned int VDimension >
        • Image< class TPixel, unsigned int VDimension >
          • BloxImage< class TPixel, unsigned int VDimension >
            • BloxImage subclasses
          • SparseImage< class TNode, unsigned int VDimension >
        • VectorImage< class TPixel, unsigned int VDimension >
        • LabelMap< class TPixel, unsigned int VDimension >
      • RectilinearImageBase < unsigned int VDimension >
        • RectilinearImage <class TPixel, unsigned in VDimension >
      • PhasedArray3DSpecialCoordinatesImage< class TPixel >

All base image classes specify the interface for only the metadata of the image. This design is required to support the method CopyInformation(). For example, you may encounter a situation where you copy information from a RectilinearImage<float, 3> to a RectilinearImage<double, 3>. Dynamic casting from a RectilinearImage<float, 3> to a RectilinearImage<double, 3> won't work, so the method will throw an exception. Casting a RectilinearImage<float, 3> to a RectilinearImageBase< 3 > will work, enabling access to the metadata methods (GetSpacing(), GetOrigin(), etc.) from the source image.

Specific methods defined or overridden in each class are provided below.

Class Diagram

This is a graph with borders and nodes. Maybe there is an Imagemap used so the nodes may be linking to some Pages.

Image Types

ImageBase

Methods:

  • Allocate()
  • ComputeIndex()
  • ComputeOffset()
  • ComputeOffsetTable()
  • CopyInformation()
  • GetBufferedRegion()
  • GetImageDimension()
  • GetLargestPossibleRegion()
  • GetNumberOfComponentsPerPixel()
  • GetOffsetTable()
  • GetRequestedRegion()
  • Graft()
  • Initialize()
  • InitializeBufferedRegion()
  • RequestedRegionIsOutsideOfTheBufferedRegion()
  • SetBufferedRegion()
  • SetLargestPossibleRegion()
  • SetNumberOfComponentsPerPixel()
  • SetRequestedRegion(const RegionType &region)
  • SetRequestedRegion(DataObject *data)
  • SetRequestedRegionToLargestPossibleRegion()
  • UpdateOutputData()
  • UpdateOutputInformation()

PhysicalImageBase

Methods overridden from ImageBase

  • CopyInformation()

Additional methods

  • GetOrigin()
  • SetOrigin()
  • GetDirection()
  • SetDirection()

RegularImageBase

Methods overridden from PhysicalImageBase

  • CopyInformation()

Additional methods

  • ComputeIndexToPhysicalPointMatrices()
  • GetSpacing()
  • SetSpacing()
  • TransformContinuousIndexToPhysicalPoint(const ContinuousIndex< TCoordRep, VImageDimension > &index, Point< TCoordRep, VImageDimension > &point) const
  • TransformIndexToPhysicalPoint(const IndexType &index, Point< TCoordRep, VImageDimension > &point) const
  • TransformLocalVectorToPhysicalVector(const FixedArray< TCoordRep, VImageDimension > &inputGradient, FixedArray< TCoordRep, VImageDimension > &outputGradient) const
  • TransformPhysicalPointToContinuousIndex(const Point< TCoordRep, VImageDimension > &point, ContinuousIndex< TCoordRep, VImageDimension > &index) const
  • TransformPhysicalPointToIndex(const Point< TCoordRep, VImageDimension > &point, IndexType &index) const

Image (subclass of itkRegularImageBase)

Methods overridden from RegularImageBase

  • Allocate()
  • Graft()
  • Initialize()

Additional methods

  • operator[]
  • FillBuffer()
  • GetBufferPointer()
  • GetNeighborhoodAccessor()
  • GetPixel(const IndexType &index) const
  • GetPixel(const IndexType &index)
  • GetPixelAccessor(void)
  • GetPixelAccessor(void) const
  • GetPixelContainer()
  • GetPixelContainer() const
  • SetNeighborhoodAccessor()
  • SetPixel(const IndexType &index, const TPixel &value)
  • SetPixelContainer(PixelContainer *container)

RectilinearImageBase

Methods overridden from PhysicalImageBase

  • CopyInformation()
  • SetLargestPossibleRegion()

Additional methods

  • ComputeSpacingPrefixSum()
  • GetDefaultSpacing()
  • GetDimensionSpacing(unsigned int dimension)
  • InitializeWithDefaultSpacings()
  • SetDefaultSpacing()
  • SetSpacing(unsigned int dimension, long index, Array<PointValueType>)
  • TransformContinuousIndexToPhysicalPoint(const ContinuousIndex< TCoordRep, VImageDimension > &index, Point< TCoordRep, VImageDimension > &point) const
  • TransformIndexToPhysicalPoint(const IndexType &index, Point< TCoordRep, VImageDimension > &point) const
  • TransformLocalVectorToPhysicalVector(const FixedArray< TCoordRep, VImageDimension > &inputGradient, FixedArray< TCoordRep, VImageDimension > &outputGradient) const
  • TransformPhysicalPointToContinuousIndex(const Point< TCoordRep, VImageDimension > &point, ContinuousIndex< TCoordRep, VImageDimension > &index) const
  • TransformPhysicalPointToIndex(const Point< TCoordRep, VImageDimension > &point, IndexType &index) const

RectilinearImage

Methods overridden from RectilinearImageBase

  • Allocate()
  • Graft()
  • Initialize()

Additional methods

  • operator[]
  • FillBuffer()
  • GetBufferPointer()
  • GetPixel(const IndexType &index) const
  • GetPixel(const IndexType &index)
  • GetPixelAccessor(void)
  • GetPixelAccessor(void) const
  • GetPixelContainer()
  • GetPixelContainer() const
  • GetNeighborhoodAccessor()
  • GetNeighborhoodAccessor() const
  • SetPixel(const IndexType &index, const TPixel &value)
  • SetPixelContainer(PixelContainer *container)

LabelMap

No change needed, but the new interface will not have the methods:

  • GetDirection()
  • GetSpacing()
  • SetDirection()
  • SetSpacing()

If LabelMaps have a physical embedding, then the LabelMap class should be changed to inherit from PhysicalImageBase.

BloxImage

This class currently descends from Image. If it has no spatial embedding, then it could be changed to descend from a new DigitalImage class.

SparseImage

This class currently descends from Image. If it has no spatial embedding, then it could be changed to descend from a new DigitalImage class.

ImageAdaptors

The ImageAdaptor class should be designed to present the proper API for each of the new image types. This requires partial template specialization of the ImageAdaptor template class to maintain backwards compatibility. Specifically, several definitions of the ImageAdaptor class will need to be defined, one for each image type.

To work with the CopyInformation() method in the various Image subclasses, each ImageBase type (RegularImageBase, RectilinearImageBase, etc.) will need to have a corresponding ImageAdaptor type (RegularImageAdaptor, RectilinearImageAdaptor, etc.), each of which is a subclass of its corresponding image base type. They CANNOT be subclasses of the image types with pixel containers because of the problem with dynamic casting in the CopyInformation() method mentioned above.

ResampleImageFilter and WarpImageFilter

The method SetOutputParametersFromImage() takes an ImageBase as input. Now that the metadata is stored in subclasses of ImageBase, this may be suboptimal.

One solution is to try to dynamic_cast the ImageBase input to the various descendants of ImageBase (PhysicalImageBase, RegularImageBase, RectilinearImageBase, etc.). Upon successful casting, the relevant parameters from the ImageBase input can be copied over to the filter. However, say we're resampling to a RectilinearImage with the ResampleImageFilter. The ResampleImageFilter would need to have a method to support individual voxel spacings. But this method isn't needed for resampling to an Image, so it would go to waste.

Alternatively, these classes could be specialized for the output image type much like the ImageAdaptor is specialized. This seems like the best option.

Outstanding Questions

  • Are BloxImages and SparseImages physically embedded images?
  • Should image sources be specialized for different image types?
  • Will interpolators work out-of-the-box for Images with implementations of TransformIndexToPhysicalPoint, etc?
  • File readers?
  • Use concept checking in filters and image sources to check support for input/output image types?

Implementation Plan

After all phases of implementation, existing tests must compile and pass.

A sample implementation encompassing phases 1-3 is available at GitHub.

Phase 1

  • Implement PhysicalImageBase< unsigned int VDimension >
  • Implement RegularImageBase
  • Make Image and VectorImage subclasses of RegularImageBase
  • Make SpecialCoordinatesImage a subclass of RegularImageBase

Example implementation complete

Phase 2

  • Write RegularImageAdaptor
  • Specialize the ImageAdaptor template for Image, VectorImage, and PhasedArray3DSpecialCoordinatesImage classes.
  • Remove unnecessary methods from adaptor classes.
  • Remove unnecessary methods, typedefs, and member variables from ImageBase, PhysicalImageBase, and RegularImageBase.

Example implementation complete

Phase 3

  • Implement RectilinearImageBase and RectilinearImage
  • Specialize the ImageAdaptor template for RectilinearImages
  • Add example tests for rectilinear images

Example implementation complete

Phase 4

  • Specialize ResampleImageFilter
  • Specialize WarpImageFilter

Participants

  • Cory Quammen (UNC Chapel Hill)

Appendix: Classes that use Regular Spacing of Images

Algorithms

    • Algorithms/itkBinaryMask3DMeshSource.txx
      • Should be easily modified to use TransformIndexToPhysicalPoint
    • Algorithms/itkCollidingFrontsImageFilter.txx
      • GetSpacing() required by FastMarchingUpwindGradientImageFilter->GetOutputSpacing()
    • Algorithms/itkDeformableSimplexMesh3DGradientConstraintForceFilter.txx
      • Should be easily modified to use TransformIndexToPhysicalPoint
    • Algorithms/itkDemonsRegistrationFunction.txx
      • Should be able to calculate m_Normalizer by getting the volume of a voxel
    • Algorithms/itkFastMarchingImageFilter.txx
      • ?
    • Algorithms/itkFastMarchingUpwindGradientImageFilter.txx
      • Spacing in finite difference calculation should be replaceable by more general image spacing; images with curvilinear coordinate systems won't work
    • Algorithms/itkFastSymmetricForcesDemonsRegistrationFunction.txx
      • Should be able to calculate m_Normalizer by getting the volume of a voxel
    • Algorithms/itkFEMRegistrationFilter.txx
      • Spacing is passed to WarpImageFilter; could be resolved by calling SetOutputParametersFromImage()
    • Algorithms/itkGradientDifferenceImageToImageMetric.txx
      • Spacing is passed to ResampleImageFilter; could be resolved by calling SetOutputParametersFromImage()
    • Algorithms/itkImageToImageMetric.txx
      • Uses the largest voxel size as the sigma in an internal gradient filter
    • Algorithms/itkIsoContourDistanceImageFilter.txx
      • ?
    • Algorithms/itkKLMRegionGrowImageFilter.txx
      • Uses spacing to compute region border lengths; could be replaced with a method in an image class
    • Algorithms/itkLevelSetMotionRegistrationFunction.txx
      • Uses spacing for forward difference calculation
    • Algorithms/itkMeanSquareRegistrationFunction.txx
      • ?
    • Algorithms/itkMultiResolutionPDEDeformableRegistration.txx
      • ?
    • Algorithms/itkMultiResolutionPyramidImageFilter.txx
      • Sets spacing of output images at each level; it seems unlikely to want to generate irregular images for a multi-resolution pyramid
    • Algorithms/itkNCCRegistrationFunction.txx;
      • Uses spacings in computing the gradient squared magnitude for the fixed image
    • Algorithms/itkPDEDeformableRegistrationFilter.txx
      • Forwards spacing from output to a temporary deformation field
    • Algorithms/itkPointSetToImageMetric.txx
      • Uses the largest voxel size as the sigma in an internal gradient filter
    • Algorithms/itkRayCastInterpolateImageFunction.txx
      • This class is heavily tied to the assumption of regular spacing
    • Algorithms/itkReinitializeLevelSetImageFilter.txx
      • Forwards spacing from input image to the FastMarchingImageFilterType
    • Algorithms/itkSymmetricForcesDemonsRegistrationFunction.txx
      • Should be able to calculate m_Normalizer by getting the volume of a voxel

BasicFilters

    • BasicFilters/itkAccumulateImageFilter.txx
      • Essentially forwards the spacing to the output, except for the collapsed dimension which has the spacing set to the size of the original image in the collapsed dimension
    • BasicFilters/itkAnisotropicDiffusionImageFilter.txx
      • Uses spacing to determine a timestep that produces stable solutions
    • BasicFilters/itkBilateralImageFilter.txx
      • ?
    • BasicFilters/itkBSplineDownsampleImageFilter.txx
      • Output image spacing is twice that of the input; should be able to do something for images with non-regular spacing
    • BasicFilters/itkBSplineInterpolateImageFunction.txx
      • Used in derivative calculation
    • BasicFilters/itkBSplineUpsampleImageFilter.txx
      • Output image spacing is half that of the input; should be able to do something for images with non-regular spacing
    • BasicFilters/itkChangeInformationImageFilter.txx
      • Should probably have a special ChangeInformationImageFilter for other image types
    • BasicFilters/itkDanielssonDistanceMapImageFilter.txx
      • ?
    • BasicFilters/itkDerivativeImageFilter.txx
      • Used for scaling coefficient in DerivativeOperator; this may not work well for images with irregular spacing
    • BasicFilters/itkDiscreteGaussianImageFilter.txx
      • Depends on GaussianOperator supporting irregular spacing
    • BasicFilters/itkDisplacementFieldJacobianDeterminantFilter.txx
      • Used in m_DerivativeWeights and m_HalfDerivativeWeights, which themselves don't seem to be used anywhere
    • BasicFilters/itkExpandImageFilter.txx
      • Should be straightforward to implement for images of irregular spacing
    • BasicFilters/itkExtractImageFilter.txx
      • Should be straightforward to implement for images of irregular spacing
    • BasicFilters/itkGradientImageFilter.txx
      • Depends on DerivativeOperator supporting irregular spacing
    • BasicFilters/itkGradientImageToBloxBoundaryPointImageFilter.txx
      • Sets output image spacing to multiple of the input image spacing
    • BasicFilters/itkGradientMagnitudeImageFilter.txx
      • Depends on DerivativeOperator supporting irregular spacing
    • BasicFilters/itkGradientMagnitudeRecursiveGaussianImageFilter.txx
      • ?
    • BasicFilters/itkGradientRecursiveGaussianImageFilter.txx
      • Spacing used to divide output scalar values
    • BasicFilters/itkHessianRecursiveGaussianImageFilter.txx
      • Used to normalize output values
    • BasicFilters/itkHoughTransform2DCirclesImageFilter.txx
      • Forwards spacing from input image to radius image
    • BasicFilters/itkHoughTransform2DLinesImageFilter.txx
      • Forwards spacing from input image to m_SimplifyAccumulator image
    • BasicFilters/itkImportImageFilter.h
      • Would need to write a version for images with irregular spacing
    • BasicFilters/itkInterpolateImagePointsFilter.txx
      • Spacing of the image specifying the x-coordinates of the interpolation points is used as the spacing of the output image; this is rather arbitrary as the output image sample coordinates are arbitrary
    • BasicFilters/itkInverseDeformationFieldImageFilter.txx
      • A scale factor of the input image spacing is used as the output image spacing
    • BasicFilters/itkIterativeInverseDeformationFieldImageFilter.txx
      • Sets output spacing to that of the input image
    • BasicFilters/itkJoinSeriesImageFilter.txx
      • Spacing of new dimension is set by the filter; this would have to be an array of spacings for a RectilinearImage
    • BasicFilters/itkLaplacianImageFilter.txx
      • Depends on LaplacianOperator supporting irregular spacing
    • BasicFilters/itkLaplacianRecursiveGaussianImageFilter.txx
      • Uses spacing as normalizer
    • BasicFilters/itkLaplacianSharpeningImageFilter.txx
      • Depends on LaplacianOperator supporting irregular spacing
    • BasicFilters/itkParallelSparseFieldLevelSetImageFilter.txx
      • ?
    • BasicFilters/itkPermuteAxesImageFilter.txx
      • Forwards spacing of input image to the output image
    • BasicFilters/itkPolylineMask2DImageFilter.txx
      • Forwards spacing from input to output image
    • BasicFilters/itkPolylineMaskImageFilter.txx
      • Forwards spacing from input to output image
    • BasicFilters/itkProjectionImageFilter.txx
      • Forwards spacing from input to output image
    • BasicFilters/itkRecursiveSeparableImageFilter.txx
      • Regular spacing assumption is encoded as a parameter in the SetUp pure virtual method
    • BasicFilters/itkRelabelComponentImageFilter.txx
      • Spacing used to compute volume of voxels
    • BasicFilters/itkResampleImageFilter.txx
      • Discussed in more detail below
    • BasicFilters/itkShrinkImageFilter.txx
      • Filter shrinks an image to an integer multiple of the original image size
    • BasicFilters/itkSignedMaurerDistanceMapImageFilter.txx
      • Uses spacing to map index of voxel position to physical space
    • BasicFilters/itkSparseFieldLevelSetImageFilter.txx
      • ?
    • BasicFilters/itkSpatialObjectToImageStatisticsCalculator.txx
      • Used to remove spacing considerations from an internal FloodFill iterator
    • BasicFilters/itkTileImageFilter.txx
      • Forwards spacing from input to output image
    • BasicFilters/itkTriangleMeshToBinaryImageFilter.txx
      • Generates image with a given spacing
    • BasicFilters/itkUnaryFunctorImageFilter.txx
      • Forwards spacing from input to output image
    • BasicFilters/itkVectorExpandImageFilter.txx
      • Output image spacing is an integer multiple of input image spacing
    • BasicFilters/itkVectorGradientMagnitudeImageFilter.txx
      • Spacing used as derivative weights
    • BasicFilters/itkWarpImageFilter.txx
      • See discussion below

Common

    • Common/itkAnnulusOperator.h
      • Uses spacing to ensure annulus is spherical
    • Common/itkBSplineDeformableTransform.txx
      • Used to set the coefficient grid spacing
    • Common/itkCentralDifferenceImageFunction.txx
      • Used in finite difference calculation
    • Common/itkDenseFiniteDifferenceImageFilter.txx
      • Used to set spacing of output image
    • Common/itkFiniteDifferenceImageFilter.txx
      • Spacing used in finite difference coefficients
    • Common/itkFloodFilledFunctionConditionalConstIterator.txx
      • Not clear where the spacing is used.
    • Common/itkGaussianBlurImageFunction.txx
      • Depends on irregular spacing support in GaussianOperator
    • Common/itkGaussianDerivativeImageFunction.txx
      • Depends on irregular spacing support in GaussianOperator
    • Common/itkImageDuplicator.txx
      • Forwards spacing of input image to output image
    • Common/itkPathConstIterator.txx
      • Not clear where the spacing is used.

IO

    • IO/itkGDCMImageIO.cxx
      • Sets spacing from image
    • IO/itkImageFileReader.txx
      • Sets spacing from image
    • IO/itkImageFileWriter.txx
      • Writes spacing to file
    • IO/itkImageIOBase.h
      • Spacing goes to/comes from image file
    • IO/itkImageSeriesReader.txx
      • Produces regular image
    • IO/itkImageSeriesWriter.txx
      • Geared to images with regular spacing
    • IO/itkMetaImageIO.cxx
      • Geared to images with regular spacing
    • IO/itkNiftiImageIO.cxx
      • Geared to images with regular spacing
    • IO/itkNrrdImageIO.cxx
      • Geared to images with regular spacing

Numerics

    • Numerics/Statistics/itkHistogramToImageFilter.h
      • Sets size of output image

Review

    • Review/itkAreaClosingImageFilter.h
      • Can optionally use spacing to compute area.
    • Review/itkAreaOpeningImageFilter.h
      • Can optionally use spacing to compute area.
    • Review/itkBSplineDeformableTransformInitializer.txx
      • Uses image spacing to calculate grid spacing
    • Review/itkBSplineScatteredDataPointSetToImageFilter.txx
      • ?
    • Review/itkConstrainedRegionBasedLevelSetFunctionSharedData.h
      • Spacing used to determine query points
    • Review/itkDiffeomorphicDemonsRegistrationFilter.txx
      • Sets output spacing to that of input
    • Review/itkDirectFourierReconstructionImageToImageFilter.txx
      • Spacing of output image set from input image
    • Review/itkDiscreteGaussianDerivativeImageFilter.txx
      • Depends on GaussianDerivativeOperator
    • Review/itkDiscreteGaussianDerivativeImageFunction.txx
      • Depends on GaussianDerivativeOperator
    • Review/itkDiscreteGradientMagnitudeGaussianImageFunction.txx
      • Depends on GaussianDerivativeOperator
    • Review/itkDiscreteHessianGaussianImageFunction.txx
      • Used by NeighborhoodOperatorImageFunction
    • Review/itkESMDemonsRegistrationFunction.txx
      • Spacing is used to computer normalizer
    • Review/itkExponentialDeformationFieldImageFilter.txx
      • Used to calculate number of iterations
    • Review/itkFastSymmetricForcesDemonsRegistrationFilter.txx
      • Copies input spacing to output image
    • Review/itkGaborImageSource.txx
      • User sets spacing
    • Review/itkGridForwardWarpImageFilter.txx
      • Copies input spacing to output image
    • Review/itkGridImageSource.txx
      • User sets spacing
    • Review/itkJPEG2000ImageIO.cxx
      • Produces regular images
    • Review/itkLabelGeometryImageFilter.txx
      • Copies input spacing to output spacing
    • Review/itkLabelPerimeterEstimationCalculator.txx
      • Uses spacing to compute physical size of voxels
    • Review/itkMINC2ImageIO.cxx
      • Produces regular images
    • Review/itkMultiphaseFiniteDifferenceImageFilter.txx
      • Spacing used for scale coefficients in the difference functions
    • Review/itkMultiphaseSparseFiniteDifferenceImageFilter.txx
      • ?
    • Review/itkRegionBasedLevelSetFunction.h
      • Spacing used in gradient computation
    • Review/itkShapedFloodFilledFunctionConditionalConstIterator.txx
      • ?
    • Review/itkShapeLabelMapFilter.txx
      • Spacing used for physical volume measurements
    • Review/itkStatisticsLabelMapFilter.txx
      • Used for statistics of physical dimensions of voxels
    • Review/itkStochasticFractalDimensionImageFilter.txx
      • ?
    • Review/itkStreamingImageIOBase.cxx
      • Produces images with regular spacing
    • Review/itkTransformToDeformationFieldSource.txx
      • Can optionally use spacing from reference image
    • Review/itkVectorCentralDifferenceImageFunction.txx
      • Used in derivative weights
    • Review/itkVTKImageIO2.cxx
      • Produces images with regular spacing
    • Review/itkWarpHarmonicEnergyCalculator.txx
      • Used in derivative weights

Spatial Object

    • SpatialObject/itkImageSpatialObject.txx
      • spacing doesn't seem to be used
    • SpatialObject/itkMetaImageConverter.txx
      • Spacing is set on the metaimage.
    • SpatialObject/itkSpatialObject.h
      • spacing is essentially a geometric scaling factor