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