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 itkNeighborhoodIterator_h 19 #define itkNeighborhoodIterator_h 20 21 #include <vector> 22 #include <cstring> 23 #include <iostream> 24 #include "itkConstNeighborhoodIterator.h" 25 26 namespace itk 27 { 28 /** 29 * \class NeighborhoodIterator 30 * 31 * \brief Defines iteration of a local N-dimensional neighborhood of pixels 32 * across an itk::Image. 33 * 34 * This class is a loose extension of the Standard Template Library (STL) 35 * bi-directional iterator concept to \em masks of pixel neighborhoods within 36 * itk::Image objects. This NeighborhoodIterator base class defines simple 37 * forward and reverse iteration of an N-dimensional neighborhood mask 38 * across an image. Elements within the mask can be accessed like elements 39 * within an array. 40 * 41 * NeighborhoodIterators are designed to encapsulate some of the complexity of 42 * working with image neighborhoods, complexity that would otherwise have to be 43 * managed at the algorithmic level. Use NeighborhoodIterators to simplify 44 * writing algorithms that perform geometrically localized operations on images 45 * (for example, convolution and morphological operations). 46 * 47 * To motivate the discussion of NeighborhoodIterators and their use in 48 * Itk, consider the following code that takes directional derivatives at each 49 * point in an image. 50 * 51 \code 52 itk::NeighborhoodInnerProduct<ImageType> innerProduct; 53 54 itk::DerivativeOperator<ImageType> operator; 55 operator->SetOrder(1); 56 operator->SetDirection(0); 57 operator->CreateDirectional(); 58 59 itk::NeighborhoodIterator<ImageType> 60 iterator(operator->GetRadius(), myImage, myImage->GetRequestedRegion()); 61 62 iterator.SetToBegin(); 63 while ( ! iterator.IsAtEnd() ) 64 { 65 std::cout << "Derivative at index " << iterator.GetIndex() << is << 66 innerProduct(iterator, operator) << std::endl; 67 ++iterator; 68 } 69 \endcode 70 * 71 * Most of the work for the programmer in the code above is in setting up for 72 * the iteration. There are three steps. First an inner product function 73 * object is created which will be used to effect convolution with the 74 * derivative kernel. Setting up the derivative kernel, DerivativeOperator, 75 * involves setting the order and direction of the derivative. Finally, we 76 * create an iterator over the RequestedRegion of the itk::Image (see Image) 77 * using the radius of the derivative kernel as the size. 78 * 79 * Itk iterators only loosely follow STL conventions. Notice that instead of 80 * asking myImage for myImage.begin() and myImage.end(), iterator.SetToBegin() 81 * and iterator.IsAtEnd() are called. Itk iterators are typically more complex 82 * objects than traditional, pointer-style STL iterators, and the increased 83 * overhead required to conform to the complete STL API is not always 84 * justified. 85 * 86 * The API for creating and manipulating a NeighborhoodIterator mimics 87 * that of the itk::ImageIterators. Like the itk::ImageIterator, a 88 * ConstNeighborhoodIterator is defined on a region of interest in an itk::Image. 89 * Iteration is constrained within that region of interest. 90 * 91 * A NeighborhoodIterator is constructed as a container of pointers (offsets) 92 * to a geometric neighborhood of image pixels. As the central pixel position 93 * in the mask is moved around the image, the neighboring pixel pointers 94 * (offsets) are moved accordingly. 95 * 96 * A \em pixel \em neighborhood is defined as a central pixel location and an 97 * N-dimensional radius extending outward from that location. 98 * 99 * Pixels in a neighborhood can be accessed through a NeighborhoodIterator 100 * like elements in an array. For example, a 2D neighborhood with radius 2x1 101 * has indices: 102 * 103 \code 104 0 1 2 3 4 105 5 6 7 8 9 106 10 11 12 13 14 107 \endcode 108 * 109 * Now suppose a NeighborhoodIterator with the above dimensions is constructed 110 * and positioned over a neighborhood of values in an Image: 111 * 112 \code 113 1.2 1.3 1.8 1.4 1.1 114 1.8 1.1 0.7 1.0 1.0 115 2.1 1.9 1.7 1.4 2.0 116 \endcode 117 * 118 * Shown below is some sample pixel access code and the values that it returns. 119 * 120 \code 121 SizeValueType c = (SizeValueType) (iterator.Size() / 2); // get offset of center pixel 122 SizeValueType s = iterator.GetStride(1); // y-dimension step size 123 124 std::cout << iterator.GetPixel(7) << std::endl; 125 std::cout << iterator.GetCenterPixel() << std::endl; 126 std::cout << iterator.GetPixel(c) << std::endl; 127 std::cout << iterator.GetPixel(c-1) << std::endl; 128 std::cout << iterator.GetPixel(c-s) << std::endl; 129 std::cout << iterator.GetPixel(c-s-1) << std::endl; 130 std::cout << *iterator[c] << std::endl; 131 \endcode 132 * 133 * Results: 134 * 135 \code 136 0.7 137 0.7 138 0.7 139 1.1 140 1.8 141 1.3 142 0.7 143 \endcode 144 * 145 * Use of GetPixel() is preferred over the *iterator[] form, and can be used 146 * without loss of efficiency in most cases. Some variations (subclasses) of 147 * NeighborhoodIterators may exist which do not support the latter 148 * API. Corresponding SetPixel() methods exist to modify pixel values in 149 * non-const NeighborhoodIterators. 150 * 151 * NeighborhoodIterators are "bidirectional iterators". They move only in two 152 * directions through the data set. These directions correspond to the layout 153 * of the image data in memory and not to spatial directions of the 154 * N-dimensional itk::Image. Iteration always proceeds along the fastest 155 * increasing dimension (as defined by the layout of the image data). For 156 * itk::Image this is the first dimension specified (i.e. for 3-dimensional 157 * (x,y,z) NeighborhoodIterator proceeds along the x-dimension) (For random 158 * access iteration through N-dimensional indices, use 159 * RandomAccessNeighborhoodIterator). 160 * 161 * Each subclass of a ConstNeighborhoodIterator may also define its own 162 * mechanism for iteration through an image. In general, the Iterator does not 163 * directly keep track of its spatial location in the image, but uses a set of 164 * internal loop variables and offsets to trigger wraps at itk::Image region 165 * boundaries, and to identify the end of the itk::Image region. 166 * 167 * \todo Better support for regions with negative indices. 168 * \todo Add Begin() and End() methods? 169 * 170 * \sa DerivativeOperator \sa NeighborhoodInnerProduct 171 * 172 * \par MORE INFORMATION 173 * For a complete description of the ITK Image Iterators and their API, please 174 * see the Iterators chapter in the ITK Software Guide. The ITK Software Guide 175 * is available in print and as a free .pdf download from https://www.itk.org. 176 * 177 * \ingroup ImageIterators 178 * 179 * \sa ImageConstIterator \sa ConditionalConstIterator 180 * \sa ConstNeighborhoodIterator \sa ConstShapedNeighborhoodIterator 181 * \sa ConstSliceIterator \sa CorrespondenceDataStructureIterator 182 * \sa FloodFilledFunctionConditionalConstIterator 183 * \sa FloodFilledImageFunctionConditionalConstIterator 184 * \sa FloodFilledImageFunctionConditionalIterator 185 * \sa FloodFilledSpatialFunctionConditionalConstIterator 186 * \sa FloodFilledSpatialFunctionConditionalIterator 187 * \sa ImageConstIterator \sa ImageConstIteratorWithIndex 188 * \sa ImageIterator \sa ImageIteratorWithIndex 189 * \sa ImageLinearConstIteratorWithIndex \sa ImageLinearIteratorWithIndex 190 * \sa ImageRandomConstIteratorWithIndex \sa ImageRandomIteratorWithIndex 191 * \sa ImageRegionConstIterator \sa ImageRegionConstIteratorWithIndex 192 * \sa ImageRegionExclusionConstIteratorWithIndex 193 * \sa ImageRegionExclusionIteratorWithIndex 194 * \sa ImageRegionIterator \sa ImageRegionIteratorWithIndex 195 * \sa ImageRegionReverseConstIterator \sa ImageRegionReverseIterator 196 * \sa ImageReverseConstIterator \sa ImageReverseIterator 197 * \sa ImageSliceConstIteratorWithIndex \sa ImageSliceIteratorWithIndex 198 * \sa NeighborhoodIterator \sa PathConstIterator \sa PathIterator 199 * \sa ShapedNeighborhoodIterator \sa SliceIterator 200 * \sa ImageConstIteratorWithIndex 201 * 202 * \ingroup Operators 203 * \ingroup ITKCommon 204 * 205 * \wiki 206 * \wikiexample{Iterators/NeighborhoodIterator,Iterate over a region of an image with a neighborhood (with write access)} 207 * \wikiexample{VectorImages/NeighborhoodIterator,NeighborhoodIterator on a VectorImage} 208 * \endwiki 209 */ 210 template< typename TImage, typename TBoundaryCondition = 211 ZeroFluxNeumannBoundaryCondition< TImage > > 212 class ITK_TEMPLATE_EXPORT NeighborhoodIterator: 213 public ConstNeighborhoodIterator< TImage, TBoundaryCondition > 214 { 215 public: 216 /** Standard class type aliases. */ 217 using Self = NeighborhoodIterator; 218 using Superclass = ConstNeighborhoodIterator< TImage, TBoundaryCondition >; 219 220 /** Extract type alias from superclass. */ 221 using InternalPixelType = typename Superclass::InternalPixelType; 222 using PixelType = typename Superclass::PixelType; 223 using SizeType = typename Superclass::SizeType; 224 using ImageType = typename Superclass::ImageType; 225 using RegionType = typename Superclass::RegionType; 226 using IndexType = typename Superclass::IndexType; 227 using OffsetType = typename Superclass::OffsetType; 228 using RadiusType = typename Superclass::RadiusType; 229 using NeighborhoodType = typename Superclass::NeighborhoodType; 230 using Iterator = typename Superclass::Iterator; 231 using ConstIterator = typename Superclass::ConstIterator; 232 using ImageBoundaryConditionPointerType = typename Superclass::ImageBoundaryConditionPointerType; 233 234 /** Default constructor. */ NeighborhoodIterator()235 NeighborhoodIterator():Superclass() {} 236 237 /** Copy constructor */ NeighborhoodIterator(const NeighborhoodIterator & n)238 NeighborhoodIterator(const NeighborhoodIterator & n):Superclass(n) {} 239 240 /** Assignment operator */ 241 Self & operator=(const Self & orig) 242 { 243 Superclass::operator=(orig); 244 return *this; 245 } 246 247 /** Constructor which establishes the region size, neighborhood, and image 248 * over which to walk. */ NeighborhoodIterator(const SizeType & radius,ImageType * ptr,const RegionType & region)249 NeighborhoodIterator(const SizeType & radius, ImageType *ptr, 250 const RegionType & region): 251 Superclass(radius, ptr, region) {} 252 253 /** Standard print method */ 254 void PrintSelf(std::ostream &, Indent) const; 255 256 /** Returns the central memory pointer of the neighborhood. */ GetCenterPointer()257 InternalPixelType * GetCenterPointer() 258 { return ( this->operator[]( ( this->Size() ) >> 1 ) ); } 259 260 /** Returns the central pixel of the neighborhood. */ SetCenterPixel(const PixelType & p)261 ITK_ITERATOR_VIRTUAL void SetCenterPixel(const PixelType & p) ITK_ITERATOR_FINAL 262 { this->m_NeighborhoodAccessorFunctor.Set(this->operator[]( ( this->Size() ) >> 1 ), p); } 263 264 /** Virtual function that replaces the pixel values in the image 265 * neighborhood that are pointed to by this NeighborhoodIterator with 266 * the pixel values contained in a Neighborhood. */ 267 ITK_ITERATOR_VIRTUAL void SetNeighborhood(const NeighborhoodType &) ITK_ITERATOR_FINAL; 268 269 /** Special SetPixel method which quietly ignores out-of-bounds attempts. 270 * Sets status TRUE if pixel has been set, FALSE otherwise. */ 271 ITK_ITERATOR_VIRTUAL void SetPixel(const unsigned i, const PixelType & v, 272 bool & status) ITK_ITERATOR_FINAL; 273 274 /** Set the pixel at the ith location. */ 275 ITK_ITERATOR_VIRTUAL void SetPixel(const unsigned i, const PixelType & v) ITK_ITERATOR_FINAL; 276 277 // { *(this->operator[](i)) = v; } 278 279 /** Set the pixel at offset o from the neighborhood center */ SetPixel(const OffsetType o,const PixelType & v)280 ITK_ITERATOR_VIRTUAL void SetPixel(const OffsetType o, const PixelType & v) ITK_ITERATOR_FINAL 281 { this->SetPixel(this->GetNeighborhoodIndex(o), v); } 282 // { *(this->operator[](o)) = v; } 283 284 /** Sets the pixel value located i pixels distant from the neighborhood center in 285 the positive specified "axis" direction. No bounds checking is done on 286 the size of the neighborhood. */ SetNext(const unsigned axis,const unsigned i,const PixelType & v)287 ITK_ITERATOR_VIRTUAL void SetNext(const unsigned axis, const unsigned i, 288 const PixelType & v) ITK_ITERATOR_FINAL 289 { 290 this->SetPixel(this->GetCenterNeighborhoodIndex() 291 + ( i * this->GetStride(axis) ), v); 292 } 293 294 /** Sets the pixel value located one pixel distant from the neighborhood center in 295 the specifed positive axis direction. No bounds checking is done on the 296 size of the neighborhood. */ SetNext(const unsigned axis,const PixelType & v)297 ITK_ITERATOR_VIRTUAL void SetNext(const unsigned axis, const PixelType & v) ITK_ITERATOR_FINAL 298 { 299 this->SetPixel(this->GetCenterNeighborhoodIndex() 300 + this->GetStride(axis), v); 301 } 302 303 /** Sets the pixel value located i pixels distant from the neighborhood center in 304 the negative specified "axis" direction. No bounds checking is done on 305 the size of the neighborhood. */ SetPrevious(const unsigned axis,const unsigned i,const PixelType & v)306 ITK_ITERATOR_VIRTUAL void SetPrevious(const unsigned axis, const unsigned i, 307 const PixelType & v) ITK_ITERATOR_FINAL 308 { 309 this->SetPixel(this->GetCenterNeighborhoodIndex() 310 - ( i * this->GetStride(axis) ), v); 311 } 312 313 /** Sets the pixel value located one pixel distant from the neighborhood center in 314 the specifed negative axis direction. No bounds checking is done on the 315 size of the neighborhood. */ SetPrevious(const unsigned axis,const PixelType & v)316 ITK_ITERATOR_VIRTUAL void SetPrevious(const unsigned axis, 317 const PixelType & v) ITK_ITERATOR_FINAL 318 { 319 this->SetPixel(this->GetCenterNeighborhoodIndex() 320 - this->GetStride(axis), v); 321 } 322 }; 323 } // namespace itk 324 325 #ifndef ITK_MANUAL_INSTANTIATION 326 #include "itkNeighborhoodIterator.hxx" 327 #endif 328 329 #endif 330