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 FILLED_SHAPE_REQUIREMENTS{.gridDomain2D = true,
60 .adjacency = AttributeAdjacencyRequirement::UniformOrDirectional,
61 .altitudeForDirectionalAdjacency = true,
62 .canonical4Or8Adjacency = true};
63
64inline constexpr AttributeCapabilityRequirements MAX_DIST_REQUIREMENTS{.gridDomain2D = true};
65
66inline constexpr AttributeCapabilityRequirements MAX_DIST_EXACT_REQUIREMENTS{.gridDomain2D = true};
67
78 Attribute attribute;
79
81 std::string_view name;
82
84 std::string_view description;
85
87 bool topologyOnly = false;
88
91};
92
102inline constexpr std::array<AttributeMetadata, static_cast<std::size_t>(Attribute::RawInertia) + 1> ATTRIBUTE_METADATA{
103 {{Area, "AREA", "Area: Number of pixels in the connected component.", false, NO_REQUIREMENTS},
104 {Volume, "VOLUME",
105 "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 "
106 "of the image function over its support.",
107 false, ALTITUDE_REQUIREMENTS},
108 {RelativeVolume, "RELATIVE_VOLUME",
109 "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.",
110 false, ALTITUDE_REQUIREMENTS},
111 {GrayLevelHeight, "GRAY_LEVEL_HEIGHT",
112 "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 "
113 "monotone max/min trees and also applies to hierarchies with unconstrained altitude order. Leaves have gray-level height 0.",
114 false, ALTITUDE_REQUIREMENTS},
115 {MeanGrayLevel, "MEAN_GRAY_LEVEL", "Mean gray level: Arithmetic mean of the image values over the node support.", false, ALTITUDE_REQUIREMENTS},
116 {GrayLevelVariance, "GRAY_LEVEL_VARIANCE", "Gray-level variance: Population variance of the image values over the node support.", false,
117 ALTITUDE_REQUIREMENTS},
118
119 {BoundingBoxWidth, "BOUNDING_BOX_WIDTH", "Bounding-box width: Width of the minimum rectangle enclosing the connected component.", true,
120 GRID_DOMAIN_2D_REQUIREMENTS},
121 {BoundingBoxHeight, "BOUNDING_BOX_HEIGHT", "Bounding-box height: Height of the minimum rectangle enclosing the connected component.", true,
122 GRID_DOMAIN_2D_REQUIREMENTS},
123 {DiagonalLength, "DIAGONAL_LENGTH", "Diagonal length: Euclidean length of the diagonal of the bounding box, computed as sqrt(width^2 + height^2).", true,
124 GRID_DOMAIN_2D_REQUIREMENTS},
125 {Rectangularity, "RECTANGULARITY",
126 "Rectangularity: Ratio between the connected component area and the area of its bounding box. Values closer to 1 indicate shapes that efficiently fill "
127 "their bounding box.",
128 true, GRID_DOMAIN_2D_REQUIREMENTS},
129 {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,
130 GRID_DOMAIN_2D_REQUIREMENTS},
131 {BoxColumnMin, "BOX_COLUMN_MIN", "Bounding box column min: Minimum column index covered by the connected component.", true, GRID_DOMAIN_2D_REQUIREMENTS},
132 {BoxColumnMax, "BOX_COLUMN_MAX", "Bounding box column max: Maximum column index covered by the connected component.", true, GRID_DOMAIN_2D_REQUIREMENTS},
133 {BoxRowMin, "BOX_ROW_MIN", "Bounding box row min: Minimum row index covered by the connected component.", true, GRID_DOMAIN_2D_REQUIREMENTS},
134 {BoxRowMax, "BOX_ROW_MAX", "Bounding box row max: Maximum row index covered by the connected component.", true, GRID_DOMAIN_2D_REQUIREMENTS},
135
136 {CentralMoment20, "CENTRAL_MOMENT_20",
137 "Central moment (2,0): Second-order moment about the centroid along the x-axis. Measures the horizontal spread of the component.", true,
138 GRID_DOMAIN_2D_REQUIREMENTS},
139 {CentralMoment02, "CENTRAL_MOMENT_02",
140 "Central moment (0,2): Second-order moment about the centroid along the y-axis. Measures the vertical spread of the component.", true,
141 GRID_DOMAIN_2D_REQUIREMENTS},
142 {CentralMoment11, "CENTRAL_MOMENT_11",
143 "Central moment (1,1): Mixed second-order moment about the centroid. Represents the covariance between x and y coordinates.", true,
144 GRID_DOMAIN_2D_REQUIREMENTS},
145 {CentralMoment30, "CENTRAL_MOMENT_30",
146 "Central moment (3,0): Third-order moment about the centroid along the x-axis. Describes horizontal asymmetry of the component.", true,
147 GRID_DOMAIN_2D_REQUIREMENTS},
148 {CentralMoment03, "CENTRAL_MOMENT_03",
149 "Central moment (0,3): Third-order moment about the centroid along the y-axis. Describes vertical asymmetry of the component.", true,
150 GRID_DOMAIN_2D_REQUIREMENTS},
151 {CentralMoment21, "CENTRAL_MOMENT_21",
152 "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},
153 {CentralMoment12, "CENTRAL_MOMENT_12",
154 "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},
155
156 {HuMoment1, "HU_MOMENT_1", "Hu moment 1: Invariant to translation, scale, and rotation. Represents overall spatial variance (shape dispersion).", true,
157 GRID_DOMAIN_2D_REQUIREMENTS},
158 {HuMoment2, "HU_MOMENT_2", "Hu moment 2: Invariant capturing the difference between horizontal and vertical spread.", true, GRID_DOMAIN_2D_REQUIREMENTS},
159 {HuMoment3, "HU_MOMENT_3", "Hu moment 3: Sensitive to skewness and asymmetry in the pixel distribution.", true, GRID_DOMAIN_2D_REQUIREMENTS},
160 {HuMoment4, "HU_MOMENT_4", "Hu moment 4: Measures symmetry with respect to diagonal axes.", true, GRID_DOMAIN_2D_REQUIREMENTS},
161 {HuMoment5, "HU_MOMENT_5", "Hu moment 5: Descriptor sensitive to orientation and reflection; captures complex asymmetries.", true,
162 GRID_DOMAIN_2D_REQUIREMENTS},
163 {HuMoment6, "HU_MOMENT_6", "Hu moment 6: Invariant capturing elliptic asymmetries, sensitive to specific shape curvature.", true,
164 GRID_DOMAIN_2D_REQUIREMENTS},
165 {HuMoment7, "HU_MOMENT_7", "Hu moment 7: Highly sensitive to irregularities and fine variations; helps discriminate mirror-symmetric shapes.", true,
166 GRID_DOMAIN_2D_REQUIREMENTS},
167
168 {Inertia, "INERTIA",
169 "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.",
170 true, GRID_DOMAIN_2D_REQUIREMENTS},
171 {Compactness, "COMPACTNESS",
172 "Compactness: Area normalized by the shape's dispersion (mu20 + mu02). Higher values indicate more compact and isotropic shapes.", true,
173 GRID_DOMAIN_2D_REQUIREMENTS},
174 {Eccentricity, "ECCENTRICITY",
175 "Eccentricity: Ratio of principal inertia eigenvalues (λ_1/λ_2). Measures elongation; values near 1 indicate circularity, higher values indicate "
176 "elongation. Degenerate line-like supports saturate at a finite maximum.",
177 true, GRID_DOMAIN_2D_REQUIREMENTS},
178 {LengthMajorAxis, "LENGTH_MAJOR_AXIS", "Major-axis length proxy of the equivalent second-moment ellipse, derived from the largest inertia eigenvalue and support area.", true,
179 GRID_DOMAIN_2D_REQUIREMENTS},
180 {LengthMinorAxis, "LENGTH_MINOR_AXIS", "Minor-axis length proxy of the equivalent second-moment ellipse, derived from the smallest inertia eigenvalue and support area.", true,
181 GRID_DOMAIN_2D_REQUIREMENTS},
182 {AxisOrientation, "AXIS_ORIENTATION",
183 "Axis orientation: Angle of the principal inertia axis, computed from central moments. Indicates the dominant orientation of the shape.", true,
184 GRID_DOMAIN_2D_REQUIREMENTS},
185 {Circularity, "CIRCULARITY",
186 "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; "
187 "values near 1 suggest circularity, values near 0 indicate elongation.",
188 true, GRID_DOMAIN_2D_REQUIREMENTS},
189
190 {BitquadArea, "BITQUAD_AREA",
191 "Bitquad area (Duda): Refined sub-pixel area estimation using fractional weights based on the geometric contribution of local 2x2 pixel patterns.", true,
192 BITQUAD_REQUIREMENTS},
193 {BitquadNumberEuler, "BITQUAD_NUMBER_EULER",
194 "Bitquad Euler number: Topological invariant computed as the number of connected components minus the number of holes, using 2x2 pattern statistics "
195 "under 4- or 8-connectivity.",
196 true, BITQUAD_REQUIREMENTS},
197 {BitquadNumberHoles, "BITQUAD_NUMBER_HOLES",
198 "Bitquad number of holes: Number of interior holes in the component, derived from the Euler characteristic assuming a single connected object.", true,
199 BITQUAD_REQUIREMENTS},
200 {BitquadPerimeter, "BITQUAD_PERIMETER",
201 "Bitquad perimeter: Discrete approximation of the shape's boundary length, calculated by summing edge-contributing patterns in the 2x2 pixel grid.",
202 true, BITQUAD_REQUIREMENTS},
203 {BitquadPerimeterContinuous, "BITQUAD_PERIMETER_CONTINUOUS",
204 "Bitquad continuous perimeter: Smoothed boundary-length estimate derived from weighted transitions across local 2x2 bitquad configurations.", true,
205 BITQUAD_REQUIREMENTS},
206 {BitquadCircularity, "BITQUAD_CIRCULARITY",
207 "Bitquad circularity: Compactness measure defined as (4π x areaDuda) / perimeter². Values close to 1 indicate circular shapes; lower values suggest "
208 "elongation or irregularity. Degenerate zero-perimeter supports return 0.",
209 true, BITQUAD_REQUIREMENTS},
210 {BitquadPerimeterAverage, "BITQUAD_PERIMETER_AVERAGE",
211 "Bitquad average perimeter: Mean perimeter per connected component, accounting for complex structures and holes. Non-positive Euler component estimates "
212 "return 0.",
213 true, BITQUAD_REQUIREMENTS},
214 {BitquadLengthAverage, "BITQUAD_LENGTH_AVERAGE",
215 "Bitquad average length: Estimated average longitudinal extent per component, derived from the average perimeter with a zero fallback for non-positive "
216 "Euler component estimates.",
217 true, BITQUAD_REQUIREMENTS},
218 {BitquadWidthAverage, "BITQUAD_WIDTH_AVERAGE",
219 "Bitquad average width: Estimated transverse extent per component, computed as (2 x areaDuda) / continuous perimeter with a zero fallback for "
220 "degenerate perimeter.",
221 true, BITQUAD_REQUIREMENTS},
222
223 {SubtreeHeight, "SUBTREE_HEIGHT", "Subtree height: Longest path from this node to any leaf in its subtree, measured in tree edges.", true,
224 NO_REQUIREMENTS},
225 {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.",
226 true, NO_REQUIREMENTS},
227 {IsLeafNode, "IS_LEAF_NODE", "Is leaf: True if the node has no children, i.e., it represents a minimal component in the hierarchy.", true,
228 NO_REQUIREMENTS},
229 {IsRootNode, "IS_ROOT_NODE", "Is root: True if the node is the root of the tree, representing the entire image support.", true, NO_REQUIREMENTS},
230 {NumChildrenNode, "NUM_CHILDREN_NODE", "Number of children: Count of direct child nodes. Reflects the immediate branching factor of the node.", true,
231 NO_REQUIREMENTS},
232 {NumSiblingsNode, "NUM_SIBLINGS_NODE", "Number of siblings: Number of other nodes that share the same parent.", true, NO_REQUIREMENTS},
233 {NumDescendantsNode, "NUM_DESCENDANTS_NODE",
234 "Number of descendants: Total number of nodes in the subtree rooted at this node (excluding the node itself).", true, NO_REQUIREMENTS},
235 {NumLeafDescendantsNode, "NUM_LEAF_DESCENDANTS_NODE",
236 "Number of leaf descendants: Number of leaf nodes in the subtree. Reflects the number of minimal patterns under this structure.", true, NO_REQUIREMENTS},
237 {LeafRatioNode, "LEAF_RATIO_NODE",
238 "Leaf ratio: Number of leaf descendants divided by subtree size, leaf_descendants / (descendants + 1). Leaves return 1.", true, NO_REQUIREMENTS},
239 {BalanceNode, "BALANCE_NODE",
240 "Balance: Difference between the maximum and minimum heights among the subtrees of the children. Indicates branching symmetry.", true, NO_REQUIREMENTS},
241
242 {MaxDist, "MAX_DIST",
243 "Approximate maximum Euclidean distance from the foreground A4 contour over the node support, in pixels, computed by an adaptive A8 dynamic "
244 "image foresting transform.",
245 true, MAX_DIST_REQUIREMENTS},
246
247 {AvgChildHeightNode, "AVG_CHILD_HEIGHT_NODE",
248 "Average child height: Mean height of all direct child subtrees. Useful for measuring uniformity of the subtree structure.", true, NO_REQUIREMENTS},
249
250 {ContourPixels, "CONTOUR_PIXELS", "Contour pixels: Number of support pixels touching the 4-neighbour complement.", true, GRID_DOMAIN_2D_REQUIREMENTS},
251 {ContourPerimeter, "CONTOUR_PERIMETER", "Contour perimeter: 4-neighbour exposed-side perimeter of the support.", true, GRID_DOMAIN_2D_REQUIREMENTS},
252 {ContourSideNorth, "CONTOUR_SIDE_NORTH", "Contour north sides: Number of exposed north sides over support pixels.", true, GRID_DOMAIN_2D_REQUIREMENTS},
253 {ContourSideWest, "CONTOUR_SIDE_WEST", "Contour west sides: Number of exposed west sides over support pixels.", true, GRID_DOMAIN_2D_REQUIREMENTS},
254 {ContourSideEast, "CONTOUR_SIDE_EAST", "Contour east sides: Number of exposed east sides over support pixels.", true, GRID_DOMAIN_2D_REQUIREMENTS},
255 {ContourSideSouth, "CONTOUR_SIDE_SOUTH", "Contour south sides: Number of exposed south sides over support pixels.", true, GRID_DOMAIN_2D_REQUIREMENTS},
256
257 {MaxDistExact, "MAX_DIST_EXACT",
258 "Maximum exact Euclidean distance from the foreground A4 contour over the node support in the original 2D pixel domain, in pixels.", true,
259 MAX_DIST_EXACT_REQUIREMENTS},
260
261 {DistSquaredSumExact, "DIST_SQUARED_SUM_EXACT",
262 "Squared-distance sum: Sum over the node support of the exact squared Euclidean distance to the foreground A4 contour.", true,
263 MAX_DIST_EXACT_REQUIREMENTS},
264 {DistSquaredMeanExact, "DIST_SQUARED_MEAN_EXACT",
265 "Squared-distance mean: Arithmetic mean over the node support of the exact squared Euclidean distance to the foreground A4 contour.", true,
266 MAX_DIST_EXACT_REQUIREMENTS},
267 {DistRmsExact, "DIST_RMS_EXACT",
268 "Distance RMS: Square root of the mean exact squared Euclidean distance to the foreground A4 contour, in pixel units.", true,
269 MAX_DIST_EXACT_REQUIREMENTS},
270 {DistSquaredVarianceExact, "DIST_SQUARED_VARIANCE_EXACT",
271 "Squared-distance variance: Population variance over the node support of the exact squared Euclidean distance to the foreground A4 contour.", true,
272 MAX_DIST_EXACT_REQUIREMENTS},
273
274 {DistSquaredSum, "DIST_SQUARED_SUM",
275 "Approximate squared-distance sum over the node support, computed from the adaptive A8 dynamic image foresting transform.", true,
276 MAX_DIST_REQUIREMENTS},
277 {DistSquaredMean, "DIST_SQUARED_MEAN",
278 "Approximate squared-distance mean over the node support, computed from the adaptive A8 dynamic image foresting transform.", true,
279 MAX_DIST_REQUIREMENTS},
280 {DistRms, "DIST_RMS",
281 "Approximate distance RMS in pixel units, computed from the adaptive A8 dynamic image foresting transform.", true,
282 MAX_DIST_REQUIREMENTS},
283 {DistSquaredVariance, "DIST_SQUARED_VARIANCE",
284 "Approximate population variance of squared distances over the node support, computed from the adaptive A8 dynamic image foresting transform.", true,
285 MAX_DIST_REQUIREMENTS},
286
287 {MaxDistCenterRowExact, "MAX_DIST_CENTER_ROW_EXACT",
288 "Maximum-distance center row: Zero-based row of the smallest row-major support pixel attaining the exact maximum squared contour distance.", true,
289 MAX_DIST_EXACT_REQUIREMENTS},
290 {MaxDistCenterColumnExact, "MAX_DIST_CENTER_COLUMN_EXACT",
291 "Maximum-distance center column: Zero-based column of the smallest row-major support pixel attaining the exact maximum squared contour distance.",
292 true, MAX_DIST_EXACT_REQUIREMENTS},
293 {MaxDistCenterRow, "MAX_DIST_CENTER_ROW",
294 "Approximate maximum-distance center row: Zero-based row of the smallest row-major support pixel attaining the adaptive-A8 DIFT maximum.", true,
295 MAX_DIST_REQUIREMENTS},
296 {MaxDistCenterColumn, "MAX_DIST_CENTER_COLUMN",
297 "Approximate maximum-distance center column: Zero-based column of the smallest row-major support pixel attaining the adaptive-A8 DIFT maximum.",
298 true, MAX_DIST_REQUIREMENTS},
299
300 {MaxDistPlateauAreaExact, "MAX_DIST_PLATEAU_AREA_EXACT",
301 "Maximum-distance plateau area: Number of support pixels attaining the exact maximum squared contour distance.", true,
302 MAX_DIST_EXACT_REQUIREMENTS},
303 {MaxDistPlateauCentroidRowExact, "MAX_DIST_PLATEAU_CENTROID_ROW_EXACT",
304 "Maximum-distance plateau centroid row: Arithmetic mean of the row coordinates of all exact maximum-distance pixels.", true,
305 MAX_DIST_EXACT_REQUIREMENTS},
306 {MaxDistPlateauCentroidColumnExact, "MAX_DIST_PLATEAU_CENTROID_COLUMN_EXACT",
307 "Maximum-distance plateau centroid column: Arithmetic mean of the column coordinates of all exact maximum-distance pixels.", true,
308 MAX_DIST_EXACT_REQUIREMENTS},
309 {MaxDistPlateauArea, "MAX_DIST_PLATEAU_AREA",
310 "Approximate maximum-distance plateau area: Number of support pixels attaining the adaptive-A8 DIFT maximum.", true,
311 MAX_DIST_REQUIREMENTS},
312 {MaxDistPlateauCentroidRow, "MAX_DIST_PLATEAU_CENTROID_ROW",
313 "Approximate maximum-distance plateau centroid row over all support pixels attaining the adaptive-A8 DIFT maximum.", true,
314 MAX_DIST_REQUIREMENTS},
315 {MaxDistPlateauCentroidColumn, "MAX_DIST_PLATEAU_CENTROID_COLUMN",
316 "Approximate maximum-distance plateau centroid column over all support pixels attaining the adaptive-A8 DIFT maximum.", true,
317 MAX_DIST_REQUIREMENTS},
318
319 {DistSum, "DIST_SUM", "Sum of approximate Euclidean contour distances over the node support, in pixels.", true, MAX_DIST_REQUIREMENTS},
320 {DistMean, "DIST_MEAN", "Arithmetic mean of approximate Euclidean contour distances over the node support, in pixels.", true,
321 MAX_DIST_REQUIREMENTS},
322 {DistVariance, "DIST_VARIANCE", "Population variance of approximate Euclidean contour distances, in squared pixels.", true,
323 MAX_DIST_REQUIREMENTS},
324 {DistMedian, "DIST_MEDIAN", "Lower median of the approximate Euclidean contour-distance distribution, in pixels.", true,
325 MAX_DIST_REQUIREMENTS},
326 {DistMode, "DIST_MODE", "Smallest approximate Euclidean contour distance among the most frequent distance levels, in pixels.", true,
327 MAX_DIST_REQUIREMENTS},
328 {DistQ25, "DIST_Q25", "Lower 25th percentile of the approximate Euclidean contour-distance distribution, in pixels.", true,
329 MAX_DIST_REQUIREMENTS},
330 {DistQ75, "DIST_Q75", "Lower 75th percentile of the approximate Euclidean contour-distance distribution, in pixels.", true,
331 MAX_DIST_REQUIREMENTS},
332 {DistQ90, "DIST_Q90", "Lower 90th percentile of the approximate Euclidean contour-distance distribution, in pixels.", true,
333 MAX_DIST_REQUIREMENTS},
334 {DistEntropy, "DIST_ENTROPY", "Shannon entropy in bits of the normalized approximate squared-distance histogram.", true,
335 MAX_DIST_REQUIREMENTS},
336 {DistPositiveArea, "DIST_POSITIVE_AREA", "Number of support pixels with strictly positive approximate contour distance.", true,
337 MAX_DIST_REQUIREMENTS},
338 {DistLevelCount, "DIST_LEVEL_COUNT", "Number of distinct approximate squared-distance levels, including zero.", true,
339 MAX_DIST_REQUIREMENTS},
340 {DistWeightedCentroidRow, "DIST_WEIGHTED_CENTROID_ROW",
341 "Zero-based support centroid row weighted by approximate Euclidean contour distance.", true, MAX_DIST_REQUIREMENTS},
342 {DistWeightedCentroidColumn, "DIST_WEIGHTED_CENTROID_COLUMN",
343 "Zero-based support centroid column weighted by approximate Euclidean contour distance.", true, MAX_DIST_REQUIREMENTS},
344 {DistWeightedCentralMoment20, "DIST_WEIGHTED_CENTRAL_MOMENT_20",
345 "Unnormalized second-order column central moment weighted by approximate Euclidean contour distance.", true, MAX_DIST_REQUIREMENTS},
346 {DistWeightedCentralMoment02, "DIST_WEIGHTED_CENTRAL_MOMENT_02",
347 "Unnormalized second-order row central moment weighted by approximate Euclidean contour distance.", true, MAX_DIST_REQUIREMENTS},
348 {DistWeightedCentralMoment11, "DIST_WEIGHTED_CENTRAL_MOMENT_11",
349 "Unnormalized mixed row-column central moment weighted by approximate Euclidean contour distance.", true, MAX_DIST_REQUIREMENTS},
350 {DistWeightedAxisOrientation, "DIST_WEIGHTED_AXIS_ORIENTATION",
351 "Non-negative column-axis orientation in degrees of the approximate distance-weighted support moments.", true, MAX_DIST_REQUIREMENTS},
352 {DistWeightedEccentricity, "DIST_WEIGHTED_ECCENTRICITY",
353 "Major/minor eigenvalue ratio of the approximate distance-weighted second moments.", true, MAX_DIST_REQUIREMENTS},
354
355 {DistSumExact, "DIST_SUM_EXACT", "Sum of exact Euclidean contour distances over the node support, in pixels.", true,
356 MAX_DIST_EXACT_REQUIREMENTS},
357 {DistMeanExact, "DIST_MEAN_EXACT", "Arithmetic mean of exact Euclidean contour distances over the node support, in pixels.", true,
358 MAX_DIST_EXACT_REQUIREMENTS},
359 {DistVarianceExact, "DIST_VARIANCE_EXACT", "Population variance of exact Euclidean contour distances, in squared pixels.", true,
360 MAX_DIST_EXACT_REQUIREMENTS},
361 {DistMedianExact, "DIST_MEDIAN_EXACT", "Lower median of the exact Euclidean contour-distance distribution, in pixels.", true,
362 MAX_DIST_EXACT_REQUIREMENTS},
363 {DistModeExact, "DIST_MODE_EXACT", "Smallest exact Euclidean contour distance among the most frequent distance levels, in pixels.", true,
364 MAX_DIST_EXACT_REQUIREMENTS},
365 {DistQ25Exact, "DIST_Q25_EXACT", "Lower 25th percentile of the exact Euclidean contour-distance distribution, in pixels.", true,
366 MAX_DIST_EXACT_REQUIREMENTS},
367 {DistQ75Exact, "DIST_Q75_EXACT", "Lower 75th percentile of the exact Euclidean contour-distance distribution, in pixels.", true,
368 MAX_DIST_EXACT_REQUIREMENTS},
369 {DistQ90Exact, "DIST_Q90_EXACT", "Lower 90th percentile of the exact Euclidean contour-distance distribution, in pixels.", true,
370 MAX_DIST_EXACT_REQUIREMENTS},
371 {DistEntropyExact, "DIST_ENTROPY_EXACT", "Shannon entropy in bits of the normalized exact squared-distance histogram.", true,
372 MAX_DIST_EXACT_REQUIREMENTS},
373 {DistPositiveAreaExact, "DIST_POSITIVE_AREA_EXACT", "Number of support pixels with strictly positive exact contour distance.", true,
374 MAX_DIST_EXACT_REQUIREMENTS},
375 {DistLevelCountExact, "DIST_LEVEL_COUNT_EXACT", "Number of distinct exact squared-distance levels, including zero.", true,
376 MAX_DIST_EXACT_REQUIREMENTS},
377 {DistWeightedCentroidRowExact, "DIST_WEIGHTED_CENTROID_ROW_EXACT",
378 "Zero-based support centroid row weighted by exact Euclidean contour distance.", true, MAX_DIST_EXACT_REQUIREMENTS},
379 {DistWeightedCentroidColumnExact, "DIST_WEIGHTED_CENTROID_COLUMN_EXACT",
380 "Zero-based support centroid column weighted by exact Euclidean contour distance.", true, MAX_DIST_EXACT_REQUIREMENTS},
381 {DistWeightedCentralMoment20Exact, "DIST_WEIGHTED_CENTRAL_MOMENT_20_EXACT",
382 "Unnormalized second-order column central moment weighted by exact Euclidean contour distance.", true, MAX_DIST_EXACT_REQUIREMENTS},
383 {DistWeightedCentralMoment02Exact, "DIST_WEIGHTED_CENTRAL_MOMENT_02_EXACT",
384 "Unnormalized second-order row central moment weighted by exact Euclidean contour distance.", true, MAX_DIST_EXACT_REQUIREMENTS},
385 {DistWeightedCentralMoment11Exact, "DIST_WEIGHTED_CENTRAL_MOMENT_11_EXACT",
386 "Unnormalized mixed row-column central moment weighted by exact Euclidean contour distance.", true, MAX_DIST_EXACT_REQUIREMENTS},
387 {DistWeightedAxisOrientationExact, "DIST_WEIGHTED_AXIS_ORIENTATION_EXACT",
388 "Non-negative column-axis orientation in degrees of the exact distance-weighted support moments.", true, MAX_DIST_EXACT_REQUIREMENTS},
389 {DistWeightedEccentricityExact, "DIST_WEIGHTED_ECCENTRICITY_EXACT",
390 "Major/minor eigenvalue ratio of the exact distance-weighted second moments.", true, MAX_DIST_EXACT_REQUIREMENTS},
391
392 {MaxSquaredDist, "MAX_SQUARED_DIST",
393 "Approximate maximum squared Euclidean distance from the foreground A4 contour over the node support, in squared pixels, computed by an adaptive "
394 "A8 dynamic image foresting transform.",
395 true, MAX_DIST_REQUIREMENTS},
396 {MaxSquaredDistExact, "MAX_SQUARED_DIST_EXACT",
397 "Maximum exact squared Euclidean distance from the foreground A4 contour over the node support in the original 2D pixel domain, in squared pixels.",
398 true, MAX_DIST_EXACT_REQUIREMENTS},
399
400 {FilledArea, "FILLED_AREA",
401 "Number of pixels enclosed by the unique external boundary, including holes.", true, FILLED_SHAPE_REQUIREMENTS},
402 {FilledCentroidRow, "FILLED_CENTROID_ROW",
403 "Zero-based mean row of the filled region pixels.", true, FILLED_SHAPE_REQUIREMENTS},
404 {FilledCentroidColumn, "FILLED_CENTROID_COLUMN",
405 "Zero-based mean column of the filled region pixels.", true, FILLED_SHAPE_REQUIREMENTS},
406 {FilledLengthMajorAxis, "FILLED_LENGTH_MAJOR_AXIS",
407 "Major-axis length proxy of the filled region, with the LENGTH_MAJOR_AXIS convention.", true, FILLED_SHAPE_REQUIREMENTS},
408 {FilledLengthMinorAxis, "FILLED_LENGTH_MINOR_AXIS",
409 "Minor-axis length proxy of the filled region, with the LENGTH_MINOR_AXIS convention.", true, FILLED_SHAPE_REQUIREMENTS},
410 {FilledAxisOrientation, "FILLED_AXIS_ORIENTATION",
411 "Non-negative principal column-axis orientation of the filled region in degrees; isotropic regions return zero.", true, FILLED_SHAPE_REQUIREMENTS},
412 {FilledEccentricity, "FILLED_ECCENTRICITY",
413 "Major/minor eigenvalue ratio of the filled region pixel-center moments, capped at 1e6; one pixel returns one.", true, FILLED_SHAPE_REQUIREMENTS},
414 {FilledInertia, "FILLED_INERTIA",
415 "Sum of the filled region second central moments divided by squared filled area.", true, FILLED_SHAPE_REQUIREMENTS},
416 {HoleAreaFraction, "HOLE_AREA_FRACTION",
417 "Fraction of the filled area occupied by holes: 1 - AREA / FILLED_AREA.", true, FILLED_SHAPE_REQUIREMENTS},
418 {FilledCentroidDisplacementNormalized, "FILLED_CENTROID_DISPLACEMENT_NORMALIZED",
419 "Distance between support and filled-region centroids divided by the square root of FILLED_AREA.", true, FILLED_SHAPE_REQUIREMENTS},
420 {FilledCompactness, "FILLED_COMPACTNESS",
421 "Filled area divided by 2*pi times the sum of filled-region second central moments; zero dispersion returns zero.", true, FILLED_SHAPE_REQUIREMENTS},
422 {FilledCircularity, "FILLED_CIRCULARITY",
423 "Minor/major eigenvalue ratio of the filled-region second moments; one pixel returns one and a nontrivial line returns zero.",
424 true, FILLED_SHAPE_REQUIREMENTS},
425 {AxisOrientationSigned, "AXIS_ORIENTATION_SIGNED",
426 "Signed principal column-axis orientation of the node support in degrees, in [-90, 90], with positive row direction downward; "
427 "isotropic regions return zero.", true, GRID_DOMAIN_2D_REQUIREMENTS},
428 {FilledAxisOrientationSigned, "FILLED_AXIS_ORIENTATION_SIGNED",
429 "Signed principal column-axis orientation of the filled region in degrees, in [-90, 90], with positive row direction downward; "
430 "isotropic regions return zero.", true, FILLED_SHAPE_REQUIREMENTS},
431 {RawInertia, "RAW_INERTIA",
432 "Raw inertia: Unnormalized polar second central moment mu20 + mu02, equal to the sum of squared Euclidean distances from support pixels to the support "
433 "centroid.",
434 true, GRID_DOMAIN_2D_REQUIREMENTS}}};
435
441inline constexpr bool hasOrdinallyAlignedAttributeMetadata() noexcept {
442 for (std::size_t index = 0; index < ATTRIBUTE_METADATA.size(); ++index) {
443 if (static_cast<std::size_t>(ATTRIBUTE_METADATA[index].attribute) != index) {
444 return false;
445 }
446 }
447 return true;
448}
449
450static_assert(hasOrdinallyAlignedAttributeMetadata(), "Attribute metadata rows must match Attribute enum ordinals.");
451
458inline const AttributeMetadata* metadata(Attribute attribute) noexcept {
459 const auto index = static_cast<std::size_t>(attribute);
460 if (index >= ATTRIBUTE_METADATA.size()) {
461 return nullptr;
462 }
463 const AttributeMetadata& item = ATTRIBUTE_METADATA[index];
464 return item.attribute == attribute ? &item : nullptr;
465}
466
476inline std::string_view name(Attribute attribute) noexcept {
477 const AttributeMetadata* item = metadata(attribute);
478 return item != nullptr ? item->name : std::string_view("UNKNOWN");
479}
480
487inline std::string_view description(Attribute attribute) noexcept {
488 const AttributeMetadata* item = metadata(attribute);
489 return item != nullptr ? item->description : std::string_view("Unknown attribute.");
490}
491
498inline bool requiresAltitude(Attribute attribute) noexcept {
499 const AttributeMetadata* item = metadata(attribute);
500 return item != nullptr && item->requirements.altitude;
501}
502
509inline bool isTopologyOnly(Attribute attribute) noexcept {
510 const AttributeMetadata* item = metadata(attribute);
511 return item != nullptr && item->topologyOnly;
512}
513
523inline AttributeCapabilityRequirements capabilityRequirements(Attribute attribute) noexcept {
524 const AttributeMetadata* item = metadata(attribute);
525 return item != nullptr ? item->requirements : AttributeCapabilityRequirements{};
526}
527
537inline bool isAttributePipelineAltitudeAttribute(Attribute attribute) noexcept { return attribute == Area || requiresAltitude(attribute); }
538
545inline bool isPipelineComputed(Attribute attribute) noexcept { return attribute == Area || requiresAltitude(attribute) || isTopologyOnly(attribute); }
546
556inline std::optional<Attribute> parse(std::string_view nameToFind) noexcept {
557 for (const AttributeMetadata& item : ATTRIBUTE_METADATA) {
558 if (item.name == nameToFind) {
559 return item.attribute;
560 }
561 }
562 return std::nullopt;
563}
564
574inline const std::unordered_map<AttributeGroup, std::vector<Attribute>>& attributeGroups() {
575 static const std::unordered_map<AttributeGroup, std::vector<Attribute>> groups = [] {
576 std::vector<Attribute> all;
577 all.reserve(ATTRIBUTE_METADATA.size());
578 for (const AttributeMetadata& item : ATTRIBUTE_METADATA) {
579 all.push_back(item.attribute);
580 }
581
582 return std::unordered_map<AttributeGroup, std::vector<Attribute>>{
583 {AttributeGroup::GrayLevel, {Volume, RelativeVolume, GrayLevelHeight, MeanGrayLevel, GrayLevelVariance}},
584 {AttributeGroup::Shape,
585 {Area,
586 BoundingBoxWidth,
587 BoundingBoxHeight,
588 DiagonalLength,
589 Rectangularity,
590 RatioWh,
591 BoxColumnMin,
592 BoxColumnMax,
593 BoxRowMin,
594 BoxRowMax,
595 CentralMoment20,
596 CentralMoment02,
597 CentralMoment11,
598 CentralMoment30,
599 CentralMoment03,
600 CentralMoment21,
601 CentralMoment12,
602 HuMoment1,
603 HuMoment2,
604 HuMoment3,
605 HuMoment4,
606 HuMoment5,
607 HuMoment6,
608 HuMoment7,
609 Inertia,
610 Compactness,
611 Eccentricity,
612 LengthMajorAxis,
613 LengthMinorAxis,
614 AxisOrientation,
615 Circularity,
616 BitquadArea,
617 BitquadNumberEuler,
618 BitquadNumberHoles,
619 BitquadPerimeter,
620 BitquadPerimeterContinuous,
621 BitquadCircularity,
622 BitquadPerimeterAverage,
623 BitquadLengthAverage,
624 BitquadWidthAverage,
625 MaxDist,
626 MaxDistExact,
627 ContourPixels,
628 ContourPerimeter,
629 ContourSideNorth,
630 ContourSideWest,
631 ContourSideEast,
632 ContourSideSouth,
633 AxisOrientationSigned,
634 RawInertia}},
635 {AttributeGroup::Moments,
636 {CentralMoment20, CentralMoment02, CentralMoment11, CentralMoment30, CentralMoment03, CentralMoment21, CentralMoment12,
637 HuMoment1, HuMoment2, HuMoment3, HuMoment4, HuMoment5, HuMoment6, HuMoment7,
638 Inertia, Compactness, Eccentricity, LengthMajorAxis, LengthMinorAxis, AxisOrientation, Circularity, AxisOrientationSigned,
639 RawInertia}},
640 {AttributeGroup::Boundary,
641 {BitquadArea, BitquadNumberEuler, BitquadNumberHoles, BitquadPerimeter, BitquadPerimeterContinuous, BitquadCircularity,
642 BitquadPerimeterAverage, BitquadLengthAverage, BitquadWidthAverage, ContourPixels, ContourPerimeter, ContourSideNorth,
643 ContourSideWest, ContourSideEast, ContourSideSouth}},
644 {AttributeGroup::TreeTopology,
645 {SubtreeHeight, DepthNode, IsLeafNode, IsRootNode, NumChildrenNode, NumSiblingsNode, NumDescendantsNode, NumLeafDescendantsNode,
646 LeafRatioNode, BalanceNode, AvgChildHeightNode}},
647 {AttributeGroup::DistTransf,
648 {MaxDist,
649 MaxSquaredDist,
650 DistSquaredSum,
651 DistSquaredMean,
652 DistRms,
653 DistSquaredVariance,
654 MaxDistCenterRow,
655 MaxDistCenterColumn,
656 MaxDistPlateauArea,
657 MaxDistPlateauCentroidRow,
658 MaxDistPlateauCentroidColumn,
659 DistSum,
660 DistMean,
661 DistVariance,
662 DistMedian,
663 DistMode,
664 DistQ25,
665 DistQ75,
666 DistQ90,
667 DistEntropy,
668 DistPositiveArea,
669 DistLevelCount,
670 DistWeightedCentroidRow,
671 DistWeightedCentroidColumn,
672 DistWeightedCentralMoment20,
673 DistWeightedCentralMoment02,
674 DistWeightedCentralMoment11,
675 DistWeightedAxisOrientation,
676 DistWeightedEccentricity}},
677 {AttributeGroup::DistTransfExact,
678 {MaxDistExact,
679 MaxSquaredDistExact,
680 DistSquaredSumExact,
681 DistSquaredMeanExact,
682 DistRmsExact,
683 DistSquaredVarianceExact,
684 MaxDistCenterRowExact,
685 MaxDistCenterColumnExact,
686 MaxDistPlateauAreaExact,
687 MaxDistPlateauCentroidRowExact,
688 MaxDistPlateauCentroidColumnExact,
689 DistSumExact,
690 DistMeanExact,
691 DistVarianceExact,
692 DistMedianExact,
693 DistModeExact,
694 DistQ25Exact,
695 DistQ75Exact,
696 DistQ90Exact,
697 DistEntropyExact,
698 DistPositiveAreaExact,
699 DistLevelCountExact,
700 DistWeightedCentroidRowExact,
701 DistWeightedCentroidColumnExact,
702 DistWeightedCentralMoment20Exact,
703 DistWeightedCentralMoment02Exact,
704 DistWeightedCentralMoment11Exact,
705 DistWeightedAxisOrientationExact,
706 DistWeightedEccentricityExact}},
707 {AttributeGroup::FilledShape,
708 {FilledArea, FilledCentroidRow, FilledCentroidColumn, FilledLengthMajorAxis, FilledLengthMinorAxis,
709 FilledAxisOrientation, FilledEccentricity, FilledInertia, HoleAreaFraction, FilledCentroidDisplacementNormalized,
710 FilledCompactness, FilledCircularity, FilledAxisOrientationSigned}},
711 {AttributeGroup::All, std::move(all)}};
712 }();
713 return groups;
714}
715
716} // 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.