ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
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 "itkIntTypes.h" // For uintmax_t
23#include "itkMath.h"
24#include "itkOffset.h"
25
26#include <array>
27#include <cassert>
28#include <limits>
29
30namespace itk
31{
32
87
88template <unsigned int VImageDimension>
90{
91public:
92 static constexpr unsigned int ImageDimension = VImageDimension;
93
105 constexpr explicit ConnectedImageNeighborhoodShape(const size_t maximumCityblockDistance,
106 const bool includeCenterPixel) noexcept
107 : m_MaximumCityblockDistance{ maximumCityblockDistance }
108 , m_IncludeCenterPixel{ includeCenterPixel }
109 , m_NumberOfOffsets{ CalculateNumberOfOffsets(maximumCityblockDistance, includeCenterPixel) }
110 {}
111
112
113
115 constexpr size_t
116 GetNumberOfOffsets() const noexcept
117 {
118 return m_NumberOfOffsets;
119 }
120
121
123 void
124 FillOffsets(Offset<ImageDimension> * const offsets) const noexcept
125 {
126 if (m_NumberOfOffsets > 0)
127 {
128 assert(offsets != nullptr);
130 std::fill_n(offset.begin(), ImageDimension, -1);
132
133 size_t i = 0;
134
135 while (i < m_NumberOfOffsets)
136 {
137 const size_t numberOfNonZeroOffsetValues =
138 ImageDimension - static_cast<size_t>(std::count(offset.begin(), offset.end(), 0));
139
140 if ((m_IncludeCenterPixel || (numberOfNonZeroOffsetValues > 0)) &&
141 (numberOfNonZeroOffsetValues <= m_MaximumCityblockDistance))
142 {
143 offsets[i] = offset;
144 ++i;
145 }
146
147 // Go to the next offset:
148 for (unsigned int direction = 0; direction < ImageDimension; ++direction)
149 {
150 auto & offsetValue = offset[direction];
151
152 ++offsetValue;
153
154 if (offsetValue <= 1)
155 {
156 break;
157 }
158 offsetValue = -1;
159 }
160 }
161 }
162 }
163
164private:
165 // The maximum city-block distance (Manhattan distance) between the center
166 // pixel and each connected neighbor pixel.
168
169 // Specifies whether or not the center pixel (offset zero) should be included
170 // with the offsets for this shape.
172
173 // The number of offsets needed to represent this shape.
175
176
177 // Calculates a + b. Numeric overflow triggers a compilation error in
178 // "constexpr context" and a debug assert failure at run-time.
179 static constexpr uintmax_t
180 CalculateSum(const uintmax_t a, const uintmax_t b) noexcept
181 {
182 return ((a + b) >= a) && ((a + b) >= b) ? (a + b) : (assert(!"CalculateSum overflow!"), 0);
183 }
184
185
186 // Calculates 2 ^ n. Numeric overflow triggers a compilation error in
187 // "constexpr context" and a debug assert failure at run-time.
188 static constexpr uintmax_t
189 CalculatePowerOfTwo(const size_t n) noexcept
190 {
191 return (n < std::numeric_limits<uintmax_t>::digits) ? (uintmax_t{ 1 } << n)
192 : (assert(!"CalculatePowerOfTwo overflow!"), 0);
193 }
194
195
196 // Calculates the binomial coefficient, 'n' over 'k'.
197 // Inspired by the 'binom' function from Walter, June 23, 2017:
198 // https://stackoverflow.com/questions/44718971/calculate-binomial-coffeficient-very-reliable/44719165#44719165
199 // Optimized for small values of 'k' (k <= n/2).
200 static constexpr uintmax_t
201 CalculateBinomialCoefficient(const uintmax_t n, const uintmax_t k) noexcept
202 {
203 return (k > n) ? (assert(!"Out of range!"), 0)
204 : (k == 0) ? 1
206 }
207
208
209 // Calculates the number of m-dimensional hypercubes on the boundary of an
210 // n-cube, as described at https://en.wikipedia.org/wiki/Hypercube#Elements
211 // (Which refers to H.S.M. Coxeter, Regular polytopes, 3rd ed., 1973, p.120.)
212 static constexpr size_t
213 CalculateNumberOfHypercubesOnBoundaryOfCube(const size_t m, const size_t n) noexcept
214 {
215 // Calculate 2^(n-m) * BinomialCoefficient(n, m)
217 (((2 * m) < n) ?
218 // Calculate either the binomial coefficient of (n, m) or (n, n - m).
219 // Mathematically, both should yield the same number, but the
220 // calculation is optimized for a smaller second argument.
222 : CalculateBinomialCoefficient(n, n - m)));
223 }
224
225
226 // Iterates recursively from i = ImageDimension-1 down to m (inclusive).
227 static constexpr size_t
228 CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(const size_t i, const size_t m) noexcept
229 {
231 ((i <= m) ? 0 : CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(i - 1, m)));
232 }
233
234
236 static constexpr size_t
237 CalculateNumberOfConnectedNeighbors(const size_t maximumCityblockDistance) noexcept
238 {
239 return (((maximumCityblockDistance == 0) || (ImageDimension == 0))
240 ? 0
241 : ((maximumCityblockDistance >= ImageDimension)
244 (ImageDimension - maximumCityblockDistance))));
245 }
246
247
249 static constexpr size_t
250 CalculateNumberOfOffsets(const size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
251 {
252 return (includeCenterPixel ? 1 : 0) + CalculateNumberOfConnectedNeighbors(maximumCityblockDistance);
253 }
254};
255
256
258template <unsigned int VImageDimension, size_t VMaximumCityblockDistance, bool VIncludeCenterPixel>
259auto
261{
262 constexpr ConnectedImageNeighborhoodShape<VImageDimension> shape{ VMaximumCityblockDistance, VIncludeCenterPixel };
263 std::array<Offset<VImageDimension>, shape.GetNumberOfOffsets()> offsets;
264 shape.FillOffsets(offsets.data());
265 return offsets;
266}
267
268
269} // namespace itk
270
271#endif
static constexpr vcl_size_t CalculateNumberOfConnectedNeighbors(const vcl_size_t maximumCityblockDistance) noexcept
static constexpr vcl_size_t CalculateNumberOfOffsets(const vcl_size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
static constexpr uintmax_t CalculatePowerOfTwo(const vcl_size_t n) noexcept
constexpr vcl_size_t GetNumberOfOffsets() const noexcept
static constexpr vcl_size_t CalculateSumOfNumberOfHypercubesOnBoundaryOfCube(const vcl_size_t i, const vcl_size_t m) noexcept
static constexpr uintmax_t CalculateSum(const uintmax_t a, const uintmax_t b) noexcept
static constexpr vcl_size_t CalculateNumberOfHypercubesOnBoundaryOfCube(const vcl_size_t m, const vcl_size_t n) noexcept
constexpr ConnectedImageNeighborhoodShape(const vcl_size_t maximumCityblockDistance, const bool includeCenterPixel) noexcept
static constexpr uintmax_t CalculateBinomialCoefficient(const uintmax_t n, const uintmax_t k) noexcept
void FillOffsets(Offset< ImageDimension > *const offsets) const noexcept
constexpr TReturnType UnsignedPower(const uintmax_t base, const uintmax_t exponent) noexcept
Definition itkMath.h:791
constexpr TReturnType UnsignedProduct(const uintmax_t a, const uintmax_t b) noexcept
Definition itkMath.h:769
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
auto GenerateConnectedImageNeighborhoodShapeOffsets() noexcept
Represent a n-dimensional offset between two n-dimensional indexes of n-dimensional image.
Definition itkOffset.h:67
constexpr iterator begin()
Definition itkOffset.h:316
constexpr iterator end()
Definition itkOffset.h:334