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 19 #ifndef itkRectangularImageNeighborhoodShape_h 20 #define itkRectangularImageNeighborhoodShape_h 21 22 #include <algorithm> // For transform. 23 #include <cassert> 24 25 #include "itkOffset.h" 26 #include "itkSize.h" 27 28 namespace itk 29 { 30 namespace Experimental 31 { 32 33 /** 34 * \class RectangularImageNeighborhoodShape 35 * Rectangular (or hyperrectangular) image-neighborhood shape. 36 * Eases creating a sequence of offsets for ShapedImageNeighborhoodRange. 37 * Can also be used for ShapedNeighborhoodIterator. 38 * 39 * The following example creates a 3 x 5 rectangular neighborhood around 40 * pixel location [10, 20], and generates the offsets for a neighborhood range: 41 \code 42 const Index<> location = { 10, 20 }; 43 const Size<> radius = { { 1, 2 } }; 44 const RectangularImageNeighborhoodShape<2> shape{ radius }; 45 const std::vector<Offset<>> offsets = GenerateImageNeighborhoodOffsets(shape); 46 ShapedImageNeighborhoodRange<ImageType> neighborhoodRange{ *image, location, offsets }; 47 \endcode 48 * 49 * \see ShapedNeighborhoodIterator 50 * \see ShapedImageNeighborhoodRange 51 * \ingroup ImageIterators 52 * \ingroup ITKCommon 53 */ 54 template <unsigned int VImageDimension> 55 class RectangularImageNeighborhoodShape 56 { 57 public: 58 static constexpr unsigned int ImageDimension = VImageDimension; 59 60 /** Constructs a hyperrectangular shape whose size is specified by the radius */ RectangularImageNeighborhoodShape(const Size<ImageDimension> & radius)61 constexpr explicit RectangularImageNeighborhoodShape( 62 const Size<ImageDimension>& radius) ITK_NOEXCEPT 63 : 64 m_Radius(radius), 65 m_NumberOfOffsets(CalculateNumberOfOffsets(ImageDimension)) 66 { 67 } 68 69 70 /** Returns the number of offsets needed to represent this shape. */ GetNumberOfOffsets()71 constexpr std::size_t GetNumberOfOffsets() const ITK_NOEXCEPT 72 { 73 return m_NumberOfOffsets; 74 } 75 76 77 /** Fills the specified buffer with the offsets for a neighborhood of this shape. */ FillOffsets(Offset<ImageDimension> * const offsets)78 void FillOffsets(Offset<ImageDimension>* const offsets) const ITK_NOEXCEPT 79 { 80 if (m_NumberOfOffsets > 0) 81 { 82 assert(offsets != nullptr); 83 Offset<ImageDimension> offset; 84 85 std::transform(m_Radius.begin(), m_Radius.end(), offset.begin(), [](const SizeValueType radiusValue) 86 { 87 return -static_cast<OffsetValueType>(radiusValue); 88 }); 89 90 for (std::size_t i = 0; i < m_NumberOfOffsets; ++i) 91 { 92 offsets[i] = offset; 93 94 for (unsigned dimensionIndex = 0; dimensionIndex < ImageDimension; ++dimensionIndex) 95 { 96 OffsetValueType& offsetValue = offset[dimensionIndex]; 97 98 ++offsetValue; 99 100 if (offsetValue <= static_cast<OffsetValueType>(m_Radius[dimensionIndex])) 101 { 102 break; 103 } 104 offsetValue = -static_cast<OffsetValueType>(m_Radius[dimensionIndex]); 105 } 106 } 107 } 108 } 109 110 private: 111 // The radius of the neighborhood along each direction. 112 Size<ImageDimension> m_Radius; 113 114 // The number of offsets needed to represent this shape. 115 std::size_t m_NumberOfOffsets; 116 117 118 // Private helper function to calculate the number of Offsets by a recursive 119 // function call. Recursion is necessary for C++11 constexpr. CalculateNumberOfOffsets(const unsigned dimension)120 constexpr std::size_t CalculateNumberOfOffsets(const unsigned dimension) const ITK_NOEXCEPT 121 { 122 return (dimension == 0) ? 1 : 123 (2 * m_Radius.m_InternalArray[dimension - 1] + 1) * CalculateNumberOfOffsets(dimension - 1); 124 } 125 126 }; 127 128 } // namespace Experimental 129 } // namespace itk 130 131 #endif 132