/*========================================================================= * * Copyright Insight Software Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkVectorImage_h #define itkVectorImage_h #include "itkImageRegion.h" #include "itkImportImageContainer.h" #include "itkDefaultVectorPixelAccessor.h" #include "itkDefaultVectorPixelAccessorFunctor.h" #include "itkVectorImageNeighborhoodAccessorFunctor.h" #include "itkWeakPointer.h" namespace itk { /** \class VectorImage * \brief Templated n-dimensional vector image class. * * This class differs from Image in that it is intended to represent multiple * images. Each pixel represents \e k measurements, each of datatype \e TPixel. * The memory organization of the resulting image is as follows: * ... Pi0 Pi1 Pi2 Pi3 P(i+1)0 P(i+1)1 P(i+1)2 P(i+1)3 P(i+2)0 ... * where Pi0 represents the 0th measurement of the pixel at index i. * * Conceptually, a VectorImage< TPixel, 3 > is the same as a * Image< VariableLengthVector< TPixel >, 3 >. The difference lies in the memory * organization. The latter results in a fragmented * organization with each location in the Image holding a pointer to an \c VariableLengthVector * holding the actual pixel. The former stores the \e k pixels instead of a * pointer reference, which apart from avoiding fragmentation of memory also avoids * storing a 8 bytes of pointer reference for each pixel. * The parameter \e k can be set using \c SetVectorLength. * * The API of the class is such that it returns a pixeltype VariableLengthVector< TPixel > when * queried, with the data internally pointing to the buffer. (the container does not * manage the memory). Similarly SetPixel calls can be made with VariableLengthVector< TPixel >. * * The API of this class is similar to Image. * * \par Caveats: * When using Iterators on this image, you cannot use the it.Value(). You must use * Set/Get() methods instead. * * \note * This work is part of the National Alliance for Medical Image Computing * (NAMIC), funded by the National Institutes of Health through the NIH Roadmap * for Medical Research, Grant U54 EB005149. * * \sa DefaultVectorPixelAccessor * \sa DefaultVectorPixelAccessorFunctor * \sa VectorImageToImagePixelAccessor * \sa VectorImageToImageAdaptor * \sa Image * \sa ImportImageContainer * * * \ingroup ImageObjects * \ingroup ITKCommon * * \wiki * \wikiexample{IO/ReadVectorImage,Read an image file with an unknown number of components} * \wikiexample{VectorImages/VectorImage,Create a vector image} * \wikiexample{VectorImages/NeighborhoodIterator,NeighborhoodIterator on a VectorImage} * \endwiki */ template< typename TPixel, unsigned int VImageDimension = 3 > class ITK_TEMPLATE_EXPORT VectorImage: public ImageBase< VImageDimension > { public: /** Standard class typedefs */ typedef VectorImage Self; typedef ImageBase< VImageDimension > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef WeakPointer< const Self > ConstWeakPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(VectorImage, ImageBase); /** Pixel typedef support. Used to declare pixel type in filters * or other operations. This is not the actual pixel type contained in * the buffer, ie m_Buffer. The image exhibits an external API of an * VariableLengthVector< T > and internally stores its data as type T. */ typedef VariableLengthVector< TPixel > PixelType; /** This is the actual pixel type contained in the buffer. Each vector * pixel is composed of 'm_VectorLength' contiguous InternalPixelType. */ typedef TPixel InternalPixelType; /** Typedef alias for PixelType */ typedef PixelType ValueType; typedef InternalPixelType IOPixelType; /** Accessor type that convert data between internal and external * representations. */ typedef DefaultVectorPixelAccessor< InternalPixelType > AccessorType; /** Functor to provide a common API between DefaultPixelAccessor and * DefaultVectorPixelAccessor */ typedef DefaultVectorPixelAccessorFunctor< Self > AccessorFunctorType; /** Typedef for the functor used to access a neighborhood of pixel * pointers. */ typedef VectorImageNeighborhoodAccessorFunctor< Self > NeighborhoodAccessorFunctorType; /** Dimension of the image. This constant is used by functions that are * templated over image type (as opposed to being templated over pixel type * and dimension) when they need compile time access to the dimension of * the image. */ itkStaticConstMacro(ImageDimension, unsigned int, VImageDimension); /** Index typedef support. An index is used to access pixel values. */ typedef typename Superclass::IndexType IndexType; typedef typename Superclass::IndexValueType IndexValueType; /** Offset typedef support. An offset is used to access pixel values. */ typedef typename Superclass::OffsetType OffsetType; /** Size typedef support. A size is used to define region bounds. */ typedef typename Superclass::SizeType SizeType; /** Container used to store pixels in the image. */ typedef ImportImageContainer< SizeValueType, InternalPixelType > PixelContainer; /** Direction typedef support. A matrix of direction cosines. */ typedef typename Superclass::DirectionType DirectionType; /** Region typedef support. A region is used to specify a subset of an image. */ typedef typename Superclass::RegionType RegionType; /** 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 is the geometric coordinates * of the index (0,0). */ typedef typename Superclass::PointType PointType; /** A pointer to the pixel container. */ typedef typename PixelContainer::Pointer PixelContainerPointer; typedef typename PixelContainer::ConstPointer PixelContainerConstPointer; /** Offset typedef (relative position between indices) */ typedef typename Superclass::OffsetValueType OffsetValueType; typedef unsigned int VectorLengthType; /** * \brief A structure which enable changing any image class' pixel * type to another. * * Since the pixel type of this class is a VariableLengthVector of * TPixelType, the following two rebinds result in the same type to * enable usage with the numeric trait's type. * * \code * typename InputImageType::template template Rebind::Type RealImageType1; * typename InputImageType::template template Rebind >::Type RealImageType2; * \endcode * * \sa Image::Rebind */ template struct Rebind { typedef itk::VectorImage Type; }; /// \cond HIDE_SPECIALIZATION_DOCUMENTATION template struct Rebind< VariableLengthVector< UElementType >, NUImageDimension> { typedef itk::VectorImage Type; }; /// \endcond /** Allocate the image memory. The size of the image must * already be set, e.g. by calling SetRegions(). */ virtual void Allocate(bool UseDefaultConstructor = false) ITK_OVERRIDE; /** Restore the data object to its initial state. This means releasing * memory. */ virtual void Initialize() ITK_OVERRIDE; /** Fill the image buffer with a value. Be sure to call Allocate() * first. */ void FillBuffer(const PixelType & value); /** \brief Set a pixel value. * * Allocate() needs to have been called first -- for efficiency, * this function does not check that the image has actually been * allocated yet. */ void SetPixel(const IndexType & index, const PixelType & value) { OffsetValueType offset = m_VectorLength * this->FastComputeOffset(index); for ( VectorLengthType i = 0; i < m_VectorLength; i++ ) { ( *m_Buffer )[offset + i] = value[i]; } } /** \brief Get a pixel (read only version). * * For efficiency, this function does not check that the * image has actually been allocated yet. Note that the method returns a * pixel on the stack. */ const PixelType GetPixel(const IndexType & index) const { OffsetValueType offset = m_VectorLength * this->FastComputeOffset(index); // Do not create a local for this method, to use return value // optimization. return PixelType(&( ( *m_Buffer )[offset] ), m_VectorLength); } /** \brief Get a "reference" to a pixel. This result cannot be used * as an lvalue because the pixel is converted on the fly to a * VariableLengthVector. * * To use the results to modify this image, return value * optimization must be relied upon. * * For efficiency, this function does not check that the * image has actually been allocated yet. */ PixelType GetPixel(const IndexType & index) { OffsetValueType offset = m_VectorLength * this->FastComputeOffset(index); // Correctness of this method relies of return value optimization, do // not create a local for the value. return PixelType(&( ( *m_Buffer )[offset] ), m_VectorLength); } /** \brief Access a pixel. This result cannot be used as an lvalue * because the pixel is converted on the fly to a * VariableLengthVector. * * To use the results to modify this image, return value * optimization must be relied upon. * * For efficiency, this function does not check that the * image has actually been allocated yet. */ PixelType operator[](const IndexType & index) { return this->GetPixel(index); } /** \brief Access a pixel. * * For efficiency, this function does not check that the * image has actually been allocated yet. */ const PixelType operator[](const IndexType & index) const { return this->GetPixel(index); } /** Return a pointer to the beginning of the buffer. This is used by * the image iterator class. */ InternalPixelType * GetBufferPointer() { return m_Buffer ? m_Buffer->GetBufferPointer() : ITK_NULLPTR; } const InternalPixelType * GetBufferPointer() const { return m_Buffer ? m_Buffer->GetBufferPointer() : ITK_NULLPTR; } /** Return a pointer to the container. */ PixelContainer * GetPixelContainer() { return m_Buffer.GetPointer(); } /** Return a pointer to the container. */ const PixelContainer * GetPixelContainer() const { return m_Buffer.GetPointer(); } /** Set the container to use. Note that this does not cause the * DataObject to be modified. */ void SetPixelContainer(PixelContainer *container); /** Graft the data and information from one image to another. This * is a convenience method to setup a second image with all the meta * information of another image and use the same pixel * container. Note that this method is different than just using two * SmartPointers to the same image since separate DataObjects are * still maintained. This method is similar to * ImageSource::GraftOutput(). The implementation in ImageBase * simply calls CopyInformation() and copies the region ivars. * The implementation here refers to the superclass' implementation * and then copies over the pixel container. */ virtual void Graft(const Self *data); /** Return the Pixel Accessor object */ AccessorType GetPixelAccessor(void) { return AccessorType(m_VectorLength); } /** Return the Pixel Accesor object */ const AccessorType GetPixelAccessor(void) const { return AccessorType(m_VectorLength); } /** Return the NeighborhoodAccessor functor */ NeighborhoodAccessorFunctorType GetNeighborhoodAccessor() { return NeighborhoodAccessorFunctorType(m_VectorLength); } /** Return the NeighborhoodAccessor functor */ const NeighborhoodAccessorFunctorType GetNeighborhoodAccessor() const { return NeighborhoodAccessorFunctorType(m_VectorLength); } /** Set/Get macros for the length of each vector in the vector image */ itkSetMacro(VectorLength, VectorLengthType); itkGetConstReferenceMacro(VectorLength, VectorLengthType); /** Get/Set the number of components each pixel has, ie the VectorLength */ virtual unsigned int GetNumberOfComponentsPerPixel() const ITK_OVERRIDE; virtual void SetNumberOfComponentsPerPixel(unsigned int n) ITK_OVERRIDE; protected: VectorImage(); void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; virtual ~VectorImage() ITK_OVERRIDE {} virtual void Graft(const DataObject *data) ITK_OVERRIDE; using Superclass::Graft; private: ITK_DISALLOW_COPY_AND_ASSIGN(VectorImage); /** Length of the "vector pixel" */ VectorLengthType m_VectorLength; /** Memory for the current buffer. */ PixelContainerPointer m_Buffer; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkVectorImage.hxx" #endif #endif