Skip to content

Commit 78a00dc

Browse files
Fix LSD computation and add tests for empty labels (#2)
* add tests for empty labels (background only) * fix lsd computation for background-only label field static type checker action failure seems unrelated to this pull request
1 parent 59a9e8a commit 78a00dc

File tree

4 files changed

+41
-3
lines changed

4 files changed

+41
-3
lines changed

src/lsd_lite/lsds.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,13 @@ def get_lsds(
192192
descriptor = upsample(descriptor, df)
193193
label_descriptors.append(descriptor * (segmentation == label)[None, ...])
194194

195-
descriptors = np.sum(np.array(label_descriptors), axis=0)
196-
np.clip(descriptors, 0.0, 1.0, out=descriptors)
195+
if len(label_descriptors) == 0:
196+
# No valid labels found, return zeros with expected shape
197+
channels = 10 if dims == 3 else 6
198+
descriptors = np.zeros((channels,) + segmentation.shape, dtype=np.float32)
199+
else:
200+
descriptors = np.sum(np.array(label_descriptors), axis=0)
201+
np.clip(descriptors, 0.0, 1.0, out=descriptors)
197202

198203
return descriptors
199204

tests/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ def toy_labels() -> np.ndarray:
1717
labels[-1] = 2
1818
return labels
1919

20+
@pytest.fixture(scope="session")
21+
def empty_labels() -> np.ndarray:
22+
"""All-background (zeros) 3D volume."""
23+
labels = np.zeros((10, 10, 10), dtype=np.uint64)
24+
return labels
2025

2126
@pytest.fixture(scope="session")
2227
def real_labels() -> np.ndarray:

tests/test_affs.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
"3d_long_range": [16, 56, 56, 32, 32, 32, 32, 32, 32],
2929
}
3030

31-
3231
@pytest.mark.parametrize("nb_key", NEIGHBORHOODS.keys())
3332
@pytest.mark.parametrize("dist_func", ["equality", "equality-no-bg"])
3433
def test_real_shapes(real_labels, nb_key, dist_func):
@@ -61,3 +60,20 @@ def test_no_background_dist_func(toy_labels, nb_key):
6160
def test_real_affs_non_empty(real_labels, nb_key, dist_func):
6261
affs = get_affs(real_labels, NEIGHBORHOODS[nb_key], dist=dist_func, pad=True)
6362
assert affs.any(), f"{nb_key}{dist_func} produced all-zero affinities"
63+
64+
65+
@pytest.mark.parametrize("nb_key", NEIGHBORHOODS.keys())
66+
def test_empty_labels(empty_labels, nb_key):
67+
"""Test that get_affs handles empty (all-background) segmentations."""
68+
neigh = NEIGHBORHOODS[nb_key]
69+
70+
# With equality-no-bg, background should not produce affinities
71+
affs = get_affs(empty_labels, neigh, dist="equality-no-bg", pad=True)
72+
assert affs.shape == (len(neigh), *empty_labels.shape)
73+
assert not affs.any()
74+
75+
# With equality, background matches itself, so all True
76+
affs_eq = get_affs(empty_labels, neigh, dist="equality", pad=True)
77+
assert affs_eq.shape == (len(neigh), *empty_labels.shape)
78+
assert affs_eq.all()
79+

tests/test_lsds.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import numpy as np
2+
13
from lsd_lite import get_lsds
24

35

@@ -12,3 +14,13 @@ def test_lsds(real_labels):
1214
def test_sigmas(real_labels):
1315
for sigma in [5, 10, 15, 20]:
1416
_ = get_lsds(real_labels[0], sigma=sigma, downsample=2)
17+
18+
19+
def test_empty_labels(empty_labels):
20+
"""Test that get_lsds handles empty (all-background) segmentations."""
21+
lsds = get_lsds(empty_labels, sigma=5, downsample=1)
22+
23+
# Should return zeros with correct shape
24+
assert lsds.shape == (10,) + empty_labels.shape
25+
assert np.all(lsds == 0)
26+

0 commit comments

Comments
 (0)