ITK  5.3.0
Insight Toolkit
itkConnectedImageNeighborhoodShape.h
Go to the documentation of this file.
1 /*=========================================================================
2  *
3  * Copyright NumFOCUS
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  * https://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 itkConnectedImageNeighborhoodShape_h
20 #define itkConnectedImageNeighborhoodShape_h
21 
22 #include "itkMath.h"
23 #include "itkOffset.h"
24 
25 #include <array>
26 #include <cassert>
27 #include <cstdint> // For uintmax_t
28 #include <limits>
29 
30 // C++11 does not guarantee that assert can be used in constexpr
31 // functions. This is a work-around for GCC 4.8, 4.9. Originating
32 // from Andrzej's C++ blog:
33 // https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
34 #if defined NDEBUG
35 # define ITK_X_ASSERT(CHECK) void(0)
36 #else
37 # define ITK_X_ASSERT(CHECK) ((CHECK) ? void(0) : [] { assert(!#CHECK); }())
38 #endif
39 
40 namespace itk
41 {
42 
96 template <unsigned int VImageDimension>
98 {
99 public:
100  static constexpr unsigned int ImageDimension = VImageDimension;
114  constexpr explicit ConnectedImageNeighborhoodShape(const size_t maximumCityblockDistance,
115  const bool includeCenterPixel) noexcept
116  : m_MaximumCityblockDistance{ maximumCityblockDistance }
117  , m_IncludeCenterPixel{ includeCenterPixel }
118  , m_NumberOfOffsets{ CalculateNumberOfOffsets(maximumCityblockDistance, includeCenterPixel) }
119  {}
124  constexpr size_t
125  GetNumberOfOffsets() const noexcept
126  {
127  return m_NumberOfOffsets;
128  }
129 
130 
132  void
133  FillOffsets(Offset<ImageDimension> * const offsets) const noexcept
134  {
135  if (m_NumberOfOffsets > 0)
136  {
137  assert(offsets != nullptr);
138  Offset<ImageDimension> offset;
139  std::fill_n(offset.begin(), ImageDimension, -1);
142  size_t i = 0;
143 
144  while (i < m_NumberOfOffsets)
145  {
146  const size_t numberOfNonZeroOffsetValues =
147  ImageDimension - static_cast<size_t>(std::count(offset.begin(), offset.end(), 0));
148 
149  if ((m_IncludeCenterPixel || (numberOfNonZeroOffsetValues > 0)) &&
150  (numberOfNonZeroOffsetValues <= m_MaximumCityblockDistance))
151  {
152  offsets[i] = offset;
153  ++i;
154  }
155 
156  // Go to the next offset:
157  for (unsigned int direction = 0; direction < ImageDimension; ++direction)
158  {
159  auto & offsetValue = offset[direction];
160 
161  ++offsetValue;
162 
163  if (offsetValue <= 1)
164  {
165  break;
166  }
167  offsetValue = -1;
168  }
169  }
170  }
171  }
172 
173 private:
174  // The maximum city-block distance (Manhattan distance) between the center
175  // pixel and each connected neighbor pixel.
177 
178  // Specifies whether or not the center pixel (offset zero) should be included
179  // with the offsets for this shape.
181 
182  // The number of offsets needed to represent this shape.
184 
185 
186  // Calculates a + b. Numeric overflow triggers a compilation error in
187  // "constexpr context" and a debug assert failure at run-time.
188  static constexpr uintmax_t
189  CalculateSum(const uintmax_t a, const uintmax_t b) noexcept
190  {
191  return ((a + b) >= a) && ((a + b) >= b) ? (a + b) : (ITK_X_ASSERT(!"CalculateSum overflow!"), 0);
192  }
193 
194 
195  // Calculates 2 ^ n. Numeric overflow triggers a compilation error in
196  // "constexpr context" and a debug assert failure at run-time.
197  static constexpr uintmax_t
198  CalculatePowerOfTwo(const size_t n) noexcept
199  {
200  return (n < std::numeric_limits<uintmax_t>::digits) ? (uintmax_t{ 1 } << n)
201  : (ITK_X_ASSERT(!"CalculatePowerOfTwo overflow!"), 0);
202  }
203 
204 
205  // Calculates the binomial coefficient, 'n' over 'k'.
206  // Inspired by the 'binom' function from Walter, June 23, 2017:
207  // https://stackoverflow.com/questions/44718971/calculate-binomial-coffeficient-very-reliable/44719165#44719165
208  // Optimized for small values of 'k' (k <= n/2).
209  static constexpr uintmax_t
210  CalculateBinomialCoefficient(const uintmax_t n, const uintmax_t k) noexcept
211  {
212  return (k > n) ? (ITK_X_ASSERT(!"Out of range!"), 0)
213  : (k == 0) ? 1 : Math::UnsignedProduct(n, CalculateBinomialCoefficient(n - 1, k - 1)) / k;
214  }
215 
216 
217  // Calculates the number of m-dimensional hypercubes on the boundary of an
218  // n-cube, as described at https://en.wikipedia.org/wiki/Hypercube#Elements
219  // (Which refers to H.S.M. Coxeter, Regular polytopes, 3rd ed., 1973, p.120.)
220  static constexpr size_t
221  CalculateNumberOfHypercubesOnBoundaryOfCube(const size_t m, const size_t n) noexcept
222  {
223  // Calculate 2^(n-m) * BinomialCoefficient(n, m)
225  (((2 * m) < n) ?
226  // Calculate either the binomial coefficient of (n, m) or (n, n - m).
227  // Mathematically, both should yield the same number, but the
228  // calculation is optimized for a smaller second argument.
230  : CalculateBinomialCoefficient(n, n - m)));
231  }
232 
233 
234  // Iterates recursively from i = ImageDimension-1 down to m (inclusive).
235  static constexpr size_t
236  CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(const size_t i, const size_t m) noexcept
237  {
238  return ITK_X_ASSERT(i >= m),
240  ((i <= m) ? 0 : CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(i - 1, m)));
241  }
242 
243 
245  static constexpr size_t
246  CalculateNumberOfConnectedNeighbors(const size_t maximumCityblockDistance) noexcept
247  {
248  return (((maximumCityblockDistance == 0) || (ImageDimension == 0))
249  ? 0
250  : ((maximumCityblockDistance >= ImageDimension)
253  (ImageDimension - maximumCityblockDistance))));
254  }
255 
256 
258  static constexpr size_t
259  CalculateNumberOfOffsets(const size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
260  {
261  return (includeCenterPixel ? 1 : 0) + CalculateNumberOfConnectedNeighbors(maximumCityblockDistance);
262  }
263 };
268 template <unsigned int VImageDimension, size_t VMaximumCityblockDistance, bool VIncludeCenterPixel>
269 auto
271 {
272  constexpr ConnectedImageNeighborhoodShape<VImageDimension> shape{ VMaximumCityblockDistance, VIncludeCenterPixel };
273  std::array<Offset<VImageDimension>, shape.GetNumberOfOffsets()> offsets;
274  shape.FillOffsets(offsets.data());
275  return offsets;
276 }
279 } // namespace itk
280 
281 #undef ITK_X_ASSERT
282 
283 #endif
itk::ConnectedImageNeighborhoodShape::ImageDimension
static constexpr unsigned int ImageDimension
Definition: itkConnectedImageNeighborhoodShape.h:100
itk::ConnectedImageNeighborhoodShape::CalculatePowerOfTwo
static constexpr uintmax_t CalculatePowerOfTwo(const vcl_size_t n) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:198
itk::Offset::end
constexpr iterator end()
Definition: itkOffset.h:337
itk::Offset::begin
constexpr iterator begin()
Definition: itkOffset.h:319
itk::ConnectedImageNeighborhoodShape::CalculateNumberOfOffsets
static constexpr vcl_size_t CalculateNumberOfOffsets(const vcl_size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:259
itkOffset.h
itk::ConnectedImageNeighborhoodShape
Definition: itkConnectedImageNeighborhoodShape.h:97
itk::Math::UnsignedProduct
constexpr TReturnType UnsignedProduct(const uintmax_t a, const uintmax_t b) noexcept
Definition: itkMath.h:780
itk::ConnectedImageNeighborhoodShape::CalculateBinomialCoefficient
static constexpr uintmax_t CalculateBinomialCoefficient(const uintmax_t n, const uintmax_t k) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:210
itk::ConnectedImageNeighborhoodShape::m_NumberOfOffsets
vcl_size_t m_NumberOfOffsets
Definition: itkConnectedImageNeighborhoodShape.h:183
itk::ConnectedImageNeighborhoodShape::ConnectedImageNeighborhoodShape
constexpr ConnectedImageNeighborhoodShape(const vcl_size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:114
itk::Math::UnsignedPower
constexpr TReturnType UnsignedPower(const uintmax_t base, const uintmax_t exponent) noexcept
Definition: itkMath.h:802
itk::ConnectedImageNeighborhoodShape::CalculateSum
static constexpr uintmax_t CalculateSum(const uintmax_t a, const uintmax_t b) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:189
itk::ConnectedImageNeighborhoodShape::FillOffsets
void FillOffsets(Offset< ImageDimension > *const offsets) const noexcept
Definition: itkConnectedImageNeighborhoodShape.h:133
itk::ConnectedImageNeighborhoodShape::CalculateSumOfNumberOfHypercubesOnBoundaryOfCube
static constexpr vcl_size_t CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(const vcl_size_t i, const vcl_size_t m) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:236
itk::ConnectedImageNeighborhoodShape::CalculateNumberOfConnectedNeighbors
static constexpr vcl_size_t CalculateNumberOfConnectedNeighbors(const vcl_size_t maximumCityblockDistance) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:246
itk::ConnectedImageNeighborhoodShape::CalculateNumberOfHypercubesOnBoundaryOfCube
static constexpr vcl_size_t CalculateNumberOfHypercubesOnBoundaryOfCube(const vcl_size_t m, const vcl_size_t n) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:221
itk::Offset< ImageDimension >
itk::ConnectedImageNeighborhoodShape::m_IncludeCenterPixel
bool m_IncludeCenterPixel
Definition: itkConnectedImageNeighborhoodShape.h:180
itk
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
Definition: itkAnnulusOperator.h:24
itk::ConnectedImageNeighborhoodShape::m_MaximumCityblockDistance
vcl_size_t m_MaximumCityblockDistance
Definition: itkConnectedImageNeighborhoodShape.h:176
itk::ConnectedImageNeighborhoodShape::GetNumberOfOffsets
constexpr vcl_size_t GetNumberOfOffsets() const noexcept
Definition: itkConnectedImageNeighborhoodShape.h:125
ITK_X_ASSERT
#define ITK_X_ASSERT(CHECK)
Definition: itkConnectedImageNeighborhoodShape.h:37
itk::GenerateConnectedImageNeighborhoodShapeOffsets
auto GenerateConnectedImageNeighborhoodShapeOffsets() noexcept
Definition: itkConnectedImageNeighborhoodShape.h:270
itkMath.h