mmcfilters
Public API documentation
Loading...
Searching...
No Matches
AttributeRegistry.hpp
1#pragma once
2
3#include "AttributeTypes.hpp"
4
5#include <array>
6#include <cstddef>
7#include <optional>
8#include <string_view>
9#include <unordered_map>
10#include <vector>
11
12namespace mmcfilters::attributes::registry {
13
17enum class AttributeAdjacencyRequirement { None, UniformOrDirectional, Uniform };
18
28 bool altitude = false;
30 bool gridDomain2D = false;
32 AttributeAdjacencyRequirement adjacency = AttributeAdjacencyRequirement::None;
39
45 constexpr bool operator==(const AttributeCapabilityRequirements&) const noexcept = default;
46};
47
48inline constexpr AttributeCapabilityRequirements NO_REQUIREMENTS{};
49
50inline constexpr AttributeCapabilityRequirements ALTITUDE_REQUIREMENTS{.altitude = true};
51
52inline constexpr AttributeCapabilityRequirements GRID_DOMAIN_2D_REQUIREMENTS{.gridDomain2D = true};
53
54inline constexpr AttributeCapabilityRequirements BITQUAD_REQUIREMENTS{.gridDomain2D = true,
55 .adjacency = AttributeAdjacencyRequirement::UniformOrDirectional,
56 .altitudeForDirectionalAdjacency = true,
57 .canonical4Or8Adjacency = true};
58
59inline constexpr AttributeCapabilityRequirements MAX_DIST_REQUIREMENTS{.gridDomain2D = true};
60
61inline constexpr AttributeCapabilityRequirements MAX_DIST_EXACT_REQUIREMENTS{.gridDomain2D = true};
62
73 Attribute attribute;
74
76 std::string_view name;
77
79 std::string_view description;
80
82 bool topologyOnly = false;
83
86};
87
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},
99 {Volume, "VOLUME",
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},
113
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},
129
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},
149
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},
161
162 {Inertia, "INERTIA",
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},
183
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 "
206 "return 0.",
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},
216
217 {SubtreeHeight, "SUBTREE_HEIGHT", "Subtree height: Longest path from this node to any leaf in its subtree, measured in tree edges.", true,
218 NO_REQUIREMENTS},
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,
222 NO_REQUIREMENTS},
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,
225 NO_REQUIREMENTS},
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},
235
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},
240
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},
243
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},
250
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},
254
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},
267
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},
280
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},
293
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},
312
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},
348
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},
385
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}}};
393
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) {
402 return false;
403 }
404 }
405 return true;
406}
407
408static_assert(hasOrdinallyAlignedAttributeMetadata(), "Attribute metadata rows must match Attribute enum ordinals.");
409
416inline const AttributeMetadata* metadata(Attribute attribute) noexcept {
417 const auto index = static_cast<std::size_t>(attribute);
418 if (index >= ATTRIBUTE_METADATA.size()) {
419 return nullptr;
420 }
421 const AttributeMetadata& item = ATTRIBUTE_METADATA[index];
422 return item.attribute == attribute ? &item : nullptr;
423}
424
434inline std::string_view name(Attribute attribute) noexcept {
435 const AttributeMetadata* item = metadata(attribute);
436 return item != nullptr ? item->name : std::string_view("UNKNOWN");
437}
438
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.");
448}
449
456inline bool requiresAltitude(Attribute attribute) noexcept {
457 const AttributeMetadata* item = metadata(attribute);
458 return item != nullptr && item->requirements.altitude;
459}
460
467inline bool isTopologyOnly(Attribute attribute) noexcept {
468 const AttributeMetadata* item = metadata(attribute);
469 return item != nullptr && item->topologyOnly;
470}
471
481inline AttributeCapabilityRequirements capabilityRequirements(Attribute attribute) noexcept {
482 const AttributeMetadata* item = metadata(attribute);
483 return item != nullptr ? item->requirements : AttributeCapabilityRequirements{};
484}
485
495inline bool isAttributePipelineAltitudeAttribute(Attribute attribute) noexcept { return attribute == Area || requiresAltitude(attribute); }
496
503inline bool isPipelineComputed(Attribute attribute) noexcept { return attribute == Area || requiresAltitude(attribute) || isTopologyOnly(attribute); }
504
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;
518 }
519 }
520 return std::nullopt;
521}
522
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);
538 }
539
540 return std::unordered_map<AttributeGroup, std::vector<Attribute>>{
541 {AttributeGroup::GrayLevel, {Volume, RelativeVolume, GrayLevelHeight, MeanGrayLevel, GrayLevelVariance}},
542 {AttributeGroup::Shape,
543 {Area,
544 BoxWidth,
545 BoundingBoxHeight,
546 DiagonalLength,
547 Rectangularity,
548 RatioWh,
549 BoxColumnMin,
550 BoxColumnMax,
551 BoxRowMin,
552 BoxRowMax,
553 CentralMoment20,
554 CentralMoment02,
555 CentralMoment11,
556 CentralMoment30,
557 CentralMoment03,
558 CentralMoment21,
559 CentralMoment12,
560 HuMoment1,
561 HuMoment2,
562 HuMoment3,
563 HuMoment4,
564 HuMoment5,
565 HuMoment6,
566 HuMoment7,
567 Inertia,
568 Compactness,
569 Eccentricity,
570 LengthMajorAxis,
571 LengthMinorAxis,
572 AxisOrientation,
573 Circularity,
574 BitquadArea,
575 BitquadNumberEuler,
576 BitquadNumberHoles,
577 BitquadPerimeter,
578 BitquadPerimeterContinuous,
579 BitquadCircularity,
580 BitquadPerimeterAverage,
581 BitquadLengthAverage,
582 BitquadWidthAverage,
583 MaxDist,
584 MaxDistExact,
585 ContourPixels,
586 ContourPerimeter,
587 ContourSideNorth,
588 ContourSideWest,
589 ContourSideEast,
590 ContourSideSouth}},
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,
603 {MaxDist,
604 MaxSquaredDist,
605 DistSquaredSum,
606 DistSquaredMean,
607 DistRms,
608 DistSquaredVariance,
609 MaxDistCenterRow,
610 MaxDistCenterColumn,
611 MaxDistPlateauArea,
612 MaxDistPlateauCentroidRow,
613 MaxDistPlateauCentroidColumn,
614 DistSum,
615 DistMean,
616 DistVariance,
617 DistMedian,
618 DistMode,
619 DistQ25,
620 DistQ75,
621 DistQ90,
622 DistEntropy,
623 DistPositiveArea,
624 DistLevelCount,
625 DistWeightedCentroidRow,
626 DistWeightedCentroidColumn,
627 DistWeightedCentralMoment20,
628 DistWeightedCentralMoment02,
629 DistWeightedCentralMoment11,
630 DistWeightedAxisOrientation,
631 DistWeightedEccentricity}},
632 {AttributeGroup::DistTransfExact,
633 {MaxDistExact,
634 MaxSquaredDistExact,
635 DistSquaredSumExact,
636 DistSquaredMeanExact,
637 DistRmsExact,
638 DistSquaredVarianceExact,
639 MaxDistCenterRowExact,
640 MaxDistCenterColumnExact,
641 MaxDistPlateauAreaExact,
642 MaxDistPlateauCentroidRowExact,
643 MaxDistPlateauCentroidColumnExact,
644 DistSumExact,
645 DistMeanExact,
646 DistVarianceExact,
647 DistMedianExact,
648 DistModeExact,
649 DistQ25Exact,
650 DistQ75Exact,
651 DistQ90Exact,
652 DistEntropyExact,
653 DistPositiveAreaExact,
654 DistLevelCountExact,
655 DistWeightedCentroidRowExact,
656 DistWeightedCentroidColumnExact,
657 DistWeightedCentralMoment20Exact,
658 DistWeightedCentralMoment02Exact,
659 DistWeightedCentralMoment11Exact,
660 DistWeightedAxisOrientationExact,
661 DistWeightedEccentricityExact}},
662 {AttributeGroup::All, std::move(all)}};
663 }();
664 return groups;
665}
666
667} // namespace mmcfilters::attributes::registry
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.
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.
Stable metadata attached to one scalar attribute descriptor.
AttributeCapabilityRequirements requirements
Complete runtime capability contract used by scheduling and validation.
std::string_view name
Stable symbolic name used in Python dictionaries, string parsing, and docs.
std::string_view description
User-facing description suitable for notebooks and Attribute.describe.
bool topologyOnly
Whether the descriptor can be computed from topology/support alone.
Attribute attribute
Scalar attribute described by this row.