1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkNeighborhood_h
19 #define itkNeighborhood_h
20 
21 #include <iostream>
22 #include "itkNeighborhoodAllocator.h"
23 #include "itkIndent.h"
24 #include "itkSliceIterator.h"
25 #include "vnl/vnl_vector.h"
26 #include "itkOffset.h"
27 #include <vector>
28 
29 namespace itk
30 {
31 /** \class Neighborhood
32  * \brief A light-weight container object for storing an N-dimensional
33  * neighborhood of values.
34  *
35  * This class serves as the base class for several other Itk objects such as
36  * itk::NeighborhoodOperator and itk::NeighborhoodIterator.  Its purpose is to
37  * store values and their relative spatial locations.
38  *
39  * A Neighborhood has an N-dimensional \em radius.  The radius is defined
40  * separately for each dimension as the number of pixels that the neighborhood
41  * extends outward from the center pixel.  For example, a 2D Neighborhood
42  * object with a radius of 2x3 has sides of length 5x7.  Neighborhood objects
43  * always have an unambiguous center because their side lengths are always odd.
44  *
45  * \sa Neighborhood
46  * \sa NeighborhoodIterator
47  *
48  * \ingroup Operators
49  * \ingroup ImageIterators
50  * \ingroup ITKCommon
51  */
52 
53 template< typename TPixel, unsigned int VDimension = 2,
54           typename TAllocator = NeighborhoodAllocator< TPixel > >
55 class ITK_TEMPLATE_EXPORT Neighborhood
56 {
57 public:
58   /** Standard class type aliases. */
59   using Self = Neighborhood;
60 
61   /** External support for allocator type. */
62   using AllocatorType = TAllocator;
63 
64   /** External support for dimensionality. */
65   static constexpr unsigned int NeighborhoodDimension = VDimension;
66 
67   /** Run-time type information (and related methods). */
68   itkTypeMacroNoParent(Neighborhood);
69 
70   /** External support for pixel type. */
71   using PixelType = TPixel;
72 
73   /** Iterator type alias support Note the naming is intentional, i.e.,
74   * AllocatorType::iterator and AllocatorType::const_iterator, because the
75   * allocator may be a vnl object or other type, which uses this form. */
76   using Iterator = typename AllocatorType::iterator;
77   using ConstIterator = typename AllocatorType::const_iterator;
78 
79   /** Size and value type alias support */
80   using SizeType = ::itk::Size<VDimension>;
81   using SizeValueType = typename SizeType::SizeValueType;
82 
83   /** Radius type alias support */
84   using RadiusType = ::itk::Size<VDimension>;
85 
86   /** Offset type used to reference neighbor locations */
87   using OffsetType = Offset< VDimension >;
88 
89   /** External slice iterator type type alias support */
90   using SliceIteratorType = SliceIterator< TPixel, Self >;
91 
92   /** Type used to refer to space dimensions */
93   using DimensionValueType = unsigned int;
94 
95   /** Type used to refer to the elements of the pixel list
96    * that are part of the neighborhood. */
97   using NeighborIndexType = SizeValueType;
98 
99   /** Default constructor. */
Neighborhood()100   Neighborhood()
101   {
102     m_Radius.Fill(0);
103     m_Size.Fill(0);
104     for ( DimensionValueType i = 0; i < VDimension; i++ )
105       {
106       m_StrideTable[i] = 0;
107       }
108   }
109 
110   /** Default destructor. */
111   virtual ~Neighborhood() = default;
112 
113   /** Copy constructor. */
114   Neighborhood(const Self & other);
115 
116   /** Move-constructor. */
117   Neighborhood(Self &&) = default;
118 
119   /** Assignment operator. */
120   Self & operator=(const Self & other);
121 
122   /** Move-assignment. */
123   Self & operator=(Self&&) = default;
124 
125   /** Comparison operator. */
126   bool
127   operator==(const Self & other) const
128   {
129     return ( m_Radius == other.m_Radius
130              && m_Size   == other.m_Size
131              && m_DataBuffer == other.m_DataBuffer );
132   }
133 
134   /** Not Equal operator. */
135   bool operator!=(const Self & other) const
136   {
137     return ( m_Radius != other.m_Radius
138              || m_Size   != other.m_Size
139              || m_DataBuffer != other.m_DataBuffer );
140   }
141 
142   /** Returns the radius of the neighborhood. */
GetRadius()143   const SizeType GetRadius() const
144   { return m_Radius; }
145 
146   /** Returns the radius of the neighborhood along a specified
147    * dimension. */
GetRadius(DimensionValueType n)148   SizeValueType GetRadius(DimensionValueType n) const
149   { return m_Radius[n]; }
150 
151   /** Returns the size (total length) of the neighborhood along
152    * a specified dimension. */
GetSize(DimensionValueType n)153   SizeValueType GetSize(DimensionValueType n) const
154   { return m_Size[n]; }
155 
156   /** Returns the size (total length of sides) of the neighborhood. */
GetSize()157   SizeType GetSize() const
158   { return m_Size; }
159 
160   /** Returns the stride length for the specified dimension. Stride
161    * length is the number of pixels between adjacent pixels along the
162    * given dimension. */
GetStride(DimensionValueType axis)163   OffsetValueType GetStride(DimensionValueType axis) const
164   { return ( axis < VDimension ) ? m_StrideTable[axis] : 0;  }
165 
166   /** STL-style iterator support. */
End()167   Iterator End()
168   { return m_DataBuffer.end(); }
Begin()169   Iterator Begin()
170   { return m_DataBuffer.begin(); }
End()171   ConstIterator End() const
172   { return m_DataBuffer.end(); }
Begin()173   ConstIterator Begin() const
174   { return m_DataBuffer.begin(); }
175 
176   /** More STL-style support. */
Size()177   NeighborIndexType Size() const
178   { return m_DataBuffer.size(); }
179 
180   /** Pass-through data access methods to the buffer. */
181   TPixel & operator[](NeighborIndexType i)
182   { return m_DataBuffer[i]; }
183   const TPixel & operator[](NeighborIndexType i) const
184   { return m_DataBuffer[i]; }
GetElement(NeighborIndexType i)185   TPixel & GetElement(NeighborIndexType i)
186   { return m_DataBuffer[i]; }
187 
188   /** Returns the element at the center of the neighborhood. */
GetCenterValue()189   TPixel GetCenterValue() const
190   { return ( this->operator[]( ( this->Size() ) >> 1 ) ); }
191 
192   /** Sets the radius for the neighborhood, calculates size from the
193    * radius, and allocates storage. */
194   void SetRadius(const SizeType &);
195 
196   /** Sets the radius for the neighborhood. Overloaded to support an unsigned
197    * long array. */
SetRadius(const SizeValueType * rad)198   void SetRadius(const SizeValueType *rad)
199   {
200     SizeType s;
201     std::copy(rad,
202               rad+VDimension,
203               s.m_InternalArray);
204     this->SetRadius(s);
205   }
206 
207   /** Overloads SetRadius to allow a single long integer argument
208    * that is used as the radius of all the dimensions of the
209    * Neighborhood (resulting in a "square" neighborhood). */
210   void SetRadius(const SizeValueType);
211 
212   /** Standard itk object method. */
Print(std::ostream & os)213   void Print(std::ostream & os) const
214   { this->PrintSelf( os, Indent(0) );  }
215 
216   /** Returns a reference to the data buffer structure. */
GetBufferReference()217   AllocatorType & GetBufferReference()
218   { return m_DataBuffer; }
GetBufferReference()219   const AllocatorType & GetBufferReference() const
220   { return m_DataBuffer; }
221 
222   /** Get pixel value by offset */
223   TPixel & operator[](const OffsetType & o)
224   { return this->operator[]( this->GetNeighborhoodIndex(o) ); }
225   const TPixel & operator[](const OffsetType & o) const
226   { return this->operator[]( this->GetNeighborhoodIndex(o) ); }
227 
228   /** Returns the itk::Offset from the center of the Neighborhood to
229       the requested neighbor index. */
GetOffset(NeighborIndexType i)230   OffsetType GetOffset(NeighborIndexType i) const
231   { return m_OffsetTable[i]; }
232 
233   virtual NeighborIndexType GetNeighborhoodIndex(const OffsetType &) const;
234 
GetCenterNeighborhoodIndex()235   NeighborIndexType GetCenterNeighborhoodIndex() const
236   {
237     return static_cast< NeighborIndexType >( this->Size() / 2 );
238   }
239 
240   std::slice GetSlice(unsigned int) const;
241 
242 protected:
243   /** Sets the length along each dimension. */
SetSize()244   void SetSize()
245   {
246     for ( DimensionValueType i = 0; i < VDimension; ++i )
247       {
248       m_Size[i] = m_Radius[i] * 2 + 1;
249       }
250   }
251 
252   /** Allocates the neighborhood's memory buffer. */
Allocate(NeighborIndexType i)253   virtual void Allocate(NeighborIndexType i)
254   { m_DataBuffer.set_size(i); }
255 
256   /** Standard itk object method. */
257   virtual void PrintSelf(std::ostream &, Indent) const;
258 
259   /** Computes the entries for the stride table */
260   virtual void ComputeNeighborhoodStrideTable();
261 
262   /** Fills entries into the offset lookup table. Called once on
263       initialization. */
264   virtual void ComputeNeighborhoodOffsetTable();
265 
266 private:
267   /** Number of neighbors to include (symmetrically) along each axis.
268    * A neighborhood will always have odd-length axes (m_Radius[n]*2+1). */
269   SizeType m_Radius;
270 
271   /** Actual length of each dimension, calculated from m_Radius.
272    * A neighborhood will always have odd-length axes (m_Radius[n]*2+1). */
273   SizeType m_Size;
274 
275   /** The buffer in which data is stored. */
276   AllocatorType m_DataBuffer;
277 
278   /** A lookup table for keeping track of stride lengths in a neighborhood
279       i.e. the memory offsets between pixels along each dimensional axis */
280   OffsetValueType m_StrideTable[VDimension];
281 
282   /** */
283   std::vector< OffsetType > m_OffsetTable;
284 };
285 
286 template< typename TPixel, unsigned int VDimension, typename TContainer >
287 std::ostream & operator<<(std::ostream & os, const Neighborhood< TPixel, VDimension, TContainer > & neighborhood)
288 {
289   os << "Neighborhood:" << std::endl;
290   os << "    Radius:" << neighborhood.GetRadius() << std::endl;
291   os << "    Size:" << neighborhood.GetSize() << std::endl;
292   os << "    DataBuffer:" << neighborhood.GetBufferReference() << std::endl;
293 
294   return os;
295 }
296 } // namespace itk
297 
298 #ifndef ITK_MANUAL_INSTANTIATION
299 #include "itkNeighborhood.hxx"
300 #endif
301 
302 /*
303 #ifndef ITK_MANUAL_INSTANTIATION
304 #include "itkNeighborhood.hxx"
305 #endif
306 */
307 
308 #endif
309