Skip to content

Commit 8270658

Browse files
Added get_wsi_at_mpp tests; fixed a few bugs
1 parent 2afa6fb commit 8270658

File tree

2 files changed

+98
-14
lines changed

2 files changed

+98
-14
lines changed

monai/data/wsi_reader.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,12 @@ def _resize_to_mpp_res(self, wsi, closest_lvl, mpp_list, user_mpp: tuple):
965965
target_res_x, target_res_y = self._compute_mpp_target_res(closest_lvl, closest_lvl_dim, mpp_list, user_mpp)
966966

967967
wsi_arr = cp.array(wsi.read_region((0, 0), level=closest_lvl, size=closest_lvl_dim, num_workers=self.num_workers))
968-
closest_lvl_wsi = cucim_resize(wsi_arr, (target_res_x, target_res_y), order=1)
968+
closest_lvl_wsi = cucim_resize(
969+
wsi_arr,
970+
(target_res_x, target_res_y),
971+
order=1,
972+
preserve_range=True,
973+
anti_aliasing=False).astype(cp.uint8)
969974

970975
return closest_lvl_wsi
971976

@@ -1210,7 +1215,7 @@ def _resize_to_mpp_res(self, wsi, closest_lvl, mpp_list, user_mpp: tuple):
12101215
target_res_x, target_res_y = self._compute_mpp_target_res(closest_lvl, closest_lvl_dim, mpp_list, user_mpp)
12111216

12121217
closest_lvl_wsi = wsi.read_region((0, 0), level=closest_lvl, size=closest_lvl_dim)
1213-
closest_lvl_wsi = closest_lvl_wsi.resize((target_res_x, target_res_y), pil_image.BILINEAR)
1218+
closest_lvl_wsi = closest_lvl_wsi.resize((target_res_y, target_res_x), pil_image.BILINEAR) # row, col order
12141219

12151220
return closest_lvl_wsi
12161221

tests/utils/enums/test_wsireader.py

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,12 @@
3737
has_tiff = has_tiff and has_codec
3838

3939
TESTS_PATH = Path(__file__).parents[2]
40-
WSI_GENERIC_TIFF_KEY = "wsi_generic_tiff"
40+
WSI_GENERIC_TIFF_KEY = "wsi_generic_tiff" # TIFF image with incorrect mpp values
4141
WSI_GENERIC_TIFF_PATH = os.path.join(TESTS_PATH, "testing_data", f"temp_{WSI_GENERIC_TIFF_KEY}.tiff")
4242

43+
WSI_GENERIC_TIFF_CORRECT_MPP_KEY = "wsi_generic_tiff_corrected"
44+
WSI_GENERIC_TIFF_CORRECT_MPP_PATH = os.path.join(TESTS_PATH, "testing_data", f"temp_{WSI_GENERIC_TIFF_CORRECT_MPP_KEY}.tiff")
45+
4346
WSI_APERIO_SVS_KEY = "wsi_aperio_svs"
4447
WSI_APERIO_SVS_PATH = os.path.join(TESTS_PATH, "testing_data", f"temp_{WSI_APERIO_SVS_KEY}.svs")
4548

@@ -256,6 +259,54 @@
256259
"cpu",
257260
]
258261

262+
TEST_CASE_SVS_MPP_1 = [
263+
WSI_APERIO_SVS_PATH,
264+
{"mpp": (4.0, 4.0), "atol": 0.0, "rtol": 0.1},
265+
{"openslide": (4106, 5739, 4), "cucim": (4106, 5739, 3)},
266+
]
267+
268+
TEST_CASE_SVS_MPP_2 = [
269+
WSI_APERIO_SVS_PATH,
270+
{"mpp": (8.0, 8.0)},
271+
{"openslide": (2057, 2875, 4), "cucim": (2057, 2875, 3)},
272+
]
273+
274+
TEST_CASE_SVS_MPP_3 = [
275+
WSI_APERIO_SVS_PATH,
276+
{"mpp": (3.0, 3.0)},
277+
{"openslide": (5475, 7652, 4), "cucim": (5475, 7652, 3)},
278+
]
279+
280+
TEST_CASE_SVS_MPP_4 = [
281+
WSI_APERIO_SVS_PATH,
282+
{"mpp": (1.5, 1.5)},
283+
{"openslide": (10949, 15303, 4), "cucim": (10949, 15303, 3)},
284+
]
285+
286+
TEST_CASE_TIFF_MPP_1 = [
287+
WSI_GENERIC_TIFF_CORRECT_MPP_PATH,
288+
{"mpp": (4.0, 4.0), "atol": 0.0, "rtol": 0.1},
289+
{"openslide": (4114, 5750, 4), "cucim": (4114, 5750, 3), "tifffile": (4106, 5739, 3)},
290+
]
291+
292+
TEST_CASE_TIFF_MPP_2 = [
293+
WSI_GENERIC_TIFF_CORRECT_MPP_PATH,
294+
{"mpp": (8.0, 8.0)},
295+
{"openslide": (2057, 2875, 4), "cucim": (2057, 2875, 3), "tifffile": (2053, 2869, 3)},
296+
]
297+
298+
TEST_CASE_TIFF_MPP_3 = [
299+
WSI_GENERIC_TIFF_CORRECT_MPP_PATH,
300+
{"mpp": (3.0, 3.0)},
301+
{"openslide": (5475, 7652, 4), "cucim": (5475, 7652, 3), "tifffile": (5475, 7651, 3)},
302+
]
303+
304+
TEST_CASE_TIFF_MPP_4 = [
305+
WSI_GENERIC_TIFF_CORRECT_MPP_PATH,
306+
{"mpp": (1.5, 1.5)},
307+
{"openslide": (10949, 15303, 4), "cucim": (10949, 15303, 3), "tifffile": (10949, 15303, 3)},
308+
]
309+
259310
TEST_CASE_DEVICE_2 = [
260311
WSI_GENERIC_TIFF_PATH,
261312
{"level": 8, "dtype": torch.float32, "device": "cuda"},
@@ -407,17 +458,45 @@ class WSIReaderTests:
407458
class Tests(unittest.TestCase):
408459
backend = None
409460

410-
@parameterized.expand([TEST_CASE_WHOLE_0])
411-
def test_read_whole_image(self, file_path, level, expected_shape):
412-
reader = WSIReader(self.backend, level=level)
413-
with reader.read(file_path) as img_obj:
414-
img, meta = reader.get_data(img_obj)
415-
self.assertTupleEqual(img.shape, expected_shape)
416-
self.assertEqual(meta["backend"], self.backend)
417-
self.assertEqual(meta[WSIPatchKeys.PATH].lower(), str(os.path.abspath(file_path)).lower())
418-
self.assertEqual(meta[WSIPatchKeys.LEVEL], level)
419-
assert_allclose(meta[WSIPatchKeys.SIZE], expected_shape[1:], type_test=False)
420-
assert_allclose(meta[WSIPatchKeys.LOCATION], (0, 0), type_test=False)
461+
# @parameterized.expand([TEST_CASE_WHOLE_0])
462+
# def test_read_whole_image(self, file_path, level, expected_shape):
463+
# reader = WSIReader(self.backend, level=level)
464+
# with reader.read(file_path) as img_obj:
465+
# img, meta = reader.get_data(img_obj)
466+
# self.assertTupleEqual(img.shape, expected_shape)
467+
# self.assertEqual(meta["backend"], self.backend)
468+
# self.assertEqual(meta[WSIPatchKeys.PATH].lower(), str(os.path.abspath(file_path)).lower())
469+
# self.assertEqual(meta[WSIPatchKeys.LEVEL], level)
470+
# assert_allclose(meta[WSIPatchKeys.SIZE], expected_shape[1:], type_test=False)
471+
# assert_allclose(meta[WSIPatchKeys.LOCATION], (0, 0), type_test=False)
472+
473+
@parameterized.expand(
474+
[
475+
TEST_CASE_SVS_MPP_1,
476+
TEST_CASE_SVS_MPP_2,
477+
TEST_CASE_SVS_MPP_3,
478+
TEST_CASE_SVS_MPP_4,
479+
TEST_CASE_TIFF_MPP_1,
480+
TEST_CASE_TIFF_MPP_2,
481+
TEST_CASE_TIFF_MPP_3,
482+
TEST_CASE_TIFF_MPP_4
483+
]
484+
)
485+
def test_get_wsi_at_mpp(self, file_path, func_kwargs, expected_shape):
486+
# Tifffile backend cannot read MPP from the SVS file, so skip.
487+
if self.backend == "tifffile" and file_path == WSI_APERIO_SVS_PATH:
488+
self.skipTest("TiffFileWSIReader cannot extract MPP from SVS files.")
489+
490+
# Look up the expected shape for the current backend
491+
if self.backend not in expected_shape:
492+
self.skipTest(f"No expected shape defined for backend '{self.backend}' in this test case.")
493+
expected_shape = expected_shape[self.backend]
494+
495+
reader = WSIReader(self.backend)
496+
with reader.read(file_path) as wsi:
497+
wsi_arr = reader.get_wsi_at_mpp(wsi, **func_kwargs)
498+
499+
self.assertTupleEqual(wsi_arr.shape, expected_shape)
421500

422501
@parameterized.expand(
423502
[

0 commit comments

Comments
 (0)