Skip to content

Commit 16b13a4

Browse files
authored
Refactor HoVerNet post-processing (#5618)
Fixes #5616 Fixes #5617 ### Description A few sentences describing the changes proposed in this pull request. ### Types of changes <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [x] Breaking change (fix or new feature that would cause existing functionality to change). - [x] New tests added to cover the changes. - [x] Integration tests passed locally by running `./runtests.sh -f -u --net --coverage`. - [x] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. - [x] In-line docstrings updated. - [x] Documentation updated, tested `make html` command in the `docs/` folder. Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com>
1 parent aef2ecc commit 16b13a4

19 files changed

Lines changed: 725 additions & 533 deletions

docs/source/apps.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ Applications
155155
:members:
156156
.. autoclass:: HoVerNetNuclearTypePostProcessing
157157
:members:
158+
.. autoclass:: HoVerNetInstanceMapPostProcessing
159+
:members:
158160

159161
.. automodule:: monai.apps.pathology.transforms.post.dictionary
160162
.. autoclass:: GenerateSuccinctContourd
@@ -175,6 +177,8 @@ Applications
175177
:members:
176178
.. autoclass:: GenerateWatershedMarkersd
177179
:members:
180+
.. autoclass:: HoVerNetInstanceMapPostProcessingd
181+
:members:
178182
.. autoclass:: HoVerNetNuclearTypePostProcessingd
179183
:members:
180184

monai/apps/pathology/transforms/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
GenerateSuccinctContour,
1919
GenerateWatershedMarkers,
2020
GenerateWatershedMask,
21+
HoVerNetInstanceMapPostProcessing,
2122
HoVerNetNuclearTypePostProcessing,
2223
Watershed,
2324
)
@@ -46,6 +47,9 @@
4647
GenerateWatershedMaskD,
4748
GenerateWatershedMaskd,
4849
GenerateWatershedMaskDict,
50+
HoVerNetInstanceMapPostProcessingD,
51+
HoVerNetInstanceMapPostProcessingd,
52+
HoVerNetInstanceMapPostProcessingDict,
4953
HoVerNetNuclearTypePostProcessingD,
5054
HoVerNetNuclearTypePostProcessingd,
5155
HoVerNetNuclearTypePostProcessingDict,

monai/apps/pathology/transforms/post/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
GenerateSuccinctContour,
1919
GenerateWatershedMarkers,
2020
GenerateWatershedMask,
21+
HoVerNetInstanceMapPostProcessing,
2122
HoVerNetNuclearTypePostProcessing,
2223
Watershed,
2324
)
@@ -46,6 +47,9 @@
4647
GenerateWatershedMaskD,
4748
GenerateWatershedMaskd,
4849
GenerateWatershedMaskDict,
50+
HoVerNetInstanceMapPostProcessingD,
51+
HoVerNetInstanceMapPostProcessingd,
52+
HoVerNetInstanceMapPostProcessingDict,
4953
HoVerNetNuclearTypePostProcessingD,
5054
HoVerNetNuclearTypePostProcessingd,
5155
HoVerNetNuclearTypePostProcessingDict,

monai/apps/pathology/transforms/post/array.py

Lines changed: 298 additions & 174 deletions
Large diffs are not rendered by default.

monai/apps/pathology/transforms/post/dictionary.py

Lines changed: 169 additions & 132 deletions
Large diffs are not rendered by default.

monai/transforms/post/array.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ class RemoveSmallObjects(Transform):
360360
Data should be one-hotted.
361361
362362
Args:
363-
min_size: objects smaller than this size are removed.
363+
min_size: objects smaller than this size (in pixel) are removed.
364364
connectivity: Maximum number of orthogonal hops to consider a pixel/voxel as a neighbor.
365365
Accepted values are ranging from 1 to input.ndim. If ``None``, a full
366366
connectivity of ``input.ndim`` is used. For more details refer to linked scikit-image

tests/test_generate_distance_map.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@
2525

2626
for p in TEST_NDARRAYS:
2727
EXCEPTION_TESTS.append([{}, p(np.random.rand(2, 5, 5)), p(np.random.rand(1, 5, 5)), ValueError])
28-
2928
EXCEPTION_TESTS.append([{}, p(np.random.rand(1, 5, 5)), p(np.random.rand(2, 5, 5)), ValueError])
3029

31-
for p in TEST_NDARRAYS:
3230
TESTS.append([{}, p(np.random.rand(1, 5, 5)), p(np.random.rand(1, 5, 5)), (1, 5, 5)])
3331
TESTS.append(
3432
[{"smooth_fn": GaussianSmooth(sigma=0.4)}, p(np.random.rand(1, 5, 5)), p(np.random.rand(1, 5, 5)), (1, 5, 5)]

tests/test_generate_distance_mapd.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,26 @@
2525

2626
for p in TEST_NDARRAYS:
2727
EXCEPTION_TESTS.append(
28-
[{"keys": "mask", "border_key": "border"}, p(np.random.rand(2, 5, 5)), p(np.random.rand(1, 5, 5)), ValueError]
28+
[
29+
{"mask_key": "mask", "border_key": "border"},
30+
p(np.random.rand(2, 5, 5)),
31+
p(np.random.rand(1, 5, 5)),
32+
ValueError,
33+
]
2934
)
30-
3135
EXCEPTION_TESTS.append(
32-
[{"keys": "mask", "border_key": "border"}, p(np.random.rand(1, 5, 5)), p(np.random.rand(2, 5, 5)), ValueError]
36+
[
37+
{"mask_key": "mask", "border_key": "border"},
38+
p(np.random.rand(1, 5, 5)),
39+
p(np.random.rand(2, 5, 5)),
40+
ValueError,
41+
]
3342
)
3443

35-
for p in TEST_NDARRAYS:
36-
TESTS.append(
37-
[{"keys": "mask", "border_key": "border"}, p(np.random.rand(1, 5, 5)), p(np.random.rand(1, 5, 5)), (1, 5, 5)]
38-
)
44+
TESTS.append([{}, p(np.random.rand(1, 5, 5)), p(np.random.rand(1, 5, 5)), (1, 5, 5)])
3945
TESTS.append(
4046
[
41-
{"keys": "mask", "border_key": "border", "smooth_fn": GaussianSmooth(sigma=0.4)},
47+
{"mask_key": "mask", "border_key": "border", "smooth_fn": GaussianSmooth(sigma=0.4)},
4248
p(np.random.rand(1, 5, 5)),
4349
p(np.random.rand(1, 5, 5)),
4450
(1, 5, 5),
@@ -55,7 +61,7 @@ def test_value(self, argments, mask, border_map, exception_type):
5561
@parameterized.expand(TESTS)
5662
def test_value2(self, argments, mask, border_map, expected_shape):
5763
result = GenerateDistanceMapd(**argments)({"mask": mask, "border": border_map})
58-
self.assertEqual(result["dist"].shape, expected_shape)
64+
self.assertEqual(result["dist_map"].shape, expected_shape)
5965

6066

6167
if __name__ == "__main__":

tests/test_generate_instance_border.py

Lines changed: 9 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -23,61 +23,23 @@
2323
np.random.RandomState(123)
2424

2525
for p in TEST_NDARRAYS:
26-
EXCEPTION_TESTS.append(
27-
[
28-
{"kernel_size": 3, "remove_small_objects": False},
29-
p(np.random.rand(1, 5, 5, 5)),
30-
p(np.random.rand(2, 5, 5)),
31-
ValueError,
32-
]
33-
)
26+
EXCEPTION_TESTS.append([{"kernel_size": 3}, p(np.random.rand(1, 5, 5, 5)), p(np.random.rand(2, 5, 5)), ValueError])
27+
EXCEPTION_TESTS.append([{"kernel_size": 3}, p(np.random.rand(1, 5, 5)), p(np.random.rand(1, 5, 5)), ValueError])
28+
EXCEPTION_TESTS.append([{"kernel_size": 3}, p(np.random.rand(2, 5, 5)), p(np.random.rand(2, 5, 5)), ValueError])
3429

35-
EXCEPTION_TESTS.append(
36-
[
37-
{"kernel_size": 3, "remove_small_objects": False},
38-
p(np.random.rand(1, 5, 5)),
39-
p(np.random.rand(1, 5, 5)),
40-
ValueError,
41-
]
42-
)
43-
44-
EXCEPTION_TESTS.append(
45-
[
46-
{"kernel_size": 3, "remove_small_objects": False},
47-
p(np.random.rand(2, 5, 5)),
48-
p(np.random.rand(2, 5, 5)),
49-
ValueError,
50-
]
51-
)
52-
53-
for p in TEST_NDARRAYS:
54-
TESTS.append(
55-
[
56-
{"kernel_size": 3, "remove_small_objects": False},
57-
p(np.random.rand(1, 5, 5)),
58-
p(np.random.rand(2, 5, 5)),
59-
(1, 5, 5),
60-
]
61-
)
62-
TESTS.append(
63-
[
64-
{"kernel_size": 3, "remove_small_objects": False},
65-
p(np.random.rand(1, 5, 5)),
66-
p(np.random.rand(2, 5, 5)),
67-
(1, 5, 5),
68-
]
69-
)
30+
TESTS.append([{"kernel_size": 3}, p(np.random.rand(1, 5, 5)), p(np.random.rand(2, 5, 5)), (1, 5, 5)])
31+
TESTS.append([{"kernel_size": 3}, p(np.random.rand(1, 5, 5)), p(np.random.rand(2, 5, 5)), (1, 5, 5)])
7032

7133

7234
class TestGenerateInstanceBorder(unittest.TestCase):
7335
@parameterized.expand(EXCEPTION_TESTS)
74-
def test_value(self, argments, mask, hover_map, exception_type):
36+
def test_value(self, arguments, mask, hover_map, exception_type):
7537
with self.assertRaises(exception_type):
76-
GenerateInstanceBorder(**argments)(mask, hover_map)
38+
GenerateInstanceBorder(**arguments)(mask, hover_map)
7739

7840
@parameterized.expand(TESTS)
79-
def test_value2(self, argments, mask, hover_map, expected_shape):
80-
result = GenerateInstanceBorder(**argments)(mask, hover_map)
41+
def test_value2(self, arguments, mask, hover_map, expected_shape):
42+
result = GenerateInstanceBorder(**arguments)(mask, hover_map)
8143
self.assertEqual(result.shape, expected_shape)
8244

8345

tests/test_generate_instance_borderd.py

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,48 +24,20 @@
2424

2525
for p in TEST_NDARRAYS:
2626
EXCEPTION_TESTS.append(
27-
[
28-
{"keys": "mask", "kernel_size": 3, "remove_small_objects": True, "min_size": 10},
29-
p(np.random.rand(1, 5, 5, 5)),
30-
p(np.random.rand(2, 5, 5)),
31-
ValueError,
32-
]
27+
[{"mask_key": "mask", "kernel_size": 3}, p(np.random.rand(1, 5, 5, 5)), p(np.random.rand(2, 5, 5)), ValueError]
3328
)
34-
3529
EXCEPTION_TESTS.append(
36-
[
37-
{"keys": "mask", "kernel_size": 3, "remove_small_objects": True, "min_size": 10},
38-
p(np.random.rand(1, 5, 5)),
39-
p(np.random.rand(1, 5, 5)),
40-
ValueError,
41-
]
30+
[{"mask_key": "mask", "kernel_size": 3}, p(np.random.rand(1, 5, 5)), p(np.random.rand(1, 5, 5)), ValueError]
4231
)
43-
4432
EXCEPTION_TESTS.append(
45-
[
46-
{"keys": "mask", "kernel_size": 3, "remove_small_objects": True, "min_size": 10},
47-
p(np.random.rand(2, 5, 5)),
48-
p(np.random.rand(2, 5, 5)),
49-
ValueError,
50-
]
33+
[{"mask_key": "mask", "kernel_size": 3}, p(np.random.rand(2, 5, 5)), p(np.random.rand(2, 5, 5)), ValueError]
5134
)
5235

53-
for p in TEST_NDARRAYS:
5436
TESTS.append(
55-
[
56-
{"keys": "mask", "kernel_size": 3, "remove_small_objects": False, "min_size": 10},
57-
p(np.random.rand(1, 5, 5)),
58-
p(np.random.rand(2, 5, 5)),
59-
(1, 5, 5),
60-
]
37+
[{"mask_key": "mask", "kernel_size": 3}, p(np.random.rand(1, 5, 5)), p(np.random.rand(2, 5, 5)), (1, 5, 5)]
6138
)
6239
TESTS.append(
63-
[
64-
{"keys": "mask", "kernel_size": 3, "remove_small_objects": True, "min_size": 10},
65-
p(np.random.rand(1, 5, 5)),
66-
p(np.random.rand(2, 5, 5)),
67-
(1, 5, 5),
68-
]
40+
[{"mask_key": "mask", "kernel_size": 3}, p(np.random.rand(1, 5, 5)), p(np.random.rand(2, 5, 5)), (1, 5, 5)]
6941
)
7042

7143

0 commit comments

Comments
 (0)