3#include "AttributeTypes.hpp"
9#include <unordered_map>
12namespace mmcfilters::attributes::registry {
17enum class AttributeAdjacencyRequirement { None, UniformOrDirectional, Uniform };
32 AttributeAdjacencyRequirement
adjacency = AttributeAdjacencyRequirement::None;
50inline constexpr AttributeCapabilityRequirements ALTITUDE_REQUIREMENTS{.altitude =
true};
52inline constexpr AttributeCapabilityRequirements GRID_DOMAIN_2D_REQUIREMENTS{.gridDomain2D =
true};
54inline constexpr AttributeCapabilityRequirements BITQUAD_REQUIREMENTS{.gridDomain2D =
true,
55 .adjacency = AttributeAdjacencyRequirement::UniformOrDirectional,
56 .altitudeForDirectionalAdjacency =
true,
57 .canonical4Or8Adjacency =
true};
59inline constexpr AttributeCapabilityRequirements MAX_DIST_REQUIREMENTS{.gridDomain2D =
true};
61inline constexpr AttributeCapabilityRequirements MAX_DIST_EXACT_REQUIREMENTS{.gridDomain2D =
true};
97inline constexpr std::array<AttributeMetadata, static_cast<std::size_t>(Attribute::MaxSquaredDistExact) + 1> ATTRIBUTE_METADATA{
98 {{Area,
"AREA",
"Area: Number of pixels in the connected component.",
false, NO_REQUIREMENTS},
100 "Volume: Sum of the gray-level intensities of all pixels in the connected component. Interpreted as the total mass under the component, or the integral "
101 "of the image function over its support.",
102 false, ALTITUDE_REQUIREMENTS},
103 {RelativeVolume,
"RELATIVE_VOLUME",
104 "Relative volume: Recursive contrast volume R(n) = area(n) + sum_c [R(c) + area(c) * abs(altitude(c) - altitude(n))] over the direct children c.",
105 false, ALTITUDE_REQUIREMENTS},
106 {GrayLevelHeight,
"GRAY_LEVEL_HEIGHT",
107 "Gray-level height: Maximum absolute altitude difference between a node and any node in its subtree. This reduces to the traditional one-sided span on "
108 "monotone max/min trees and also applies to hierarchies with unconstrained altitude order. Leaves have gray-level height 0.",
109 false, ALTITUDE_REQUIREMENTS},
110 {MeanGrayLevel,
"MEAN_GRAY_LEVEL",
"Mean gray level: Arithmetic mean of the image values over the node support.",
false, ALTITUDE_REQUIREMENTS},
111 {GrayLevelVariance,
"GRAY_LEVEL_VARIANCE",
"Gray-level variance: Population variance of the image values over the node support.",
false,
112 ALTITUDE_REQUIREMENTS},
114 {BoxWidth,
"BOX_WIDTH",
"Bounding box width: Width of the minimum rectangle enclosing the connected component.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
115 {BoundingBoxHeight,
"BOUNDING_BOX_HEIGHT",
"Bounding-box height: Height of the minimum rectangle enclosing the connected component.",
true,
116 GRID_DOMAIN_2D_REQUIREMENTS},
117 {DiagonalLength,
"DIAGONAL_LENGTH",
"Diagonal length: Euclidean length of the diagonal of the bounding box, computed as sqrt(width^2 + height^2).",
true,
118 GRID_DOMAIN_2D_REQUIREMENTS},
119 {Rectangularity,
"RECTANGULARITY",
120 "Rectangularity: Ratio between the connected component area and the area of its bounding box. Values closer to 1 indicate shapes that efficiently fill "
121 "their bounding box.",
122 true, GRID_DOMAIN_2D_REQUIREMENTS},
123 {RatioWh,
"RATIO_WH",
"Aspect ratio: Maximum bounding-box extent divided by the minimum extent. Values are at least 1 and describe elongation independently of orientation.",
true,
124 GRID_DOMAIN_2D_REQUIREMENTS},
125 {BoxColumnMin,
"BOX_COLUMN_MIN",
"Bounding box column min: Minimum column index covered by the connected component.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
126 {BoxColumnMax,
"BOX_COLUMN_MAX",
"Bounding box column max: Maximum column index covered by the connected component.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
127 {BoxRowMin,
"BOX_ROW_MIN",
"Bounding box row min: Minimum row index covered by the connected component.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
128 {BoxRowMax,
"BOX_ROW_MAX",
"Bounding box row max: Maximum row index covered by the connected component.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
130 {CentralMoment20,
"CENTRAL_MOMENT_20",
131 "Central moment (2,0): Second-order moment about the centroid along the x-axis. Measures the horizontal spread of the component.",
true,
132 GRID_DOMAIN_2D_REQUIREMENTS},
133 {CentralMoment02,
"CENTRAL_MOMENT_02",
134 "Central moment (0,2): Second-order moment about the centroid along the y-axis. Measures the vertical spread of the component.",
true,
135 GRID_DOMAIN_2D_REQUIREMENTS},
136 {CentralMoment11,
"CENTRAL_MOMENT_11",
137 "Central moment (1,1): Mixed second-order moment about the centroid. Represents the covariance between x and y coordinates.",
true,
138 GRID_DOMAIN_2D_REQUIREMENTS},
139 {CentralMoment30,
"CENTRAL_MOMENT_30",
140 "Central moment (3,0): Third-order moment about the centroid along the x-axis. Describes horizontal asymmetry of the component.",
true,
141 GRID_DOMAIN_2D_REQUIREMENTS},
142 {CentralMoment03,
"CENTRAL_MOMENT_03",
143 "Central moment (0,3): Third-order moment about the centroid along the y-axis. Describes vertical asymmetry of the component.",
true,
144 GRID_DOMAIN_2D_REQUIREMENTS},
145 {CentralMoment21,
"CENTRAL_MOMENT_21",
146 "Central moment (2,1): Mixed third-order moment about the centroid. Captures joint spread and asymmetry in x and y.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
147 {CentralMoment12,
"CENTRAL_MOMENT_12",
148 "Central moment (1,2): Mixed third-order moment about the centroid. Captures joint spread and asymmetry in y and x.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
150 {HuMoment1,
"HU_MOMENT_1",
"Hu moment 1: Invariant to translation, scale, and rotation. Represents overall spatial variance (shape dispersion).",
true,
151 GRID_DOMAIN_2D_REQUIREMENTS},
152 {HuMoment2,
"HU_MOMENT_2",
"Hu moment 2: Invariant capturing the difference between horizontal and vertical spread.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
153 {HuMoment3,
"HU_MOMENT_3",
"Hu moment 3: Sensitive to skewness and asymmetry in the pixel distribution.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
154 {HuMoment4,
"HU_MOMENT_4",
"Hu moment 4: Measures symmetry with respect to diagonal axes.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
155 {HuMoment5,
"HU_MOMENT_5",
"Hu moment 5: Descriptor sensitive to orientation and reflection; captures complex asymmetries.",
true,
156 GRID_DOMAIN_2D_REQUIREMENTS},
157 {HuMoment6,
"HU_MOMENT_6",
"Hu moment 6: Invariant capturing elliptic asymmetries, sensitive to specific shape curvature.",
true,
158 GRID_DOMAIN_2D_REQUIREMENTS},
159 {HuMoment7,
"HU_MOMENT_7",
"Hu moment 7: Highly sensitive to irregularities and fine variations; helps discriminate mirror-symmetric shapes.",
true,
160 GRID_DOMAIN_2D_REQUIREMENTS},
163 "Inertia: Sum of normalized second-order central moments, mu20 / area^2 + mu02 / area^2. This is the same scalar expression as the first Hu moment.",
164 true, GRID_DOMAIN_2D_REQUIREMENTS},
165 {Compactness,
"COMPACTNESS",
166 "Compactness: Area normalized by the shape's dispersion (mu20 + mu02). Higher values indicate more compact and isotropic shapes.",
true,
167 GRID_DOMAIN_2D_REQUIREMENTS},
168 {Eccentricity,
"ECCENTRICITY",
169 "Eccentricity: Ratio of principal inertia eigenvalues (λ_1/λ_2). Measures elongation; values near 1 indicate circularity, higher values indicate "
170 "elongation. Degenerate line-like supports saturate at a finite maximum.",
171 true, GRID_DOMAIN_2D_REQUIREMENTS},
172 {LengthMajorAxis,
"LENGTH_MAJOR_AXIS",
"Major-axis length proxy of the equivalent second-moment ellipse, derived from the largest inertia eigenvalue and support area.",
true,
173 GRID_DOMAIN_2D_REQUIREMENTS},
174 {LengthMinorAxis,
"LENGTH_MINOR_AXIS",
"Minor-axis length proxy of the equivalent second-moment ellipse, derived from the smallest inertia eigenvalue and support area.",
true,
175 GRID_DOMAIN_2D_REQUIREMENTS},
176 {AxisOrientation,
"AXIS_ORIENTATION",
177 "Axis orientation: Angle of the principal inertia axis, computed from central moments. Indicates the dominant orientation of the shape.",
true,
178 GRID_DOMAIN_2D_REQUIREMENTS},
179 {Circularity,
"CIRCULARITY",
180 "Circularity: Ratio of the minor to major eigenvalues of the inertia matrix (λ_2/λ_1), i.e., Inverse of eccentricity. Indicates how circular a shape is; "
181 "values near 1 suggest circularity, values near 0 indicate elongation.",
182 true, GRID_DOMAIN_2D_REQUIREMENTS},
184 {BitquadArea,
"BITQUAD_AREA",
185 "Bitquad area (Duda): Refined sub-pixel area estimation using fractional weights based on the geometric contribution of local 2x2 pixel patterns.",
true,
186 BITQUAD_REQUIREMENTS},
187 {BitquadNumberEuler,
"BITQUAD_NUMBER_EULER",
188 "Bitquad Euler number: Topological invariant computed as the number of connected components minus the number of holes, using 2x2 pattern statistics "
189 "under 4- or 8-connectivity.",
190 true, BITQUAD_REQUIREMENTS},
191 {BitquadNumberHoles,
"BITQUAD_NUMBER_HOLES",
192 "Bitquad number of holes: Number of interior holes in the component, derived from the Euler characteristic assuming a single connected object.",
true,
193 BITQUAD_REQUIREMENTS},
194 {BitquadPerimeter,
"BITQUAD_PERIMETER",
195 "Bitquad perimeter: Discrete approximation of the shape's boundary length, calculated by summing edge-contributing patterns in the 2x2 pixel grid.",
196 true, BITQUAD_REQUIREMENTS},
197 {BitquadPerimeterContinuous,
"BITQUAD_PERIMETER_CONTINUOUS",
198 "Bitquad continuous perimeter: Smoothed boundary-length estimate derived from weighted transitions across local 2x2 bitquad configurations.",
true,
199 BITQUAD_REQUIREMENTS},
200 {BitquadCircularity,
"BITQUAD_CIRCULARITY",
201 "Bitquad circularity: Compactness measure defined as (4π x areaDuda) / perimeter². Values close to 1 indicate circular shapes; lower values suggest "
202 "elongation or irregularity. Degenerate zero-perimeter supports return 0.",
203 true, BITQUAD_REQUIREMENTS},
204 {BitquadPerimeterAverage,
"BITQUAD_PERIMETER_AVERAGE",
205 "Bitquad average perimeter: Mean perimeter per connected component, accounting for complex structures and holes. Non-positive Euler component estimates "
207 true, BITQUAD_REQUIREMENTS},
208 {BitquadLengthAverage,
"BITQUAD_LENGTH_AVERAGE",
209 "Bitquad average length: Estimated average longitudinal extent per component, derived from the average perimeter with a zero fallback for non-positive "
210 "Euler component estimates.",
211 true, BITQUAD_REQUIREMENTS},
212 {BitquadWidthAverage,
"BITQUAD_WIDTH_AVERAGE",
213 "Bitquad average width: Estimated transverse extent per component, computed as (2 x areaDuda) / continuous perimeter with a zero fallback for "
214 "degenerate perimeter.",
215 true, BITQUAD_REQUIREMENTS},
217 {SubtreeHeight,
"SUBTREE_HEIGHT",
"Subtree height: Longest path from this node to any leaf in its subtree, measured in tree edges.",
true,
219 {DepthNode,
"DEPTH_NODE",
"Depth: Number of steps from this node to the root of the tree. Indicates the level of embedding within the tree hierarchy.",
220 true, NO_REQUIREMENTS},
221 {IsLeafNode,
"IS_LEAF_NODE",
"Is leaf: True if the node has no children, i.e., it represents a minimal component in the hierarchy.",
true,
223 {IsRootNode,
"IS_ROOT_NODE",
"Is root: True if the node is the root of the tree, representing the entire image support.",
true, NO_REQUIREMENTS},
224 {NumChildrenNode,
"NUM_CHILDREN_NODE",
"Number of children: Count of direct child nodes. Reflects the immediate branching factor of the node.",
true,
226 {NumSiblingsNode,
"NUM_SIBLINGS_NODE",
"Number of siblings: Number of other nodes that share the same parent.",
true, NO_REQUIREMENTS},
227 {NumDescendantsNode,
"NUM_DESCENDANTS_NODE",
228 "Number of descendants: Total number of nodes in the subtree rooted at this node (excluding the node itself).",
true, NO_REQUIREMENTS},
229 {NumLeafDescendantsNode,
"NUM_LEAF_DESCENDANTS_NODE",
230 "Number of leaf descendants: Number of leaf nodes in the subtree. Reflects the number of minimal patterns under this structure.",
true, NO_REQUIREMENTS},
231 {LeafRatioNode,
"LEAF_RATIO_NODE",
232 "Leaf ratio: Number of leaf descendants divided by subtree size, leaf_descendants / (descendants + 1). Leaves return 1.",
true, NO_REQUIREMENTS},
233 {BalanceNode,
"BALANCE_NODE",
234 "Balance: Difference between the maximum and minimum heights among the subtrees of the children. Indicates branching symmetry.",
true, NO_REQUIREMENTS},
236 {MaxDist,
"MAX_DIST",
237 "Approximate maximum Euclidean distance from the foreground A4 contour over the node support, in pixels, computed by an adaptive A8 dynamic "
238 "image foresting transform.",
239 true, MAX_DIST_REQUIREMENTS},
241 {AvgChildHeightNode,
"AVG_CHILD_HEIGHT_NODE",
242 "Average child height: Mean height of all direct child subtrees. Useful for measuring uniformity of the subtree structure.",
true, NO_REQUIREMENTS},
244 {ContourPixels,
"CONTOUR_PIXELS",
"Contour pixels: Number of support pixels touching the 4-neighbour complement.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
245 {ContourPerimeter,
"CONTOUR_PERIMETER",
"Contour perimeter: 4-neighbour exposed-side perimeter of the support.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
246 {ContourSideNorth,
"CONTOUR_SIDE_NORTH",
"Contour north sides: Number of exposed north sides over support pixels.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
247 {ContourSideWest,
"CONTOUR_SIDE_WEST",
"Contour west sides: Number of exposed west sides over support pixels.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
248 {ContourSideEast,
"CONTOUR_SIDE_EAST",
"Contour east sides: Number of exposed east sides over support pixels.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
249 {ContourSideSouth,
"CONTOUR_SIDE_SOUTH",
"Contour south sides: Number of exposed south sides over support pixels.",
true, GRID_DOMAIN_2D_REQUIREMENTS},
251 {MaxDistExact,
"MAX_DIST_EXACT",
252 "Maximum exact Euclidean distance from the foreground A4 contour over the node support in the original 2D pixel domain, in pixels.",
true,
253 MAX_DIST_EXACT_REQUIREMENTS},
255 {DistSquaredSumExact,
"DIST_SQUARED_SUM_EXACT",
256 "Squared-distance sum: Sum over the node support of the exact squared Euclidean distance to the foreground A4 contour.",
true,
257 MAX_DIST_EXACT_REQUIREMENTS},
258 {DistSquaredMeanExact,
"DIST_SQUARED_MEAN_EXACT",
259 "Squared-distance mean: Arithmetic mean over the node support of the exact squared Euclidean distance to the foreground A4 contour.",
true,
260 MAX_DIST_EXACT_REQUIREMENTS},
261 {DistRmsExact,
"DIST_RMS_EXACT",
262 "Distance RMS: Square root of the mean exact squared Euclidean distance to the foreground A4 contour, in pixel units.",
true,
263 MAX_DIST_EXACT_REQUIREMENTS},
264 {DistSquaredVarianceExact,
"DIST_SQUARED_VARIANCE_EXACT",
265 "Squared-distance variance: Population variance over the node support of the exact squared Euclidean distance to the foreground A4 contour.",
true,
266 MAX_DIST_EXACT_REQUIREMENTS},
268 {DistSquaredSum,
"DIST_SQUARED_SUM",
269 "Approximate squared-distance sum over the node support, computed from the adaptive A8 dynamic image foresting transform.",
true,
270 MAX_DIST_REQUIREMENTS},
271 {DistSquaredMean,
"DIST_SQUARED_MEAN",
272 "Approximate squared-distance mean over the node support, computed from the adaptive A8 dynamic image foresting transform.",
true,
273 MAX_DIST_REQUIREMENTS},
274 {DistRms,
"DIST_RMS",
275 "Approximate distance RMS in pixel units, computed from the adaptive A8 dynamic image foresting transform.",
true,
276 MAX_DIST_REQUIREMENTS},
277 {DistSquaredVariance,
"DIST_SQUARED_VARIANCE",
278 "Approximate population variance of squared distances over the node support, computed from the adaptive A8 dynamic image foresting transform.",
true,
279 MAX_DIST_REQUIREMENTS},
281 {MaxDistCenterRowExact,
"MAX_DIST_CENTER_ROW_EXACT",
282 "Maximum-distance center row: Zero-based row of the smallest row-major support pixel attaining the exact maximum squared contour distance.",
true,
283 MAX_DIST_EXACT_REQUIREMENTS},
284 {MaxDistCenterColumnExact,
"MAX_DIST_CENTER_COLUMN_EXACT",
285 "Maximum-distance center column: Zero-based column of the smallest row-major support pixel attaining the exact maximum squared contour distance.",
286 true, MAX_DIST_EXACT_REQUIREMENTS},
287 {MaxDistCenterRow,
"MAX_DIST_CENTER_ROW",
288 "Approximate maximum-distance center row: Zero-based row of the smallest row-major support pixel attaining the adaptive-A8 DIFT maximum.",
true,
289 MAX_DIST_REQUIREMENTS},
290 {MaxDistCenterColumn,
"MAX_DIST_CENTER_COLUMN",
291 "Approximate maximum-distance center column: Zero-based column of the smallest row-major support pixel attaining the adaptive-A8 DIFT maximum.",
292 true, MAX_DIST_REQUIREMENTS},
294 {MaxDistPlateauAreaExact,
"MAX_DIST_PLATEAU_AREA_EXACT",
295 "Maximum-distance plateau area: Number of support pixels attaining the exact maximum squared contour distance.",
true,
296 MAX_DIST_EXACT_REQUIREMENTS},
297 {MaxDistPlateauCentroidRowExact,
"MAX_DIST_PLATEAU_CENTROID_ROW_EXACT",
298 "Maximum-distance plateau centroid row: Arithmetic mean of the row coordinates of all exact maximum-distance pixels.",
true,
299 MAX_DIST_EXACT_REQUIREMENTS},
300 {MaxDistPlateauCentroidColumnExact,
"MAX_DIST_PLATEAU_CENTROID_COLUMN_EXACT",
301 "Maximum-distance plateau centroid column: Arithmetic mean of the column coordinates of all exact maximum-distance pixels.",
true,
302 MAX_DIST_EXACT_REQUIREMENTS},
303 {MaxDistPlateauArea,
"MAX_DIST_PLATEAU_AREA",
304 "Approximate maximum-distance plateau area: Number of support pixels attaining the adaptive-A8 DIFT maximum.",
true,
305 MAX_DIST_REQUIREMENTS},
306 {MaxDistPlateauCentroidRow,
"MAX_DIST_PLATEAU_CENTROID_ROW",
307 "Approximate maximum-distance plateau centroid row over all support pixels attaining the adaptive-A8 DIFT maximum.",
true,
308 MAX_DIST_REQUIREMENTS},
309 {MaxDistPlateauCentroidColumn,
"MAX_DIST_PLATEAU_CENTROID_COLUMN",
310 "Approximate maximum-distance plateau centroid column over all support pixels attaining the adaptive-A8 DIFT maximum.",
true,
311 MAX_DIST_REQUIREMENTS},
313 {DistSum,
"DIST_SUM",
"Sum of approximate Euclidean contour distances over the node support, in pixels.",
true, MAX_DIST_REQUIREMENTS},
314 {DistMean,
"DIST_MEAN",
"Arithmetic mean of approximate Euclidean contour distances over the node support, in pixels.",
true,
315 MAX_DIST_REQUIREMENTS},
316 {DistVariance,
"DIST_VARIANCE",
"Population variance of approximate Euclidean contour distances, in squared pixels.",
true,
317 MAX_DIST_REQUIREMENTS},
318 {DistMedian,
"DIST_MEDIAN",
"Lower median of the approximate Euclidean contour-distance distribution, in pixels.",
true,
319 MAX_DIST_REQUIREMENTS},
320 {DistMode,
"DIST_MODE",
"Smallest approximate Euclidean contour distance among the most frequent distance levels, in pixels.",
true,
321 MAX_DIST_REQUIREMENTS},
322 {DistQ25,
"DIST_Q25",
"Lower 25th percentile of the approximate Euclidean contour-distance distribution, in pixels.",
true,
323 MAX_DIST_REQUIREMENTS},
324 {DistQ75,
"DIST_Q75",
"Lower 75th percentile of the approximate Euclidean contour-distance distribution, in pixels.",
true,
325 MAX_DIST_REQUIREMENTS},
326 {DistQ90,
"DIST_Q90",
"Lower 90th percentile of the approximate Euclidean contour-distance distribution, in pixels.",
true,
327 MAX_DIST_REQUIREMENTS},
328 {DistEntropy,
"DIST_ENTROPY",
"Shannon entropy in bits of the normalized approximate squared-distance histogram.",
true,
329 MAX_DIST_REQUIREMENTS},
330 {DistPositiveArea,
"DIST_POSITIVE_AREA",
"Number of support pixels with strictly positive approximate contour distance.",
true,
331 MAX_DIST_REQUIREMENTS},
332 {DistLevelCount,
"DIST_LEVEL_COUNT",
"Number of distinct approximate squared-distance levels, including zero.",
true,
333 MAX_DIST_REQUIREMENTS},
334 {DistWeightedCentroidRow,
"DIST_WEIGHTED_CENTROID_ROW",
335 "Zero-based support centroid row weighted by approximate Euclidean contour distance.",
true, MAX_DIST_REQUIREMENTS},
336 {DistWeightedCentroidColumn,
"DIST_WEIGHTED_CENTROID_COLUMN",
337 "Zero-based support centroid column weighted by approximate Euclidean contour distance.",
true, MAX_DIST_REQUIREMENTS},
338 {DistWeightedCentralMoment20,
"DIST_WEIGHTED_CENTRAL_MOMENT_20",
339 "Unnormalized second-order column central moment weighted by approximate Euclidean contour distance.",
true, MAX_DIST_REQUIREMENTS},
340 {DistWeightedCentralMoment02,
"DIST_WEIGHTED_CENTRAL_MOMENT_02",
341 "Unnormalized second-order row central moment weighted by approximate Euclidean contour distance.",
true, MAX_DIST_REQUIREMENTS},
342 {DistWeightedCentralMoment11,
"DIST_WEIGHTED_CENTRAL_MOMENT_11",
343 "Unnormalized mixed row-column central moment weighted by approximate Euclidean contour distance.",
true, MAX_DIST_REQUIREMENTS},
344 {DistWeightedAxisOrientation,
"DIST_WEIGHTED_AXIS_ORIENTATION",
345 "Non-negative column-axis orientation in degrees of the approximate distance-weighted support moments.",
true, MAX_DIST_REQUIREMENTS},
346 {DistWeightedEccentricity,
"DIST_WEIGHTED_ECCENTRICITY",
347 "Major/minor eigenvalue ratio of the approximate distance-weighted second moments.",
true, MAX_DIST_REQUIREMENTS},
349 {DistSumExact,
"DIST_SUM_EXACT",
"Sum of exact Euclidean contour distances over the node support, in pixels.",
true,
350 MAX_DIST_EXACT_REQUIREMENTS},
351 {DistMeanExact,
"DIST_MEAN_EXACT",
"Arithmetic mean of exact Euclidean contour distances over the node support, in pixels.",
true,
352 MAX_DIST_EXACT_REQUIREMENTS},
353 {DistVarianceExact,
"DIST_VARIANCE_EXACT",
"Population variance of exact Euclidean contour distances, in squared pixels.",
true,
354 MAX_DIST_EXACT_REQUIREMENTS},
355 {DistMedianExact,
"DIST_MEDIAN_EXACT",
"Lower median of the exact Euclidean contour-distance distribution, in pixels.",
true,
356 MAX_DIST_EXACT_REQUIREMENTS},
357 {DistModeExact,
"DIST_MODE_EXACT",
"Smallest exact Euclidean contour distance among the most frequent distance levels, in pixels.",
true,
358 MAX_DIST_EXACT_REQUIREMENTS},
359 {DistQ25Exact,
"DIST_Q25_EXACT",
"Lower 25th percentile of the exact Euclidean contour-distance distribution, in pixels.",
true,
360 MAX_DIST_EXACT_REQUIREMENTS},
361 {DistQ75Exact,
"DIST_Q75_EXACT",
"Lower 75th percentile of the exact Euclidean contour-distance distribution, in pixels.",
true,
362 MAX_DIST_EXACT_REQUIREMENTS},
363 {DistQ90Exact,
"DIST_Q90_EXACT",
"Lower 90th percentile of the exact Euclidean contour-distance distribution, in pixels.",
true,
364 MAX_DIST_EXACT_REQUIREMENTS},
365 {DistEntropyExact,
"DIST_ENTROPY_EXACT",
"Shannon entropy in bits of the normalized exact squared-distance histogram.",
true,
366 MAX_DIST_EXACT_REQUIREMENTS},
367 {DistPositiveAreaExact,
"DIST_POSITIVE_AREA_EXACT",
"Number of support pixels with strictly positive exact contour distance.",
true,
368 MAX_DIST_EXACT_REQUIREMENTS},
369 {DistLevelCountExact,
"DIST_LEVEL_COUNT_EXACT",
"Number of distinct exact squared-distance levels, including zero.",
true,
370 MAX_DIST_EXACT_REQUIREMENTS},
371 {DistWeightedCentroidRowExact,
"DIST_WEIGHTED_CENTROID_ROW_EXACT",
372 "Zero-based support centroid row weighted by exact Euclidean contour distance.",
true, MAX_DIST_EXACT_REQUIREMENTS},
373 {DistWeightedCentroidColumnExact,
"DIST_WEIGHTED_CENTROID_COLUMN_EXACT",
374 "Zero-based support centroid column weighted by exact Euclidean contour distance.",
true, MAX_DIST_EXACT_REQUIREMENTS},
375 {DistWeightedCentralMoment20Exact,
"DIST_WEIGHTED_CENTRAL_MOMENT_20_EXACT",
376 "Unnormalized second-order column central moment weighted by exact Euclidean contour distance.",
true, MAX_DIST_EXACT_REQUIREMENTS},
377 {DistWeightedCentralMoment02Exact,
"DIST_WEIGHTED_CENTRAL_MOMENT_02_EXACT",
378 "Unnormalized second-order row central moment weighted by exact Euclidean contour distance.",
true, MAX_DIST_EXACT_REQUIREMENTS},
379 {DistWeightedCentralMoment11Exact,
"DIST_WEIGHTED_CENTRAL_MOMENT_11_EXACT",
380 "Unnormalized mixed row-column central moment weighted by exact Euclidean contour distance.",
true, MAX_DIST_EXACT_REQUIREMENTS},
381 {DistWeightedAxisOrientationExact,
"DIST_WEIGHTED_AXIS_ORIENTATION_EXACT",
382 "Non-negative column-axis orientation in degrees of the exact distance-weighted support moments.",
true, MAX_DIST_EXACT_REQUIREMENTS},
383 {DistWeightedEccentricityExact,
"DIST_WEIGHTED_ECCENTRICITY_EXACT",
384 "Major/minor eigenvalue ratio of the exact distance-weighted second moments.",
true, MAX_DIST_EXACT_REQUIREMENTS},
386 {MaxSquaredDist,
"MAX_SQUARED_DIST",
387 "Approximate maximum squared Euclidean distance from the foreground A4 contour over the node support, in squared pixels, computed by an adaptive "
388 "A8 dynamic image foresting transform.",
389 true, MAX_DIST_REQUIREMENTS},
390 {MaxSquaredDistExact,
"MAX_SQUARED_DIST_EXACT",
391 "Maximum exact squared Euclidean distance from the foreground A4 contour over the node support in the original 2D pixel domain, in squared pixels.",
392 true, MAX_DIST_EXACT_REQUIREMENTS}}};
399inline constexpr bool hasOrdinallyAlignedAttributeMetadata() noexcept {
400 for (std::size_t index = 0; index < ATTRIBUTE_METADATA.size(); ++index) {
401 if (
static_cast<std::size_t
>(ATTRIBUTE_METADATA[index].attribute) != index) {
408static_assert(hasOrdinallyAlignedAttributeMetadata(),
"Attribute metadata rows must match Attribute enum ordinals.");
416inline const AttributeMetadata* metadata(Attribute attribute)
noexcept {
417 const auto index =
static_cast<std::size_t
>(attribute);
418 if (index >= ATTRIBUTE_METADATA.size()) {
421 const AttributeMetadata& item = ATTRIBUTE_METADATA[index];
422 return item.attribute == attribute ? &item :
nullptr;
434inline std::string_view name(Attribute attribute)
noexcept {
435 const AttributeMetadata* item = metadata(attribute);
436 return item !=
nullptr ? item->name : std::string_view(
"UNKNOWN");
445inline std::string_view description(Attribute attribute)
noexcept {
446 const AttributeMetadata* item = metadata(attribute);
447 return item !=
nullptr ? item->description : std::string_view(
"Unknown attribute.");
456inline bool requiresAltitude(Attribute attribute)
noexcept {
457 const AttributeMetadata* item = metadata(attribute);
458 return item !=
nullptr && item->requirements.altitude;
467inline bool isTopologyOnly(Attribute attribute)
noexcept {
468 const AttributeMetadata* item = metadata(attribute);
469 return item !=
nullptr && item->topologyOnly;
481inline AttributeCapabilityRequirements capabilityRequirements(Attribute attribute)
noexcept {
482 const AttributeMetadata* item = metadata(attribute);
483 return item !=
nullptr ? item->requirements : AttributeCapabilityRequirements{};
495inline bool isAttributePipelineAltitudeAttribute(Attribute attribute)
noexcept {
return attribute == Area || requiresAltitude(attribute); }
503inline bool isPipelineComputed(Attribute attribute)
noexcept {
return attribute == Area || requiresAltitude(attribute) || isTopologyOnly(attribute); }
514inline std::optional<Attribute> parse(std::string_view nameToFind)
noexcept {
515 for (
const AttributeMetadata& item : ATTRIBUTE_METADATA) {
516 if (item.name == nameToFind) {
517 return item.attribute;
532inline const std::unordered_map<AttributeGroup, std::vector<Attribute>>& attributeGroups() {
533 static const std::unordered_map<AttributeGroup, std::vector<Attribute>> groups = [] {
534 std::vector<Attribute> all;
535 all.reserve(ATTRIBUTE_METADATA.size());
536 for (
const AttributeMetadata& item : ATTRIBUTE_METADATA) {
537 all.push_back(item.attribute);
540 return std::unordered_map<AttributeGroup, std::vector<Attribute>>{
541 {AttributeGroup::GrayLevel, {Volume, RelativeVolume, GrayLevelHeight, MeanGrayLevel, GrayLevelVariance}},
542 {AttributeGroup::Shape,
578 BitquadPerimeterContinuous,
580 BitquadPerimeterAverage,
581 BitquadLengthAverage,
591 {AttributeGroup::Moments,
592 {CentralMoment20, CentralMoment02, CentralMoment11, CentralMoment30, CentralMoment03, CentralMoment21, CentralMoment12,
593 HuMoment1, HuMoment2, HuMoment3, HuMoment4, HuMoment5, HuMoment6, HuMoment7,
594 Inertia, Compactness, Eccentricity, LengthMajorAxis, LengthMinorAxis, AxisOrientation, Circularity}},
595 {AttributeGroup::Boundary,
596 {BitquadArea, BitquadNumberEuler, BitquadNumberHoles, BitquadPerimeter, BitquadPerimeterContinuous, BitquadCircularity,
597 BitquadPerimeterAverage, BitquadLengthAverage, BitquadWidthAverage, ContourPixels, ContourPerimeter, ContourSideNorth,
598 ContourSideWest, ContourSideEast, ContourSideSouth}},
599 {AttributeGroup::TreeTopology,
600 {SubtreeHeight, DepthNode, IsLeafNode, IsRootNode, NumChildrenNode, NumSiblingsNode, NumDescendantsNode, NumLeafDescendantsNode,
601 LeafRatioNode, BalanceNode, AvgChildHeightNode}},
602 {AttributeGroup::DistTransf,
612 MaxDistPlateauCentroidRow,
613 MaxDistPlateauCentroidColumn,
625 DistWeightedCentroidRow,
626 DistWeightedCentroidColumn,
627 DistWeightedCentralMoment20,
628 DistWeightedCentralMoment02,
629 DistWeightedCentralMoment11,
630 DistWeightedAxisOrientation,
631 DistWeightedEccentricity}},
632 {AttributeGroup::DistTransfExact,
636 DistSquaredMeanExact,
638 DistSquaredVarianceExact,
639 MaxDistCenterRowExact,
640 MaxDistCenterColumnExact,
641 MaxDistPlateauAreaExact,
642 MaxDistPlateauCentroidRowExact,
643 MaxDistPlateauCentroidColumnExact,
653 DistPositiveAreaExact,
655 DistWeightedCentroidRowExact,
656 DistWeightedCentroidColumnExact,
657 DistWeightedCentralMoment20Exact,
658 DistWeightedCentralMoment02Exact,
659 DistWeightedCentralMoment11Exact,
660 DistWeightedAxisOrientationExact,
661 DistWeightedEccentricityExact}},
662 {AttributeGroup::All, std::move(all)}};
Runtime capabilities required to compute one scalar attribute.
bool monotoneAltitudeOrder
Whether the global altitude order must be monotone.
bool gridDomain2D
Whether proper parts must have a regular 2D domain.
bool altitude
Whether node altitudes must be available.
constexpr bool operator==(const AttributeCapabilityRequirements &) const noexcept=default
Compares every capability requirement.
bool altitudeForDirectionalAdjacency
Whether directional adjacency selection requires node altitudes.
bool canonical4Or8Adjacency
Whether only canonical 4- or 8-neighbourhoods are accepted.
AttributeAdjacencyRequirement adjacency
Required form of adjacency context.