ITK  5.1.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  * 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 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 namespace Experimental
43 {
44 
98 template <unsigned int VImageDimension>
100 {
101 public:
102  static constexpr unsigned int ImageDimension = VImageDimension;
104 
116  constexpr explicit ConnectedImageNeighborhoodShape(const std::size_t maximumCityblockDistance,
117  const bool includeCenterPixel) ITK_NOEXCEPT
118  : m_MaximumCityblockDistance{ maximumCityblockDistance }
119  , m_IncludeCenterPixel{ includeCenterPixel }
120  , m_NumberOfOffsets{ CalculateNumberOfOffsets(maximumCityblockDistance, includeCenterPixel) }
121  {}
123 
124 
126  constexpr std::size_t
127  GetNumberOfOffsets() const ITK_NOEXCEPT
128  {
129  return m_NumberOfOffsets;
130  }
131 
132 
134  void
135  FillOffsets(Offset<ImageDimension> * const offsets) const ITK_NOEXCEPT
136  {
137  if (m_NumberOfOffsets > 0)
138  {
139  assert(offsets != nullptr);
140  Offset<ImageDimension> offset;
141  std::fill_n(offset.begin(), ImageDimension, -1);
143 
144  std::size_t i = 0;
145 
146  while (i < m_NumberOfOffsets)
147  {
148  const std::size_t numberOfNonZeroOffsetValues =
149  ImageDimension - static_cast<std::size_t>(std::count(offset.begin(), offset.end(), 0));
150 
151  if ((m_IncludeCenterPixel || (numberOfNonZeroOffsetValues > 0)) &&
152  (numberOfNonZeroOffsetValues <= m_MaximumCityblockDistance))
153  {
154  offsets[i] = offset;
155  ++i;
156  }
157 
158  // Go to the next offset:
159  for (unsigned int direction = 0; direction < ImageDimension; ++direction)
160  {
161  auto & offsetValue = offset[direction];
162 
163  ++offsetValue;
164 
165  if (offsetValue <= 1)
166  {
167  break;
168  }
169  offsetValue = -1;
170  }
171  };
172  }
173  }
174 
175 private:
176  // The maximum city-block distance (Manhattan distance) between the center
177  // pixel and each connected neighbor pixel.
179 
180  // Specifies whether or not the center pixel (offset zero) should be included
181  // with the offsets for this shape.
183 
184  // The number of offsets needed to represent this shape.
185  std::size_t m_NumberOfOffsets;
186 
187 
188  // Calculates a + b. Numeric overflow triggers a compilation error in
189  // "constexpr context" and a debug assert failure at run-time.
190  static constexpr std::uintmax_t
191  CalculateSum(const std::uintmax_t a, const std::uintmax_t b) ITK_NOEXCEPT
192  {
193  return ((a + b) >= a) && ((a + b) >= b) ? (a + b) : (ITK_X_ASSERT(!"CalculateSum overflow!"), 0);
194  }
195 
196 
197  // Calculates 2 ^ n. Numeric overflow triggers a compilation error in
198  // "constexpr context" and a debug assert failure at run-time.
199  static constexpr std::uintmax_t
200  CalculatePowerOfTwo(const std::size_t n) ITK_NOEXCEPT
201  {
202  return (n < std::numeric_limits<std::uintmax_t>::digits) ? (std::uintmax_t{ 1 } << n)
203  : (ITK_X_ASSERT(!"CalculatePowerOfTwo overflow!"), 0);
204  }
205 
206 
207  // Calculates the binomial coefficient, 'n' over 'k'.
208  // Inspired by the 'binom' function from Walter, June 23, 2017:
209  // https://stackoverflow.com/questions/44718971/calculate-binomial-coffeficient-very-reliable/44719165#44719165
210  // Optimized for small values of 'k' (k <= n/2).
211  static constexpr std::uintmax_t
213  {
214  return (k > n) ? (ITK_X_ASSERT(!"Out of range!"), 0)
215  : (k == 0) ? 1 : Math::UnsignedProduct(n, CalculateBinomialCoefficient(n - 1, k - 1)) / k;
216  }
217 
218 
219  // Calculates the number of m-dimensional hypercubes on the boundary of an
220  // n-cube, as described at https://en.wikipedia.org/wiki/Hypercube#Elements
221  // (Which refers to H.S.M. Coxeter, Regular polytopes, 3rd ed., 1973, p.120.)
222  static constexpr std::size_t
223  CalculateNumberOfHypercubesOnBoundaryOfCube(const std::size_t m, const std::size_t n) ITK_NOEXCEPT
224  {
225  // Calculate 2^(n-m) * BinomialCoefficient(n, m)
227  (((2 * m) < n) ?
228  // Calculate either the binomial coefficient of (n, m) or (n, n - m).
229  // Mathematically, both should yield the same number, but the
230  // calculation is optimized for a smaller second argument.
232  : CalculateBinomialCoefficient(n, n - m)));
233  }
234 
235 
236  // Iterates recursively from i = ImageDimension-1 down to m (inclusive).
237  static constexpr std::size_t
238  CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(const std::size_t i, const std::size_t m) ITK_NOEXCEPT
239  {
240  return ITK_X_ASSERT(i >= m),
242  ((i <= m) ? 0 : CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(i - 1, m)));
243  }
244 
245 
247  static constexpr std::size_t
248  CalculateNumberOfConnectedNeighbors(const std::size_t maximumCityblockDistance) ITK_NOEXCEPT
249  {
250  return (((maximumCityblockDistance == 0) || (ImageDimension == 0))
251  ? 0
252  : ((maximumCityblockDistance >= ImageDimension)
255  (ImageDimension - maximumCityblockDistance))));
256  }
257 
258 
260  static constexpr std::size_t
261  CalculateNumberOfOffsets(const std::size_t maximumCityblockDistance, const bool includeCenterPixel) ITK_NOEXCEPT
262  {
263  return (includeCenterPixel ? 1 : 0) + CalculateNumberOfConnectedNeighbors(maximumCityblockDistance);
264  }
265 
266 
267  template <unsigned int VImageDimensionOfFriend, std::size_t VMaximumCityblockDistance, bool VIncludeCenterPixel>
268  friend std::array<
271  VIncludeCenterPixel)>
273 };
274 
275 
277 template <unsigned int VImageDimension, std::size_t VMaximumCityblockDistance, bool VIncludeCenterPixel>
278 std::array<Offset<VImageDimension>,
279  ConnectedImageNeighborhoodShape<VImageDimension>::CalculateNumberOfOffsets(VMaximumCityblockDistance,
280  VIncludeCenterPixel)>
282 {
283  constexpr ConnectedImageNeighborhoodShape<VImageDimension> shape{ VMaximumCityblockDistance, VIncludeCenterPixel };
284  std::array<Offset<VImageDimension>, shape.GetNumberOfOffsets()> offsets;
285  shape.FillOffsets(offsets.data());
286  return offsets;
287 }
289 
290 } // namespace Experimental
291 } // namespace itk
292 
293 #undef ITK_X_ASSERT
294 
295 #endif
itk::Experimental::ConnectedImageNeighborhoodShape::CalculateSumOfNumberOfHypercubesOnBoundaryOfCube
static constexpr std::vcl_size_t CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(const std::vcl_size_t i, const std::vcl_size_t m) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:238
itk::Experimental::ConnectedImageNeighborhoodShape
Definition: itkConnectedImageNeighborhoodShape.h:99
itk::Experimental::ConnectedImageNeighborhoodShape::ConnectedImageNeighborhoodShape
constexpr ConnectedImageNeighborhoodShape(const std::vcl_size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:116
itkOffset.h
itk::Experimental::ConnectedImageNeighborhoodShape::GetNumberOfOffsets
constexpr std::vcl_size_t GetNumberOfOffsets() const noexcept
Definition: itkConnectedImageNeighborhoodShape.h:127
itk::Experimental::ConnectedImageNeighborhoodShape::m_IncludeCenterPixel
bool m_IncludeCenterPixel
Definition: itkConnectedImageNeighborhoodShape.h:182
itk::Experimental::ConnectedImageNeighborhoodShape::CalculateNumberOfConnectedNeighbors
static constexpr std::vcl_size_t CalculateNumberOfConnectedNeighbors(const std::vcl_size_t maximumCityblockDistance) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:248
itk::Experimental::ConnectedImageNeighborhoodShape::ImageDimension
static constexpr unsigned int ImageDimension
Definition: itkConnectedImageNeighborhoodShape.h:102
itk::Experimental::ConnectedImageNeighborhoodShape::m_MaximumCityblockDistance
std::vcl_size_t m_MaximumCityblockDistance
Definition: itkConnectedImageNeighborhoodShape.h:178
itk::Math::UnsignedPower
constexpr TReturnType UnsignedPower(const std::uintmax_t base, const std::uintmax_t exponent) noexcept
Definition: itkMath.h:802
itk::Experimental::ConnectedImageNeighborhoodShape::CalculateNumberOfHypercubesOnBoundaryOfCube
static constexpr std::vcl_size_t CalculateNumberOfHypercubesOnBoundaryOfCube(const std::vcl_size_t m, const std::vcl_size_t n) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:223
itk::Experimental::ConnectedImageNeighborhoodShape::CalculateSum
static constexpr std::uintmax_t CalculateSum(const std::uintmax_t a, const std::uintmax_t b) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:191
itk::uintmax_t
::uintmax_t uintmax_t
Definition: itkIntTypes.h:56
itk::Experimental::ConnectedImageNeighborhoodShape::GenerateConnectedImageNeighborhoodShapeOffsets
friend std::array< Offset< VImageDimensionOfFriend >, ConnectedImageNeighborhoodShape< VImageDimensionOfFriend >::CalculateNumberOfOffsets(VMaximumCityblockDistance, VIncludeCenterPixel)> GenerateConnectedImageNeighborhoodShapeOffsets() noexcept
Definition: itkConnectedImageNeighborhoodShape.h:281
itk::Experimental::ConnectedImageNeighborhoodShape::CalculateBinomialCoefficient
static constexpr std::uintmax_t CalculateBinomialCoefficient(const std::uintmax_t n, const std::uintmax_t k) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:212
itk::Offset< ImageDimension >
itk::Experimental::ConnectedImageNeighborhoodShape::m_NumberOfOffsets
std::vcl_size_t m_NumberOfOffsets
Definition: itkConnectedImageNeighborhoodShape.h:185
itk
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
Definition: itkArray.h:26
itk::Math::UnsignedProduct
constexpr TReturnType UnsignedProduct(const std::uintmax_t a, const std::uintmax_t b) noexcept
Definition: itkMath.h:780
itk::Offset::begin
iterator begin()
Definition: itkOffset.h:311
ITK_X_ASSERT
#define ITK_X_ASSERT(CHECK)
Definition: itkConnectedImageNeighborhoodShape.h:37
itk::Experimental::ConnectedImageNeighborhoodShape::CalculateNumberOfOffsets
static constexpr std::vcl_size_t CalculateNumberOfOffsets(const std::vcl_size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:261
itk::Experimental::ConnectedImageNeighborhoodShape::CalculatePowerOfTwo
static constexpr std::uintmax_t CalculatePowerOfTwo(const std::vcl_size_t n) noexcept
Definition: itkConnectedImageNeighborhoodShape.h:200
itkMath.h
itk::Experimental::ConnectedImageNeighborhoodShape::FillOffsets
void FillOffsets(Offset< ImageDimension > *const offsets) const noexcept
Definition: itkConnectedImageNeighborhoodShape.h:135
itk::Offset::end
iterator end()
Definition: itkOffset.h:323