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