Skip to content

feat(np_utils): Voronoi / nearest-label expansion - #147

Merged
Hendrik-code merged 3 commits into
mainfrom
feat/np-voronoi-labels
Oct 12, 2026
Merged

Hendrik-code merged 3 commits into
mainfrom
feat/np-voronoi-labels

Conversation

@Hendrik-code

@Hendrik-code Hendrik-code commented Aug 31, 2026 •

Copy link
Copy Markdown
Owner

Upstreams the nearest-label partition from voronoi-loss's make_voronoi_arr, using panoptica's
algorithm (Apache-2.0, panoptica/_functionals.py::_get_voronoi_regions) instead of its
implementation.

What's new

np_voronoi_labels(arr, label_ref, max_distance, zoom, signed_background, tie_to_zero) assigns every
voxel the label of the nearest labelled region, keeping voronoi-loss's semantics:

  • labelled voxels keep their positive label,
  • background voxels carry the negated label of the region they were assigned to, so the original
    mask is still recoverable from the result,
  • voxels exactly equidistant to two different regions are set to 0 rather than broken arbitrarily.
>>> arr = np.zeros((5, 1, 1), dtype=np.uint8); arr[0] = 1; arr[4] = 2
>>> np_voronoi_labels(arr).ravel().tolist()
[1, -1, 0, -2, 2]

np_expand_labels(arr, distance, ...) is the plain unsigned form — the unbounded, spacing-aware
sibling of the existing np_dilate_msk_euclid.

Why the rewrite

voronoi-loss ran one full-array distance transform per label — O(n_labels · n_voxels) — and
needed a Ray cluster with an object store and a /tmp/spill directory to make that tractable. The
whole partition falls out of a single Euclidean feature transform of the background instead, since
the nearest background voxel of arr == 0 is exactly the nearest labelled voxel of arr.

volume np_voronoi_labels voronoi-loss loop (serial, no Ray)
128³, 150 labels 1.9 s 55.8 s
256×256×128, 300 labels 7.5 s 426.1 s

Both outputs are voxel-identical.

Unlike the original, the cost does not grow with the label count at all.

Recovering the ties

The equidistant voxels came for free from the original's per-label loop; distance_transform_edt
picks one nearest source and never reports that the choice was arbitrary, so they have to be found
afterwards. _np_voronoi_ties restricts the search to voxels next to a change in the nearest-label
assignment, then tests each of their neighbours' nearest sources for being at exactly the same
distance. Any neighbour's source is a real foreground voxel, so a hit is always a genuine tie — the
test can miss one, but never invent one. In practice it is exact.

Additions on top of the original

label_ref to partition by a subset of labels, max_distance to leave far background voxels empty,
zoom for anisotropic voxel spacing, and flags to turn the signing and the tie handling off.

Tests

16 tests in unit_tests/test_nputils.py, including a per-voxel brute-force reference (isotropic and
anisotropic, 2D and 3D). The output is also voxel-identical to voronoi-loss's original loop on random
2D and 3D masks — verified locally, not committed, since reproducing it needs that repo.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GFZf44LHBB6N5jaf6YFzhx

Upstreams the nearest-label partition from voronoi-loss's make_voronoi_arr,
keeping its semantics: labelled voxels keep their positive label, background
voxels carry the negated label of the region they were assigned to, and voxels
exactly equidistant to two different regions are set to 0 instead of being
broken arbitrarily.

The algorithm is panoptica's (Apache-2.0, panoptica/_functionals.py
_get_voronoi_regions): a single Euclidean feature transform of the background,
since the nearest background voxel of `arr == 0` is exactly the nearest
labelled voxel of `arr`. voronoi-loss instead ran one full-array distance
transform per label and needed a Ray cluster and a spill directory to make that
tractable. On a 128^3 volume with 150 labels this is 1.9s against 55.8s for the
original loop on one core, and unlike the original the cost does not grow with
the label count.

The equidistant voxels the original got for free from its per-label loop have
to be recovered afterwards, because distance_transform_edt picks one nearest
source and never reports that the choice was arbitrary. _np_voronoi_ties finds
them by restricting to voxels next to a change in the assignment and testing
each of their neighbours' nearest sources for being at exactly the same
distance. Any such source is a real foreground voxel, so a hit is always a
genuine tie - the test can miss one, but never invent one. In practice it is
exact: the result is voxel-identical to the original on random 2D and 3D masks,
and to a brute-force per-voxel reference.

Added on top of the original: label_ref to partition by a subset, max_distance
to leave far background voxels empty, zoom for anisotropic spacing, and flags
to turn off the signing and the tie handling. np_expand_labels is that plain
form, the unbounded and spacing-aware sibling of np_dilate_msk_euclid.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GFZf44LHBB6N5jaf6YFzhx
@github-actions

github-actions Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Benchmark comparison

Speed (wall time per call)

baseline 872d239 vs head 872d239 · python 3.11.17 · 5 repeats + 1 warmup

Showing the 5 most-changed measurements per case; the rest are collapsed. Rows with a baseline below 3 ms are tagged (noise) — runner jitter on those swamps any real change.

ct_3d — shape (73, 47, 73)

Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_fill_holes 4.45 ±0.07 4.63 ±0.09 +4.1% 0.012
poi_calc_poi_from_subreg_vert 13.10 ±0.06 12.76 ±0.13 -2.6% 0.001
poi_calc_centroids_nocrop 4.36 ±0.17 4.43 ±0.11 +1.5% 0.586
nii_dilate_msk 124.95 ±0.40 126.36 ±0.43 +1.1% 0.000
nii_rescale 39.96 ±0.31 40.26 ±0.64 +0.8% 0.163
… 31 more measurements
Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_load_img 10.85 ±0.08 10.78 ±0.06 -0.6% 0.130
nii_filter_connected_components 4.43 ±0.11 4.41 ±0.05 -0.4% 0.533
nii_erode_msk 6.27 ±0.04 6.25 ±0.07 -0.3% 0.930
nii_save 11.80 ±0.12 11.77 ±0.12 -0.3% 0.598
nii_rescale_seg 3.16 ±0.04 3.16 ±0.06 +0.1% 0.622
nii_resample_from_to 42.18 ±0.33 42.16 ±0.66 -0.1% 0.340
metric_voxels 250463.00 ±0.00 250463.00 ±0.00 +0.0% —
metric_labels 3.00 ±0.00 3.00 ±0.00 +0.0% —
metric_foreground_pct 14.51 ±0.00 14.51 ±0.00 +0.0% —
poi_reorient 0.34 ±0.04 0.45 ±0.04 +32.3% (noise) 0.008
poi_to_global 0.17 ±0.02 0.21 ±0.03 +26.4% (noise) 0.020
poi_save 0.39 ±0.04 0.46 ±0.02 +19.0% (noise) 0.048
poi_load 0.99 ±0.03 1.17 ±0.01 +17.7% (noise) 0.000
nii_extract_label 0.33 ±0.04 0.37 ±0.02 +13.1% (noise) 0.311
poi_local_to_global_arr 0.29 ±0.02 0.32 ±0.02 +9.9% (noise) 0.321
nii_get_array 0.05 ±0.01 0.05 ±0.00 -8.2% (noise) 0.157
poi_map_labels 0.15 ±0.01 0.16 ±0.01 +8.1% (noise) 0.107
poi_resample_from_to 0.70 ±0.05 0.65 ±0.04 -7.0% (noise) 0.046
nii_set_dtype 0.46 ±0.03 0.49 ±0.05 +6.8% (noise) 0.254
nii_map_labels 1.01 ±0.04 1.07 ±0.07 +6.4% (noise) 0.157
nii_apply_crop 0.63 ±0.03 0.60 ±0.03 -5.4% (noise) 0.428
poi_rescale 0.21 ±0.02 0.20 ±0.01 -4.5% (noise) 0.927
nii_load_seg 2.90 ±0.19 2.78 ±0.06 -4.2% (noise) 0.348
nii_reorient 0.78 ±0.04 0.81 ±0.01 +3.0% (noise) 0.688
nii_pad_to 0.68 ±0.03 0.67 ±0.06 -2.4% (noise) 0.421
poi_calc_centroids 2.46 ±0.08 2.50 ±0.07 +1.8% (noise) 0.096
nii_unique 0.67 ±0.02 0.68 ±0.02 +1.3% (noise) 0.350
nii_get_connected_components 2.36 ±0.07 2.33 ±0.08 -1.2% (noise) 0.737
nii_center_of_masses 1.72 ±0.02 1.73 ±0.01 +0.5% (noise) 0.875
nii_volumes 1.85 ±0.01 1.86 ±0.01 +0.5% (noise) 0.131
nii_compute_crop 0.33 ±0.01 0.33 ±0.01 +0.4% (noise) 0.471

ct_2d — shape (73, 47, 1)

Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_rescale 5.57 ±0.06 5.45 ±0.12 -2.2% 0.264
nii_dilate_msk 14.68 ±0.10 14.90 ±0.07 +1.5% 0.003
nii_resample_from_to 7.69 ±0.15 7.63 ±0.08 -0.8% 0.173
metric_voxels 3431.00 ±0.00 3431.00 ±0.00 +0.0% —
metric_labels 3.00 ±0.00 3.00 ±0.00 +0.0% —
… 30 more measurements
Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
metric_foreground_pct 37.60 ±0.00 37.60 ±0.00 +0.0% —
poi_map_labels 0.23 ±0.16 0.20 ±0.01 -12.2% (noise) 0.306
nii_unique 0.13 ±0.01 0.14 ±0.01 +9.4% (noise) 0.511
nii_pad_to 0.62 ±0.02 0.57 ±0.02 -7.9% (noise) 0.006
poi_to_global 0.25 ±0.01 0.23 ±0.01 -7.3% (noise) 0.114
nii_rescale_seg 0.87 ±0.04 0.81 ±0.04 -7.1% (noise) 0.011
poi_reorient 0.48 ±0.02 0.45 ±0.02 -6.7% (noise) 0.047
nii_extract_label 0.46 ±0.02 0.43 ±0.04 -6.7% (noise) 0.307
nii_save 1.50 ±0.04 1.40 ±0.04 -6.2% (noise) 0.001
poi_resample_from_to 0.79 ±0.03 0.75 ±0.02 -5.4% (noise) 0.053
nii_center_of_masses 0.22 ±0.01 0.23 ±0.01 +5.0% (noise) 0.432
nii_get_connected_components 0.71 ±0.02 0.67 ±0.03 -4.9% (noise) 0.024
nii_volumes 0.31 ±0.02 0.30 ±0.03 -4.5% (noise) 0.931
nii_map_labels 0.50 ±0.02 0.48 ±0.02 -4.4% (noise) 0.065
nii_load_img 1.65 ±0.08 1.59 ±0.03 -4.2% (noise) 0.074
poi_calc_centroids 1.01 ±0.03 0.97 ±0.03 -3.9% (noise) 0.082
nii_filter_connected_components 0.89 ±0.01 0.86 ±0.02 -3.4% (noise) 0.020
poi_calc_centroids_nocrop 1.24 ±0.04 1.20 ±0.02 -3.4% (noise) 0.160
poi_save 0.51 ±0.04 0.50 ±0.02 -3.1% (noise) 0.123
poi_rescale 0.26 ±0.01 0.25 ±0.01 -2.6% (noise) 0.405
nii_load_seg 1.79 ±0.05 1.74 ±0.05 -2.5% (noise) 0.080
nii_apply_crop 0.73 ±0.03 0.72 ±0.05 -1.8% (noise) 0.470
nii_erode_msk 1.03 ±0.02 1.02 ±0.03 -1.2% (noise) 0.523
nii_set_dtype 0.43 ±0.01 0.43 ±0.02 +0.7% (noise) 0.659
nii_reorient 0.90 ±0.02 0.91 ±0.03 +0.7% (noise) 0.447
poi_load 1.22 ±0.05 1.21 ±0.03 -0.7% (noise) 0.683
nii_fill_holes 0.89 ±0.02 0.90 ±0.02 +0.6% (noise) 0.935
poi_local_to_global_arr 0.35 ±0.01 0.35 ±0.02 -0.6% (noise) 0.981
nii_get_array 0.02 ±0.00 0.02 ±0.00 -0.6% (noise) 0.857
nii_compute_crop 0.15 ±0.01 0.15 ±0.01 -0.1% (noise) 0.882

mri_3d — shape (68, 52, 67)

Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
poi_calc_centroids_nocrop 8.51 ±0.20 8.79 ±0.11 +3.3% 0.044
nii_fill_holes 5.40 ±0.04 5.53 ±0.07 +2.3% 0.005
nii_load_img 8.79 ±0.06 8.99 ±0.17 +2.2% 0.068
nii_rescale_seg 3.39 ±0.11 3.33 ±0.09 -2.0% 0.558
nii_save 9.60 ±0.19 9.43 ±0.06 -1.8% 0.090
… 31 more measurements
Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_resample_from_to 40.27 ±0.22 40.66 ±0.38 +1.0% 0.038
nii_erode_msk 7.75 ±0.09 7.82 ±0.10 +0.9% 0.112
nii_filter_connected_components 4.76 ±0.07 4.80 ±0.05 +0.8% 0.101
nii_dilate_msk 162.61 ±1.51 163.69 ±0.71 +0.7% 0.549
nii_load_seg 3.00 ±0.06 2.99 ±0.08 -0.4% 0.440
poi_calc_poi_from_subreg_vert 12.21 ±0.06 12.26 ±0.11 +0.4% 0.068
nii_rescale 38.22 ±0.28 38.19 ±0.70 -0.1% 0.392
metric_voxels 236912.00 ±0.00 236912.00 ±0.00 +0.0% —
metric_labels 8.00 ±0.00 8.00 ±0.00 +0.0% —
metric_foreground_pct 18.21 ±0.00 18.21 ±0.00 +0.0% —
poi_to_global 0.26 ±0.02 0.30 ±0.05 +15.9% (noise) 0.081
nii_get_array 0.06 ±0.00 0.06 ±0.01 +15.3% (noise) 0.012
nii_extract_label 0.47 ±0.02 0.51 ±0.03 +8.6% (noise) 0.026
poi_load 2.33 ±0.07 2.51 ±0.08 +7.3% (noise) 0.004
poi_rescale 0.28 ±0.02 0.30 ±0.01 +7.3% (noise) 0.018
poi_save 0.53 ±0.02 0.57 ±0.01 +7.0% (noise) 0.015
poi_reorient 0.49 ±0.01 0.51 ±0.03 +5.4% (noise) 0.056
poi_map_labels 0.24 ±0.01 0.25 ±0.01 +4.6% (noise) 0.018
nii_apply_crop 0.76 ±0.03 0.79 ±0.02 +3.8% (noise) 0.299
nii_get_connected_components 2.25 ±0.04 2.33 ±0.10 +3.4% (noise) 0.043
nii_pad_to 0.77 ±0.01 0.79 ±0.01 +3.1% (noise) 0.003
poi_resample_from_to 0.81 ±0.03 0.83 ±0.04 +2.9% (noise) 0.402
poi_calc_centroids 2.82 ±0.03 2.89 ±0.04 +2.7% (noise) 0.007
poi_local_to_global_arr 0.34 ±0.02 0.35 ±0.00 +2.7% (noise) 0.517
nii_unique 0.69 ±0.01 0.70 ±0.01 +2.5% (noise) 0.029
nii_set_dtype 0.57 ±0.02 0.58 ±0.02 +1.9% (noise) 0.298
nii_volumes 1.96 ±0.01 1.98 ±0.02 +0.9% (noise) 0.083
nii_reorient 0.93 ±0.03 0.94 ±0.03 +0.9% (noise) 0.747
nii_center_of_masses 2.01 ±0.04 2.02 ±0.02 +0.7% (noise) 0.492
nii_compute_crop 0.34 ±0.01 0.34 ±0.02 +0.3% (noise) 0.497
nii_map_labels 1.11 ±0.03 1.11 ±0.04 +0.2% (noise) 0.253

mri_2d — shape (68, 52, 1)

Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_rescale 5.48 ±0.04 5.58 ±0.05 +1.7% 0.002
nii_dilate_msk 19.55 ±0.11 19.86 ±0.21 +1.6% 0.021
nii_resample_from_to 7.66 ±0.08 7.65 ±0.08 -0.1% 0.674
metric_voxels 3536.00 ±0.00 3536.00 ±0.00 +0.0% —
metric_labels 7.00 ±0.00 7.00 ±0.00 +0.0% —
… 30 more measurements
Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
metric_foreground_pct 50.17 ±0.00 50.17 ±0.00 +0.0% —
nii_volumes 0.46 ±0.04 0.52 ±0.08 +13.1% (noise) 0.052
nii_extract_label 0.44 ±0.03 0.49 ±0.03 +12.5% (noise) 0.019
poi_save 0.53 ±0.04 0.59 ±0.02 +11.2% (noise) 0.020
nii_rescale_seg 0.78 ±0.03 0.85 ±0.04 +9.8% (noise) 0.004
nii_erode_msk 1.31 ±0.02 1.42 ±0.04 +8.1% (noise) 0.001
nii_save 1.40 ±0.02 1.51 ±0.04 +8.0% (noise) 0.001
nii_reorient 0.84 ±0.01 0.90 ±0.03 +7.6% (noise) 0.008
nii_center_of_masses 0.42 ±0.01 0.45 ±0.00 +7.1% (noise) 0.004
nii_load_seg 1.71 ±0.10 1.83 ±0.09 +7.0% (noise) 0.043
nii_get_connected_components 0.63 ±0.02 0.67 ±0.02 +6.7% (noise) 0.047
nii_fill_holes 1.11 ±0.02 1.18 ±0.01 +6.6% (noise) 0.000
poi_calc_centroids 1.14 ±0.04 1.20 ±0.02 +5.9% (noise) 0.033
nii_filter_connected_components 0.87 ±0.04 0.92 ±0.02 +5.9% (noise) 0.026
poi_reorient 0.47 ±0.01 0.50 ±0.01 +5.3% (noise) 0.037
nii_compute_crop 0.14 ±0.01 0.15 ±0.01 +4.9% (noise) 0.109
nii_set_dtype 0.42 ±0.01 0.44 ±0.03 +4.6% (noise) 0.059
poi_resample_from_to 0.85 ±0.03 0.82 ±0.02 -4.0% (noise) 0.180
nii_map_labels 0.50 ±0.04 0.52 ±0.02 +3.8% (noise) 0.043
nii_load_img 1.57 ±0.04 1.63 ±0.02 +3.8% (noise) 0.019
poi_to_global 0.28 ±0.02 0.27 ±0.01 -3.5% (noise) 0.859
poi_map_labels 0.24 ±0.02 0.25 ±0.01 +2.2% (noise) 0.713
poi_rescale 0.29 ±0.02 0.29 ±0.01 -2.1% (noise) 0.340
nii_apply_crop 0.72 ±0.02 0.74 ±0.05 +2.0% (noise) 0.219
nii_pad_to 0.60 ±0.01 0.59 ±0.02 -1.9% (noise) 0.561
nii_unique 0.13 ±0.01 0.13 ±0.01 +1.6% (noise) 0.384
poi_calc_centroids_nocrop 1.46 ±0.04 1.48 ±0.05 +1.3% (noise) 0.828
nii_get_array 0.02 ±0.00 0.02 ±0.00 +0.5% (noise) 0.530
poi_load 2.25 ±0.08 2.25 ±0.09 +0.2% (noise) 0.516
poi_local_to_global_arr 0.37 ±0.01 0.37 ±0.01 -0.2% (noise) 0.935

Gate: a measurement fails when the baseline is ≥ 1 ms, the median grows by ≥ 50%, and Welch's t-test gives p < 0.05. metric_* rows are context only.

Memory (peak RSS growth per call)

baseline 872d239 vs head 872d239 · python 3.11.17 · 5 repeats + 1 warmup · sampler proc-status, isolation fork · measurement floor ≈ 0.90 MiB

Showing the 5 most-changed measurements per case; the rest are collapsed. Rows with a baseline below 3 MiB are tagged (noise) — runner jitter on those swamps any real change.

ct_3d — shape (73, 47, 73)

Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
poi_resample_from_to 5.27 ±0.00 5.18 ±0.00 -1.9% —
nii_reorient 5.90 ±0.00 5.81 ±0.00 -1.6% —
nii_rescale 6.16 ±0.00 6.07 ±0.00 -1.5% —
nii_resample_from_to 6.29 ±0.00 6.20 ±0.00 -1.5% 0.000
nii_extract_label 5.36 ±0.00 5.30 ±0.00 -1.1% —
… 31 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
nii_map_labels 5.49 ±0.00 5.43 ±0.00 -1.1% —
nii_set_dtype 5.24 ±0.00 5.18 ±0.00 -1.0% —
nii_pad_to 5.42 ±0.00 5.37 ±0.00 -1.0% —
nii_apply_crop 5.86 ±0.00 5.80 ±0.00 -0.9% —
poi_calc_centroids_nocrop 5.92 ±0.00 5.87 ±0.00 -0.9% —
nii_dilate_msk 5.93 ±0.00 5.87 ±0.00 -0.9% —
nii_rescale_seg 5.94 ±0.00 5.88 ±0.00 -0.9% —
nii_erode_msk 5.94 ±0.00 5.89 ±0.00 -0.9% —
poi_calc_centroids 6.05 ±0.00 6.00 ±0.00 -0.9% —
poi_calc_poi_from_subreg_vert 7.11 ±0.00 7.05 ±0.00 -0.9% —
nii_fill_holes 6.28 ±0.00 6.22 ±0.00 -0.9% —
nii_get_connected_components 6.61 ±0.00 6.56 ±0.00 -0.8% 0.000
nii_filter_connected_components 6.86 ±0.00 6.81 ±0.00 -0.8% —
nii_load_img 3.55 ±0.00 3.58 ±0.00 +0.7% 0.000
nii_load_seg 6.00 ±0.00 5.96 ±0.00 -0.7% —
poi_to_global 3.08 ±0.00 3.09 ±0.00 +0.3% —
nii_center_of_masses 3.27 ±0.00 3.28 ±0.00 +0.2% —
nii_volumes 3.52 ±0.00 3.53 ±0.00 +0.2% —
nii_save 3.70 ±0.00 3.71 ±0.00 +0.2% —
poi_reorient 3.83 ±0.00 3.84 ±0.00 +0.2% —
metric_voxels 250463.00 ±0.00 250463.00 ±0.00 +0.0% —
metric_labels 3.00 ±0.00 3.00 ±0.00 +0.0% —
metric_foreground_pct 14.51 ±0.00 14.51 ±0.00 +0.0% —
nii_get_array 1.64 ±0.00 1.65 ±0.00 +0.5% (noise) —
poi_save 1.39 ±0.00 1.40 ±0.00 +0.3% (noise) —
nii_compute_crop 2.89 ±0.00 2.90 ±0.00 +0.3% (noise) —
poi_local_to_global_arr 2.95 ±0.00 2.96 ±0.00 +0.3% (noise) —
nii_unique 2.96 ±0.00 2.96 ±0.00 +0.3% (noise) —
poi_load 1.61 ±0.00 1.61 ±0.00 +0.2% (noise) —
poi_map_labels 1.77 ±0.00 1.77 ±0.00 +0.2% (noise) —
poi_rescale 2.60 ±0.00 2.61 ±0.00 +0.2% (noise) —

ct_2d — shape (73, 47, 1)

Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
poi_resample_from_to 5.21 ±0.00 5.11 ±0.00 -1.9% —
nii_reorient 5.84 ±0.00 5.74 ±0.00 -1.7% —
nii_rescale 6.10 ±0.00 6.00 ±0.00 -1.6% —
nii_resample_from_to 6.23 ±0.03 6.13 ±0.00 -1.6% 0.002
nii_set_dtype 5.18 ±0.00 5.12 ±0.00 -1.1% —
… 30 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
nii_extract_label 5.30 ±0.00 5.24 ±0.00 -1.1% —
nii_pad_to 5.36 ±0.00 5.30 ±0.00 -1.1% —
nii_map_labels 5.43 ±0.00 5.37 ±0.00 -1.1% —
nii_apply_crop 5.80 ±0.00 5.74 ±0.00 -1.0% —
nii_dilate_msk 5.86 ±0.00 5.80 ±0.00 -1.0% —
nii_rescale_seg 5.88 ±0.00 5.82 ±0.00 -1.0% —
nii_erode_msk 5.88 ±0.00 5.82 ±0.00 -1.0% —
poi_calc_centroids_nocrop 5.92 ±0.00 5.86 ±0.00 -1.0% —
poi_calc_centroids 5.99 ±0.00 5.93 ±0.00 -1.0% —
nii_fill_holes 6.21 ±0.00 6.16 ±0.00 -0.9% —
nii_get_connected_components 6.55 ±0.00 6.49 ±0.00 -0.9% —
nii_filter_connected_components 6.80 ±0.00 6.74 ±0.00 -0.9% —
nii_load_seg 5.94 ±0.00 5.89 ±0.00 -0.7% —
nii_load_img 3.49 ±0.00 3.51 ±0.00 +0.6% —
poi_to_global 3.02 ±0.00 3.02 ±0.00 +0.1% —
nii_center_of_masses 3.21 ±0.00 3.21 ±0.00 +0.1% —
nii_volumes 3.46 ±0.00 3.46 ±0.00 +0.1% —
nii_save 3.64 ±0.00 3.64 ±0.00 +0.1% —
poi_reorient 3.77 ±0.00 3.77 ±0.00 +0.1% —
metric_voxels 3431.00 ±0.00 3431.00 ±0.00 +0.0% —
metric_labels 3.00 ±0.00 3.00 ±0.00 +0.0% —
metric_foreground_pct 37.60 ±0.00 37.60 ±0.00 +0.0% —
poi_save 1.33 ±0.00 1.34 ±0.00 +0.3% (noise) —
poi_load 1.55 ±0.00 1.55 ±0.00 +0.3% (noise) —
nii_get_array 1.58 ±0.00 1.59 ±0.00 +0.2% (noise) —
poi_map_labels 1.71 ±0.00 1.71 ±0.00 +0.2% (noise) —
poi_rescale 2.54 ±0.00 2.54 ±0.00 +0.2% (noise) —
nii_compute_crop 2.83 ±0.00 2.84 ±0.00 +0.1% (noise) —
poi_local_to_global_arr 2.89 ±0.00 2.89 ±0.00 +0.1% (noise) —
nii_unique 2.89 ±0.00 2.90 ±0.00 +0.1% (noise) —

mri_3d — shape (68, 52, 67)

Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
poi_resample_from_to 5.21 ±0.00 5.11 ±0.00 -1.9% —
nii_reorient 5.84 ±0.00 5.74 ±0.00 -1.7% —
nii_rescale 6.10 ±0.00 6.00 ±0.00 -1.6% —
nii_resample_from_to 6.23 ±0.00 6.13 ±0.00 -1.6% —
nii_set_dtype 5.24 ±0.00 5.18 ±0.00 -1.1% —
… 31 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
nii_extract_label 5.30 ±0.00 5.24 ±0.00 -1.1% —
nii_pad_to 5.36 ±0.00 5.30 ±0.00 -1.1% —
nii_map_labels 5.43 ±0.00 5.37 ±0.00 -1.1% —
nii_apply_crop 5.80 ±0.00 5.74 ±0.00 -1.0% —
poi_calc_centroids_nocrop 5.86 ±0.00 5.80 ±0.00 -1.0% —
nii_dilate_msk 5.86 ±0.00 5.80 ±0.00 -1.0% —
nii_rescale_seg 5.88 ±0.00 5.82 ±0.00 -1.0% —
nii_erode_msk 5.88 ±0.00 5.82 ±0.00 -1.0% —
poi_calc_centroids 5.99 ±0.00 5.93 ±0.00 -1.0% —
nii_fill_holes 6.21 ±0.00 6.16 ±0.00 -0.9% —
nii_get_connected_components 6.55 ±0.00 6.49 ±0.00 -0.9% —
nii_filter_connected_components 6.80 ±0.00 6.74 ±0.00 -0.9% —
poi_calc_poi_from_subreg_vert 7.11 ±0.00 7.05 ±0.00 -0.8% —
nii_load_seg 5.94 ±0.00 5.89 ±0.00 -0.7% —
nii_load_img 3.55 ±0.00 3.57 ±0.00 +0.5% —
poi_to_global 3.02 ±0.00 3.02 ±0.00 +0.1% —
nii_save 3.64 ±0.00 3.64 ±0.00 +0.1% —
poi_reorient 3.77 ±0.00 3.77 ±0.00 +0.1% —
nii_volumes 3.46 ±0.00 3.46 ±0.00 +0.0% —
nii_center_of_masses 3.21 ±0.00 3.21 ±0.00 +0.0% —
metric_voxels 236912.00 ±0.00 236912.00 ±0.00 +0.0% —
metric_labels 8.00 ±0.00 8.00 ±0.00 +0.0% —
metric_foreground_pct 18.21 ±0.00 18.21 ±0.00 +0.0% —
poi_save 1.39 ±0.00 1.40 ±0.00 +0.3% (noise) —
poi_load 1.55 ±0.00 1.55 ±0.00 +0.3% (noise) —
nii_get_array 1.58 ±0.00 1.59 ±0.00 +0.2% (noise) —
poi_map_labels 1.71 ±0.00 1.71 ±0.00 +0.2% (noise) —
poi_rescale 2.54 ±0.00 2.54 ±0.00 +0.2% (noise) —
nii_compute_crop 2.83 ±0.00 2.84 ±0.00 +0.1% (noise) —
poi_local_to_global_arr 2.89 ±0.00 2.89 ±0.00 +0.1% (noise) —
nii_unique 2.89 ±0.00 2.90 ±0.00 +0.1% (noise) —

mri_2d — shape (68, 52, 1)

Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
poi_resample_from_to 5.21 ±0.00 5.11 ±0.00 -1.9% —
nii_reorient 5.84 ±0.00 5.74 ±0.00 -1.7% —
nii_rescale 6.10 ±0.00 6.00 ±0.00 -1.6% —
nii_resample_from_to 6.23 ±0.00 6.13 ±0.00 -1.6% —
nii_set_dtype 5.24 ±0.00 5.18 ±0.00 -1.1% —
… 30 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
nii_extract_label 5.30 ±0.00 5.24 ±0.00 -1.1% —
nii_pad_to 5.36 ±0.00 5.30 ±0.00 -1.1% —
nii_map_labels 5.43 ±0.00 5.37 ±0.00 -1.1% —
nii_apply_crop 5.80 ±0.00 5.74 ±0.00 -1.0% —
nii_dilate_msk 5.86 ±0.00 5.80 ±0.00 -1.0% —
nii_rescale_seg 5.88 ±0.00 5.82 ±0.00 -1.0% —
nii_erode_msk 5.88 ±0.00 5.82 ±0.00 -1.0% —
poi_calc_centroids_nocrop 5.92 ±0.00 5.86 ±0.00 -1.0% —
poi_calc_centroids 5.99 ±0.00 5.93 ±0.00 -1.0% —
nii_fill_holes 6.21 ±0.00 6.16 ±0.00 -0.9% —
nii_get_connected_components 6.55 ±0.00 6.49 ±0.00 -0.9% —
nii_filter_connected_components 6.80 ±0.00 6.74 ±0.00 -0.9% —
nii_load_seg 5.94 ±0.00 5.89 ±0.00 -0.7% —
nii_load_img 3.55 ±0.00 3.57 ±0.00 +0.5% —
poi_to_global 3.02 ±0.00 3.02 ±0.00 +0.1% —
nii_center_of_masses 3.21 ±0.00 3.21 ±0.00 +0.1% —
nii_volumes 3.46 ±0.00 3.46 ±0.00 +0.1% —
nii_save 3.64 ±0.00 3.64 ±0.00 +0.1% —
poi_reorient 3.77 ±0.00 3.77 ±0.00 +0.1% —
metric_voxels 3536.00 ±0.00 3536.00 ±0.00 +0.0% —
metric_labels 7.00 ±0.00 7.00 ±0.00 +0.0% —
metric_foreground_pct 50.17 ±0.00 50.17 ±0.00 +0.0% —
poi_save 1.39 ±0.00 1.40 ±0.00 +0.3% (noise) —
poi_load 1.55 ±0.00 1.55 ±0.00 +0.3% (noise) —
nii_get_array 1.58 ±0.00 1.59 ±0.00 +0.2% (noise) —
poi_map_labels 1.71 ±0.00 1.71 ±0.00 +0.2% (noise) —
poi_rescale 2.54 ±0.00 2.54 ±0.00 +0.2% (noise) —
nii_compute_crop 2.83 ±0.00 2.84 ±0.00 +0.1% (noise) —
poi_local_to_global_arr 2.89 ±0.00 2.89 ±0.00 +0.1% (noise) —
nii_unique 2.89 ±0.00 2.90 ±0.00 +0.1% (noise) —

Gate: a measurement fails when the baseline is ≥ 1 MiB, the median grows by ≥ 50%, and Welch's t-test gives p < 0.05. metric_* rows are context only.

@Hendrik-code Hendrik-code self-assigned this Aug 31, 2026
@Hendrik-code Hendrik-code added the enhancement New feature or request label Aug 31, 2026

@robert-graf robert-graf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add TO NII

Hendrik-code and others added 2 commits October 12, 2026 09:26
Distances default to mm using the image zoom, since the partition itself
changes with anisotropic spacing; use_mm=False falls back to voxels. The
signed dtype chosen by np_voronoi_labels is kept, as the negated labels
would wrap on an unsigned image.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Hendrik-code
Hendrik-code merged commit e012157 into main Oct 12, 2026
6 checks passed
@Hendrik-code
Hendrik-code deleted the feat/np-voronoi-labels branch October 12, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants