vol_label_shape_stats — VOLCOLOR measure op

• Data kinds: labels → table

• Call: import fullseye as fs; fs.ledger.vol_label_shape_stats(labels, spacing=None, shape: 'bool' = True) (to call the implementation directly, import volcolor; volcolor.vol_label_shape_stats(labels, spacing=None, shape: 'bool' = True); from the registry, opsvolcolor.get("vol_label_shape_stats"))

• GPU: none (CPU reference implementation only)

Usage

Per-component quantities that can be had in linear time (volume, centroid, box, PCA shape indices).

Sister of volops.vol_region_props, but with a different purpose:

• It gives out surface_area and Wadell sphericity. For that purpose Since the marching cubes are run for each component, the Python loop is proportional to the number of components. Turn (quickly becomes heavy with pathological input of 1 voxel 1 label).

• This is limited to the amount that requires only the weighted sum of np.bincount. 1 label array 10 bincount(number of pieces 1, coordinate sum 3, covariance 6) = O(N + n). Actual measurement (connectivity=26, Checkerboard pattern of 1 voxel 1 label = pathological input):

163 = 4096 voxels / 512 components = 0.0037 s, 323 = 32768 / 4096 =

0.0350 s, 643 = 262144 / 32768 = 0.2556 s, 1283 = 2097152 / 262144 =

2.3122 s. 9.5 / 7.3 / 9.0 times for every 8 voxels (64 times for quadratic),

Approximately 1.1 microseconds/voxel over the entire area. The same 1283 coloring is 0.0357 s.

(For reference: volops.vol_region_props(surface="faces") is the same 163

0.0121 s -- 3.5 times longer due to the Python loop for each component. marching cubes

The default to use surface="auto" is even heavier. )

label voxel_count volume centroid bbox volops.vol_region_props same definition and same value (tests/test_volcolor.py::test_stats_agree_with_vol_region_props_exactly is (fixed with exact match). bbox is (z0, z1, y0, y1, x0, x1) and the upper limit is exclusive.

What we also return:

centroid_mm (z, y, x) Physical coordinates (same as voxel without spacing)

extent Physical dimensions of bbox (dz, dy, dx) · equivalent_diameter

(6V/pi)(1/3) · touches_border Does bbox touch the volume edge? ·

principal_extent Square root of covariance eigenvalue (s1 >= s2 >= s3)(physical unit) ·

linearity (l1-l2)/l1 · planarity (l2-l3)/l1 · isotropy

l3/l1 · elongation sqrt(l1/l2).

elongation can be infinite (contract): l1 > 0 and l2 == 0, In other words, a perfectly straight line component with a thickness of 1 voxel returns inf. Accident divided by 0 Rather, it is the fact that there is no spread in the second axis direction, and when rounded, the order of slenderness changes. They switch places silently. A single voxel (l1 == 0) is an isotropic point, so it is 1.0.

If you forget to pass spacing, the numbers and conclusions will change. Actual measurement - A sphere with a radius of 6 mm spacing = (3.0, 1.0, 1.0) When sampled with an anisotropic grid of mm (3 times coarser in z), It becomes 293 voxels. The closed-form true value is 4/3 pi 63 = 904.78 mm3:

• With spacing = 879.0 mm3 (error -2.85 %), isotropy = 0.7349 (approximately isotropic = correct).

• No spacing = 293.0 (in voxel units. Error -67.62% when read as mm3), isotropy = 0.0817 -- The sphere looks like a "board". Ignoring anisotropy The shape index is broken, yet returns a finite and reasonable value.

*Equivalent diameter also differs by a factor of 1.44, 11.8849 mm vs. 8.2406.

Numerical note: The second moment is calculated as E[x2] - E[x]2, so the coordinates For components with large and small spreads, loss of precision may occur. Upper limit MAX_COLOR_VOXELS (up to ~2000 on one side), the relative precision of float64 for E[x2] ~ 4e6 is 1e-16 = Absolute 1e-10, with 10 orders of magnitude margin for voxel-wise variance. bigger than that The volume should be passed after cutting the ROI (this is also the reason for the upper limit).

Setting *shape* to False will omit the covariance (bincount of 6 out of 10), principal_extent Do not return the following 5 items -- only volumetric filters are required Sometimes an O(N) temporary array can be reduced to one.

Returns list[dict] in ascending label order (actual labels only) --- labels.max() does not return an empty dict even if there are gaps in the number).

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

• The canonical algorithm (author, year) and its uses are named in the family usage guide above.

Runnable examples (verified samples that actually call this op)

• poc_cold_chain_excursion — py -3.11 examples/poc_cold_chain_excursion.py

• voxel_labels_color — py -3.11 examples/voxel_labels_color.py

Ops the type connects to (they accept table as input)

—

Same category (measure)

vol_label_legend


*Provenance: volcolor.py — VOLCOLOR operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.