Skip to content

feat(NII): split a label at a cumulative-volume fraction or at its center of mass - #146

Merged
Hendrik-code merged 4 commits into
mainfrom
feat/nii-split-label-at
Oct 12, 2026
Merged

Hendrik-code merged 4 commits into
mainfrom
feat/nii-split-label-at

Conversation

@Hendrik-code

Copy link
Copy Markdown
Owner

Upstreams the two reusable kernels hiding inside paraside's split_ethmoid, which wrapped generic
logic around hard-coded ethmoid label ids (7/8/15/16) and offsets (+100/+200).

What's new

NII.split_label_at_cumulative_volume_fraction(labels, axis, fraction, offset) walks slices inwards
from the axis-most end of a mask, summing voxels until fraction of the total volume is covered,
and adds offset to the labels of that slab. This is a volume fraction, not an extent fraction, so
a structure that is thin at one end is not cut in the middle of its bounding box.

NII.split_label_at_center_of_mass(labels, axis, offset) cuts at the rounded center of mass along
axis and offsets the labels on the axis side of the plane.

eth = seg.extract_label([7, 8, 15, 16], keep_label=True)
eth = eth.split_label_at_cumulative_volume_fraction([7, 8, 15, 16], "P", 1 / 3, 100)  # posterior third
eth = eth.split_label_at_center_of_mass([7, 15], "R", 200)                            # right half of the front

Changes from the source implementation

  • The axis is an anatomical direction resolved against orientation, so the reorient round-trip the
    original did (and the reorient back at the end) is gone. A raw array axis int also works.
  • The center-of-mass rounding happens in the anatomical frame, so the split is identical whichever
    orientation the image is stored in. Rounding in the array frame shifted it by one slice when the
    center of mass landed exactly on a voxel center.
  • The offset is applied through a mask instead of arr[slab] += offset followed by
    arr[arr == offset] = 0, which silently deletes any label equal to the offset. The dtype is
    promoted when the offset would overflow it.
  • fraction=0 yields an empty slab. The original had no such case: its loop left cutoff_slice as
    None when the threshold was never reached and then crashed on an undefined variable.
  • Labels absent from the mask are a no-op instead of a KeyError.

Tests

12 tests in unit_tests/test_nii_extended.py, including orientation invariance for both methods and
a pipeline test that composes them back into the original ethmoid split — the result is
voxel-identical to split_ethmoid.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GFZf44LHBB6N5jaf6YFzhx

…bel_at_center_of_mass

Two reusable label-splitting kernels lifted out of paraside's split_ethmoid,
which hard-coded the ethmoid label ids (7/8/15/16) and offsets (+100/+200)
around otherwise generic logic.

split_label_at_cumulative_volume_fraction walks slices inwards from the
axis-most end of a mask, summing voxels until a given fraction of the total
volume is covered, and adds an offset to the labels of that slab. Note this is
a volume fraction, not an extent fraction, so a structure that is thin at one
end is not cut in the middle of its bounding box.

split_label_at_center_of_mass cuts at the rounded center of mass along an axis
and offsets the labels on the axis side of the plane.

Changes from the source implementation:
- the axis is an anatomical direction resolved against `orientation`, so the
  reorient round-trip the original did (and the reorient back at the end) is
  gone, and either method can also take a raw array axis as an int
- the center-of-mass rounding happens in the anatomical frame, so the split is
  identical whichever orientation the image is stored in; rounding in the array
  frame shifted it by a slice when the center of mass landed on a voxel center
- the offset is applied via a mask instead of `arr[slab] += offset` followed by
  `arr[arr == offset] = 0`, which silently breaks for any label equal to the
  offset, and the dtype is promoted when the offset would overflow it
- fraction 0 now yields an empty slab; the original had no such case and its
  loop left `cutoff_slice` as None when the threshold was never reached, which
  then crashed on an undefined variable
- labels not present in the mask are a no-op instead of a KeyError

A test composes the two into the original ethmoid pipeline; the result is
voxel-identical to split_ethmoid.

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 59217fe vs head 59217fe · 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_save 11.33 ±0.17 11.97 ±0.51 +5.6% 0.050
poi_calc_centroids_nocrop 4.19 ±0.30 4.00 ±0.23 -4.6% 0.576
nii_load_img 10.51 ±0.13 10.96 ±0.13 +4.3% 0.000
nii_fill_holes 4.42 ±0.10 4.35 ±0.06 -1.6% 0.303
poi_calc_poi_from_subreg_vert 12.36 ±0.09 12.50 ±0.10 +1.2% 0.068
… 31 more measurements
Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_erode_msk 6.00 ±0.05 6.06 ±0.07 +1.0% 0.061
nii_rescale 39.71 ±0.18 39.94 ±0.22 +0.6% 0.233
nii_filter_connected_components 4.12 ±0.04 4.14 ±0.08 +0.4% 0.394
nii_dilate_msk 121.45 ±0.30 121.10 ±0.35 -0.3% 0.216
nii_rescale_seg 3.18 ±0.06 3.19 ±0.03 +0.3% 0.339
nii_resample_from_to 41.95 ±0.63 41.92 ±0.36 -0.1% 0.459
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 0.03 ±0.00 0.06 ±0.01 +90.9% (noise) 0.000
poi_rescale 0.16 ±0.02 0.22 ±0.01 +41.4% (noise) 0.002
poi_reorient 0.30 ±0.03 0.39 ±0.04 +29.2% (noise) 0.011
poi_to_global 0.14 ±0.02 0.18 ±0.03 +27.2% (noise) 0.097
nii_extract_label 0.41 ±0.03 0.33 ±0.06 -18.9% (noise) 0.085
poi_local_to_global_arr 0.26 ±0.01 0.31 ±0.02 +18.2% (noise) 0.010
nii_load_seg 2.51 ±0.09 2.90 ±0.06 +15.4% (noise) 0.001
poi_resample_from_to 0.56 ±0.03 0.63 ±0.06 +13.0% (noise) 0.061
nii_set_dtype 0.47 ±0.15 0.52 ±0.02 +11.1% (noise) 0.830
nii_apply_crop 0.60 ±0.05 0.66 ±0.05 +10.5% (noise) 0.333
poi_map_labels 0.13 ±0.01 0.14 ±0.02 +7.9% (noise) 0.157
nii_unique 0.67 ±0.02 0.62 ±0.06 -6.8% (noise) 0.727
nii_reorient 0.80 ±0.11 0.85 ±0.04 +6.5% (noise) 0.281
poi_calc_centroids 2.27 ±0.02 2.42 ±0.07 +6.3% (noise) 0.013
nii_pad_to 0.64 ±0.08 0.61 ±0.07 -5.1% (noise) 0.870
nii_volumes 1.85 ±0.04 1.95 ±0.04 +5.1% (noise) 0.002
nii_center_of_masses 1.74 ±0.05 1.80 ±0.01 +3.3% (noise) 0.020
nii_get_connected_components 2.09 ±0.05 2.15 ±0.10 +3.1% (noise) 0.241
nii_compute_crop 0.33 ±0.03 0.32 ±0.01 -2.6% (noise) 0.343
nii_map_labels 0.95 ±0.03 0.93 ±0.04 -1.6% (noise) 0.198
poi_save 0.39 ±0.02 0.40 ±0.02 +1.2% (noise) 0.352
poi_load 0.89 ±0.02 0.88 ±0.02 -1.2% (noise) 0.512

ct_2d — shape (73, 47, 1)

Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_resample_from_to 7.55 ±0.25 7.35 ±0.10 -2.6% 0.130
nii_rescale 5.37 ±0.24 5.24 ±0.13 -2.5% 0.468
nii_dilate_msk 14.30 ±0.03 14.38 ±0.07 +0.6% 0.038
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% —
nii_center_of_masses 0.21 ±0.01 0.23 ±0.02 +12.7% (noise) 0.047
nii_volumes 0.27 ±0.02 0.30 ±0.01 +11.1% (noise) 0.018
nii_rescale_seg 0.86 ±0.18 0.77 ±0.02 -9.6% (noise) 0.218
nii_map_labels 0.47 ±0.02 0.51 ±0.01 +8.8% (noise) 0.004
poi_calc_centroids 0.90 ±0.05 0.97 ±0.03 +7.9% (noise) 0.014
poi_calc_centroids_nocrop 1.09 ±0.03 1.18 ±0.03 +7.4% (noise) 0.004
nii_extract_label 0.40 ±0.04 0.42 ±0.03 +7.0% (noise) 0.199
nii_fill_holes 0.80 ±0.03 0.86 ±0.01 +6.7% (noise) 0.052
nii_apply_crop 0.68 ±0.03 0.72 ±0.02 +6.1% (noise) 0.026
poi_save 0.47 ±0.02 0.50 ±0.04 +5.3% (noise) 0.067
poi_resample_from_to 0.76 ±0.04 0.72 ±0.03 -5.3% (noise) 0.048
poi_to_global 0.21 ±0.01 0.22 ±0.01 +5.1% (noise) 0.027
nii_erode_msk 0.95 ±0.03 1.00 ±0.02 +5.1% (noise) 0.023
nii_pad_to 0.55 ±0.02 0.57 ±0.03 +5.0% (noise) 0.084
nii_get_connected_components 0.62 ±0.04 0.65 ±0.02 +4.9% (noise) 0.079
nii_get_array 0.02 ±0.00 0.02 ±0.00 -4.3% (noise) 0.192
poi_map_labels 0.18 ±0.01 0.19 ±0.01 +4.0% (noise) 0.101
nii_unique 0.11 ±0.00 0.12 ±0.00 +4.0% (noise) 0.011
nii_set_dtype 0.41 ±0.02 0.39 ±0.01 -3.4% (noise) 0.517
poi_local_to_global_arr 0.32 ±0.02 0.33 ±0.01 +3.1% (noise) 0.454
nii_compute_crop 0.15 ±0.01 0.15 ±0.00 -2.7% (noise) 0.113
nii_filter_connected_components 0.81 ±0.10 0.83 ±0.02 +2.5% (noise) 0.916
nii_load_seg 1.62 ±0.08 1.65 ±0.03 +1.9% (noise) 0.716
nii_save 1.36 ±0.12 1.34 ±0.08 -1.4% (noise) 0.924
nii_load_img 1.44 ±0.04 1.46 ±0.07 +1.4% (noise) 0.405
nii_reorient 0.82 ±0.03 0.83 ±0.02 +0.8% (noise) 0.931
poi_reorient 0.44 ±0.03 0.43 ±0.01 -0.7% (noise) 0.496
poi_rescale 0.24 ±0.02 0.24 ±0.00 -0.1% (noise) 0.757
poi_load 1.02 ±0.03 1.02 ±0.03 -0.0% (noise) 0.691

mri_3d — shape (68, 52, 67)

Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_rescale 37.98 ±0.28 37.07 ±0.22 -2.4% 0.002
nii_rescale_seg 3.12 ±0.05 3.06 ±0.03 -2.0% 0.048
nii_resample_from_to 39.84 ±0.19 39.32 ±0.25 -1.3% 0.003
nii_load_img 8.62 ±0.10 8.52 ±0.06 -1.2% 0.036
nii_save 9.27 ±0.07 9.17 ±0.12 -1.2% 0.574
… 31 more measurements
Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
poi_calc_centroids_nocrop 8.41 ±0.31 8.50 ±0.09 +1.1% 0.304
nii_filter_connected_components 4.61 ±0.05 4.65 ±0.06 +0.8% 0.226
poi_calc_poi_from_subreg_vert 11.71 ±0.17 11.63 ±0.12 -0.7% 0.875
nii_dilate_msk 158.33 ±0.49 157.53 ±1.34 -0.5% 0.583
nii_erode_msk 7.70 ±0.15 7.73 ±0.10 +0.3% 0.471
nii_fill_holes 5.34 ±0.07 5.34 ±0.10 +0.0% 0.759
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% —
nii_apply_crop 0.76 ±0.03 0.70 ±0.04 -7.7% (noise) 0.009
nii_get_array 0.05 ±0.01 0.05 ±0.00 -6.6% (noise) 0.305
poi_save 0.52 ±0.02 0.55 ±0.03 +5.6% (noise) 0.080
poi_reorient 0.48 ±0.02 0.46 ±0.03 -4.7% (noise) 0.145
poi_map_labels 0.22 ±0.01 0.23 ±0.02 +3.8% (noise) 0.258
poi_local_to_global_arr 0.33 ±0.01 0.32 ±0.01 -3.6% (noise) 0.116
nii_unique 0.66 ±0.02 0.64 ±0.01 -3.0% (noise) 0.086
poi_calc_centroids 2.73 ±0.02 2.81 ±0.05 +2.6% (noise) 0.025
poi_rescale 0.27 ±0.00 0.27 ±0.01 -2.5% (noise) 0.069
nii_compute_crop 0.33 ±0.02 0.32 ±0.01 -2.2% (noise) 0.394
nii_get_connected_components 2.16 ±0.02 2.21 ±0.04 +2.0% (noise) 0.123
poi_resample_from_to 0.76 ±0.02 0.75 ±0.03 -1.7% (noise) 0.423
nii_reorient 0.85 ±0.04 0.86 ±0.02 +1.3% (noise) 0.681
poi_load 2.19 ±0.07 2.21 ±0.06 +0.9% (noise) 0.878
nii_center_of_masses 1.96 ±0.03 1.97 ±0.01 +0.6% (noise) 0.951
nii_set_dtype 0.49 ±0.03 0.49 ±0.03 -0.5% (noise) 0.540
nii_map_labels 0.97 ±0.02 0.97 ±0.02 -0.4% (noise) 0.572
nii_extract_label 0.43 ±0.03 0.43 ±0.01 +0.3% (noise) 0.676
nii_pad_to 0.70 ±0.04 0.70 ±0.02 +0.3% (noise) 0.733
poi_to_global 0.25 ±0.01 0.25 ±0.01 +0.2% (noise) 0.364
nii_load_seg 2.77 ±0.08 2.77 ±0.09 -0.2% (noise) 0.860
nii_volumes 1.93 ±0.03 1.93 ±0.02 -0.2% (noise) 0.754

mri_2d — shape (68, 52, 1)

Measurement baseline ms (median ±½·range) head ms (median ±½·range) Δ % p
nii_rescale 5.37 ±0.06 5.25 ±0.02 -2.3% 0.004
nii_resample_from_to 7.55 ±0.12 7.41 ±0.10 -1.9% 0.170
nii_dilate_msk 19.07 ±0.15 19.01 ±0.13 -0.3% 0.257
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_set_dtype 0.41 ±0.02 0.36 ±0.03 -12.5% (noise) 0.099
nii_get_array 0.02 ±0.00 0.02 ±0.00 +10.5% (noise) 0.818
nii_map_labels 0.45 ±0.03 0.49 ±0.03 +8.8% (noise) 0.342
nii_apply_crop 0.68 ±0.02 0.64 ±0.02 -5.3% (noise) 0.036
nii_reorient 0.85 ±0.03 0.81 ±0.06 -4.6% (noise) 0.621
nii_pad_to 0.54 ±0.03 0.52 ±0.01 -4.5% (noise) 0.106
nii_erode_msk 1.30 ±0.04 1.25 ±0.04 -4.5% (noise) 0.389
nii_filter_connected_components 0.86 ±0.02 0.82 ±0.03 -4.2% (noise) 0.195
poi_map_labels 0.22 ±0.01 0.21 ±0.03 -3.5% (noise) 0.515
nii_compute_crop 0.14 ±0.01 0.14 ±0.00 -3.3% (noise) 0.032
poi_save 0.52 ±0.03 0.50 ±0.02 -3.1% (noise) 0.349
poi_calc_centroids_nocrop 1.44 ±0.07 1.40 ±0.03 -2.8% (noise) 0.582
poi_load 2.00 ±0.02 1.95 ±0.04 -2.6% (noise) 0.020
nii_volumes 0.45 ±0.02 0.46 ±0.01 +2.3% (noise) 0.817
poi_rescale 0.26 ±0.02 0.26 ±0.00 -2.2% (noise) 0.170
nii_fill_holes 1.09 ±0.07 1.06 ±0.02 -2.1% (noise) 0.180
poi_local_to_global_arr 0.33 ±0.01 0.32 ±0.02 -2.0% (noise) 0.596
poi_to_global 0.24 ±0.01 0.25 ±0.01 +1.8% (noise) 0.381
nii_unique 0.12 ±0.01 0.12 ±0.01 +1.5% (noise) 0.495
nii_rescale_seg 0.76 ±0.04 0.75 ±0.03 -1.3% (noise) 0.743
poi_calc_centroids 1.14 ±0.03 1.15 ±0.08 +0.6% (noise) 0.511
poi_resample_from_to 0.77 ±0.04 0.77 ±0.02 -0.5% (noise) 0.531
nii_center_of_masses 0.40 ±0.01 0.40 ±0.01 +0.5% (noise) 0.133
nii_load_seg 1.60 ±0.06 1.60 ±0.05 -0.4% (noise) 0.755
nii_get_connected_components 0.61 ±0.04 0.61 ±0.02 -0.4% (noise) 0.929
nii_extract_label 0.41 ±0.01 0.41 ±0.05 -0.3% (noise) 0.546
nii_save 1.31 ±0.04 1.31 ±0.05 -0.1% (noise) 0.578
nii_load_img 1.45 ±0.05 1.45 ±0.05 -0.1% (noise) 0.528
poi_reorient 0.44 ±0.03 0.44 ±0.02 +0.0% (noise) 0.684

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 59217fe vs head 59217fe · 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.23 ±0.00 5.28 ±0.00 +0.8% —
nii_reorient 5.86 ±0.00 5.91 ±0.00 +0.7% —
nii_rescale 6.12 ±0.00 6.17 ±0.00 +0.7% —
nii_resample_from_to 6.25 ±0.00 6.29 ±0.00 +0.7% —
nii_erode_msk 5.93 ±0.00 5.92 ±0.00 -0.2% —
… 31 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
poi_to_global 3.08 ±0.00 3.08 ±0.00 +0.1% —
nii_center_of_masses 3.27 ±0.00 3.27 ±0.00 +0.1% —
nii_volumes 3.52 ±0.00 3.52 ±0.00 +0.1% —
nii_save 3.70 ±0.00 3.71 ±0.00 +0.1% —
poi_reorient 3.83 ±0.00 3.83 ±0.00 +0.1% —
nii_set_dtype 5.24 ±0.00 5.24 ±0.00 +0.1% —
nii_extract_label 5.36 ±0.00 5.37 ±0.00 +0.1% —
nii_pad_to 5.42 ±0.00 5.43 ±0.00 +0.1% —
nii_map_labels 5.49 ±0.00 5.49 ±0.00 +0.1% —
nii_apply_crop 5.86 ±0.00 5.86 ±0.00 +0.1% —
poi_calc_centroids_nocrop 5.92 ±0.00 5.93 ±0.00 +0.1% —
nii_dilate_msk 5.93 ±0.00 5.93 ±0.00 +0.1% —
nii_rescale_seg 5.94 ±0.00 5.94 ±0.00 +0.1% —
poi_calc_centroids 6.05 ±0.00 6.05 ±0.00 +0.1% —
nii_fill_holes 6.28 ±0.00 6.28 ±0.00 +0.1% —
nii_get_connected_components 6.61 ±0.00 6.62 ±0.00 +0.1% —
nii_filter_connected_components 6.86 ±0.00 6.87 ±0.00 +0.1% —
poi_calc_poi_from_subreg_vert 7.11 ±0.00 7.11 ±0.00 -0.1% 0.016
nii_load_img 3.56 ±0.00 3.56 ±0.00 +0.0% —
nii_load_seg 6.00 ±0.00 6.00 ±0.00 +0.0% —
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_save 1.39 ±0.00 1.40 ±0.00 +0.3% (noise) —
poi_load 1.61 ±0.00 1.61 ±0.00 +0.2% (noise) —
nii_get_array 1.64 ±0.00 1.65 ±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) —
nii_compute_crop 2.89 ±0.00 2.90 ±0.00 +0.1% (noise) —
poi_local_to_global_arr 2.95 ±0.00 2.96 ±0.00 +0.1% (noise) —
nii_unique 2.96 ±0.00 2.96 ±0.00 +0.1% (noise) —

ct_2d — shape (73, 47, 1)

Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
poi_resample_from_to 5.17 ±0.00 5.21 ±0.00 +0.8% —
nii_reorient 5.80 ±0.00 5.84 ±0.00 +0.7% —
nii_rescale 6.06 ±0.00 6.11 ±0.00 +0.7% —
nii_resample_from_to 6.19 ±0.00 6.23 ±0.00 +0.7% —
nii_erode_msk 5.87 ±0.00 5.86 ±0.00 -0.2% —
… 30 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
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% —
nii_set_dtype 5.18 ±0.00 5.18 ±0.00 +0.1% —
nii_extract_label 5.30 ±0.00 5.30 ±0.00 +0.1% —
nii_pad_to 5.36 ±0.00 5.36 ±0.00 +0.1% —
nii_map_labels 5.43 ±0.00 5.43 ±0.00 +0.1% —
nii_apply_crop 5.80 ±0.00 5.80 ±0.00 +0.1% —
nii_dilate_msk 5.86 ±0.00 5.87 ±0.00 +0.1% —
nii_rescale_seg 5.88 ±0.00 5.88 ±0.00 +0.1% —
poi_calc_centroids_nocrop 5.92 ±0.00 5.93 ±0.00 +0.1% —
poi_calc_centroids 5.99 ±0.00 5.99 ±0.00 +0.1% —
nii_fill_holes 6.21 ±0.00 6.22 ±0.00 +0.1% —
nii_get_connected_components 6.55 ±0.00 6.55 ±0.00 +0.1% —
nii_filter_connected_components 6.80 ±0.00 6.80 ±0.00 +0.1% —
nii_load_img 3.50 ±0.00 3.50 ±0.00 +0.0% —
nii_load_seg 5.94 ±0.00 5.94 ±0.00 +0.0% —
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.17 ±0.00 5.21 ±0.00 +0.8% —
nii_reorient 5.80 ±0.00 5.84 ±0.00 +0.7% —
nii_rescale 6.06 ±0.00 6.11 ±0.00 +0.7% —
nii_resample_from_to 6.19 ±0.00 6.23 ±0.00 +0.7% —
nii_erode_msk 5.87 ±0.00 5.86 ±0.00 -0.2% —
… 31 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
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% —
nii_set_dtype 5.24 ±0.00 5.24 ±0.00 +0.1% —
nii_extract_label 5.30 ±0.00 5.30 ±0.00 +0.1% —
nii_pad_to 5.36 ±0.00 5.36 ±0.00 +0.1% —
nii_map_labels 5.43 ±0.00 5.43 ±0.00 +0.1% —
nii_apply_crop 5.80 ±0.00 5.80 ±0.00 +0.1% —
poi_calc_centroids_nocrop 5.86 ±0.00 5.86 ±0.00 +0.1% —
nii_dilate_msk 5.86 ±0.00 5.87 ±0.00 +0.1% —
nii_rescale_seg 5.88 ±0.00 5.88 ±0.00 +0.1% —
poi_calc_centroids 5.99 ±0.00 5.99 ±0.00 +0.1% —
nii_fill_holes 6.21 ±0.00 6.22 ±0.00 +0.1% —
nii_get_connected_components 6.55 ±0.00 6.55 ±0.00 +0.1% —
nii_filter_connected_components 6.80 ±0.00 6.80 ±0.00 +0.1% —
poi_calc_poi_from_subreg_vert 7.11 ±0.00 7.11 ±0.00 +0.1% —
nii_load_img 3.56 ±0.00 3.56 ±0.00 +0.0% —
nii_load_seg 5.94 ±0.00 5.94 ±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.17 ±0.00 5.21 ±0.00 +0.8% —
nii_reorient 5.80 ±0.00 5.84 ±0.00 +0.7% —
nii_rescale 6.06 ±0.00 6.11 ±0.00 +0.7% —
nii_resample_from_to 6.19 ±0.00 6.23 ±0.00 +0.7% —
nii_erode_msk 5.87 ±0.00 5.86 ±0.00 -0.2% —
… 30 more measurements
Measurement baseline MiB (median ±½·range) head MiB (median ±½·range) Δ % p
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% —
nii_set_dtype 5.24 ±0.00 5.24 ±0.00 +0.1% —
nii_extract_label 5.30 ±0.00 5.30 ±0.00 +0.1% —
nii_pad_to 5.36 ±0.00 5.36 ±0.00 +0.1% —
nii_map_labels 5.43 ±0.00 5.43 ±0.00 +0.1% —
nii_apply_crop 5.80 ±0.00 5.80 ±0.00 +0.1% —
nii_dilate_msk 5.86 ±0.00 5.87 ±0.00 +0.1% —
nii_rescale_seg 5.88 ±0.00 5.88 ±0.00 +0.1% —
poi_calc_centroids_nocrop 5.92 ±0.00 5.93 ±0.00 +0.1% —
poi_calc_centroids 5.99 ±0.00 5.99 ±0.00 +0.1% —
nii_fill_holes 6.21 ±0.00 6.22 ±0.00 +0.1% —
nii_get_connected_components 6.55 ±0.00 6.55 ±0.00 +0.1% —
nii_filter_connected_components 6.80 ±0.00 6.80 ±0.00 +0.1% —
nii_load_img 3.56 ±0.00 3.56 ±0.00 +0.0% —
nii_load_seg 5.94 ±0.00 5.94 ±0.00 +0.0% —
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

Copy link
Copy Markdown
Collaborator

Suggestion: partition_segmentation_by_volume
partition_segmentation_by_cms

@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.

Rename and approved

Hendrik-code and others added 3 commits October 12, 2026 12:56
split_label_at_cumulative_volume_fraction -> partition_segmentation_by_volume
split_label_at_center_of_mass -> partition_segmentation_by_center_of_mass

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The CI linter installs the latest ruff, which now flags the unaliased
import; the finding predates this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Hendrik-code
Hendrik-code merged commit a044621 into main Oct 12, 2026
6 checks passed
@Hendrik-code
Hendrik-code deleted the feat/nii-split-label-at branch October 12, 2026 13:23
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