Skip to content

Commit b70c121

Browse files
Add test for segmentation table
1 parent a4d601c commit b70c121

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

flamingo_tools/measurements.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from tqdm import tqdm
1010

1111
from .file_utils import read_image_data
12-
from .segmentation.postprocessing import _compute_table
12+
from .segmentation.postprocessing import compute_table_on_the_fly
1313

1414

1515
def _measure_volume_and_surface(mask, resolution):
@@ -45,7 +45,7 @@ def compute_object_measures_impl(
4545
table: The segmentation table. Will be computed on the fly if it is not given.
4646
"""
4747
if table is None:
48-
table = _compute_table(segmentation, resolution)
48+
table = compute_table_on_the_fly(segmentation, resolution=resolution)
4949

5050
def intensity_measures(seg_id):
5151
# Get the bounding box.

flamingo_tools/segmentation/postprocessing.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ def neighbors_in_radius(table: pd.DataFrame, radius: float = 15) -> np.ndarray:
115115
#
116116

117117

118-
def _compute_table(segmentation, resolution):
118+
def compute_table_on_the_fly(segmentation: np.typing.ArrayLike, resolution: float) -> pd.DataFrame:
119+
"""
120+
"""
119121
props = measure.regionprops(segmentation)
120122
label_ids = np.array([prop.label for prop in props])
121123
coordinates = np.array([prop.centroid for prop in props]).astype("float32")
@@ -171,10 +173,9 @@ def filter_segmentation(
171173
n_ids
172174
n_ids_filtered
173175
"""
174-
# Compute the table on the fly.
175-
# NOTE: this currently doesn't work for large segmentations.
176+
# Compute the table on the fly. This doesn't work for large segmentations.
176177
if table is None:
177-
table = _compute_table(segmentation, resolution=resolution)
178+
table = compute_table_on_the_fly(segmentation, resolution=resolution)
178179
n_ids = len(table)
179180

180181
# First apply the size filter.

flamingo_tools/test_data.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@
66
from skimage.data import binary_blobs, cells3d
77
from skimage.measure import label
88

9-
from .segmentation.postprocessing import _compute_table
9+
from .segmentation.postprocessing import compute_table_on_the_fly
1010

1111
SEGMENTATION_URL = "https://owncloud.gwdg.de/index.php/s/kwoGRYiJRRrswgw/download"
1212

1313

1414
def get_test_volume_and_segmentation(folder: str) -> Tuple[str, str, str]:
15+
"""Download a small volume with nuclei and corresponding segmentation.
16+
17+
Args:
18+
folder:
19+
20+
Returns:
21+
"""
1522
os.makedirs(folder, exist_ok=True)
1623

1724
segmentation_path = os.path.join(folder, "segmentation.tif")
@@ -29,7 +36,7 @@ def get_test_volume_and_segmentation(folder: str) -> Tuple[str, str, str]:
2936
imageio.imwrite(image_path, nuclei)
3037

3138
table_path = os.path.join(folder, "default.tsv")
32-
table = _compute_table(segmentation, resolution=0.38)
39+
table = compute_table_on_the_fly(segmentation, resolution=0.38)
3340
table.to_csv(table_path, sep="\t", index=False)
3441

3542
return image_path, segmentation_path, table_path
@@ -51,7 +58,7 @@ def create_image_data_and_segmentation(folder: str, size: int = 256) -> Tuple[st
5158
imageio.imwrite(segmentation_path, seg)
5259

5360
table_path = os.path.join(folder, "default.tsv")
54-
table = _compute_table(seg, resolution=0.38)
61+
table = compute_table_on_the_fly(seg, resolution=0.38)
5562
table.to_csv(table_path, sep="\t", index=False)
5663

5764
return image_path, segmentation_path, table_path

test/test_segmentation/test_postprocessing.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
import tempfile
33
import unittest
44

5+
import imageio.v3 as imageio
6+
import numpy as np
7+
import pandas as pd
58
from elf.io import open_file
69
from skimage.data import binary_blobs
7-
from skimage.measure import label
10+
from skimage.measure import label, regionprops_table
811

912

1013
class TestPostprocessing(unittest.TestCase):
@@ -44,6 +47,32 @@ def test_neighbors_in_radius(self):
4447

4548
self._test_postprocessing(neighbors_in_radius, threshold=5)
4649

50+
def test_compute_table_on_the_fly(self):
51+
from flamingo_tools.segmentation.postprocessing import compute_table_on_the_fly
52+
from flamingo_tools.test_data import get_test_volume_and_segmentation
53+
54+
with tempfile.TemporaryDirectory() as tmp_dir:
55+
_, seg_path, _ = get_test_volume_and_segmentation(tmp_dir)
56+
segmentation = imageio.imread(seg_path)
57+
58+
resolution = 0.38
59+
table = compute_table_on_the_fly(segmentation, resolution=resolution)
60+
61+
properties = ("label", "bbox", "centroid")
62+
expected_table = regionprops_table(segmentation, properties=properties)
63+
expected_table = pd.DataFrame(expected_table)
64+
65+
for (col, col_exp) in [
66+
("label_id", "label"),
67+
("anchor_x", "centroid-2"), ("anchor_y", "centroid-1"), ("anchor_z", "centroid-0"),
68+
("bb_min_x", "bbox-2"), ("bb_min_y", "bbox-1"), ("bb_min_z", "bbox-0"),
69+
("bb_max_x", "bbox-5"), ("bb_max_y", "bbox-4"), ("bb_max_z", "bbox-3"),
70+
]:
71+
values = table[col].values
72+
if col != "label_id":
73+
values /= resolution
74+
self.assertTrue(np.allclose(values, expected_table[col_exp].values))
75+
4776

4877
if __name__ == "__main__":
4978
unittest.main()

0 commit comments

Comments
 (0)