Description:
Expected behavior: every label returned when enforce_connectivity=True should refer to a single connected component.
Actual behavior: a small (below the minimum size) component can be assigned the same label id as a different component in the volume which it is not connected to.
Way to reproduce:
import numpy as np
from scipy import ndimage as ndi
from scipy.spatial.distance import cdist
from skimage.segmentation import slic
CONNECTIVITY_6 = ndi.generate_binary_structure(3, 1)
def connected_pieces(label_mask):
labeled, n_pieces = ndi.label(label_mask, structure=CONNECTIVITY_6)
return [np.argwhere(labeled == i) for i in range(1, n_pieces + 1)]
# Volume + mask with several small excluded ("below threshold") pockets.
shape = (24, 24, 24)
rng = np.random.default_rng(27)
volume = rng.integers(0, 255, size=shape + (3,)).astype(np.float64)
volume = ndi.uniform_filter(volume, size=(3, 3, 3, 1))
mask_rng = np.random.default_rng(27 + 1000)
mask = np.ones(shape, dtype=bool)
for _ in range(6):
z, y, x = (mask_rng.integers(0, shape[i] - 2) for i in range(3))
mask[z:z+2, y:y+2, x:x+2] = False
start_label = 1
segments = slic(
volume, mask=mask, n_segments=80, compactness=5,
enforce_connectivity=True, min_size_factor=0.3, max_size_factor=3,
start_label=start_label, channel_axis=-1,
)
bg_label = start_label - 1
for lbl in np.unique(segments):
if lbl == bg_label:
continue
pieces = connected_pieces(segments == lbl)
if len(pieces) > 1:
dist = min(
cdist(pieces[i], pieces[j]).min()
for i in range(len(pieces))
for j in range(i + 1, len(pieces))
)
sizes = [len(p) for p in pieces]
print(f"label {lbl}: {len(pieces)} disconnected pieces, sizes={sizes}, "
f"min distance between pieces={dist:.2f}")
Output:
label 28: 2 disconnected pieces, sizes=[2, 358], min distance between pieces=2.00
This means that two non-connected components were both assigned the label 28.
Version information:
3.11.16 (main, Aug 12 2026, 23:03:19) [Clang 21.0.0 (clang-2100.1.1.101)]
macOS-26.6.2-arm64-arm-64bit
scikit-image version: 0.26.0
numpy version: 2.4.6
Description:
Expected behavior: every label returned when
enforce_connectivity=Trueshould refer to a single connected component.Actual behavior: a small (below the minimum size) component can be assigned the same label id as a different component in the volume which it is not connected to.
Way to reproduce:
Output:
This means that two non-connected components were both assigned the label
28.Version information: