Exemplo n.º 1
0
 def test_read_malformats(self, img_expected):
     if self.backend == "cucim" and (len(img_expected.shape) < 3 or img_expected.shape[2] == 1):
         # Until cuCIM addresses https://github.com/rapidsai/cucim/issues/230
         return
     reader = WSIReader(self.backend)
     file_path = os.path.join(os.path.dirname(__file__), "testing_data", "temp_tiff_image_gray.tiff")
     imwrite(file_path, img_expected, shape=img_expected.shape)
     with self.assertRaises((RuntimeError, ValueError, openslide.OpenSlideError if has_osl else ValueError)):
         with reader.read(file_path) as img_obj:
             reader.get_data(img_obj)
Exemplo n.º 2
0
 def test_read_whole_image(self, file_path, level, expected_shape):
     reader = WSIReader(self.backend, level=level)
     with reader.read(file_path) as img_obj:
         img, meta = reader.get_data(img_obj)
     self.assertTupleEqual(img.shape, expected_shape)
     self.assertEqual(meta["backend"], self.backend)
     self.assertEqual(meta["path"], str(os.path.abspath(file_path)))
     self.assertEqual(meta["patch_level"], level)
     assert_array_equal(meta["patch_size"], expected_shape[1:])
     assert_array_equal(meta["patch_location"], (0, 0))
Exemplo n.º 3
0
 def test_read_malformats(self, img_expected):
     reader = WSIReader(self.backend)
     file_path = save_gray_tiff(
         img_expected,
         os.path.join(os.path.dirname(__file__), "testing_data",
                      "temp_tiff_image_gray.tiff"))
     with self.assertRaises(
         (RuntimeError, ValueError,
          openslide.OpenSlideError if has_osl else ValueError)):
         with reader.read(file_path) as img_obj:
             reader.get_data(img_obj)
Exemplo n.º 4
0
        def test_read_rgba(self, img_expected):
            # skip for OpenSlide since not working with images without tiles
            if self.backend == "openslide":
                return
            image = {}
            reader = WSIReader(self.backend)
            for mode in ["RGB", "RGBA"]:
                file_path = save_rgba_tiff(
                    img_expected,
                    os.path.join(os.path.dirname(__file__), "testing_data", f"temp_tiff_image_{mode}.tiff"),
                    mode=mode,
                )
                with reader.read(file_path) as img_obj:
                    image[mode], _ = reader.get_data(img_obj)

            self.assertIsNone(assert_array_equal(image["RGB"], img_expected))
            self.assertIsNone(assert_array_equal(image["RGBA"], img_expected))
Exemplo n.º 5
0
    def __init__(
        self,
        data: Sequence,
        patch_size: Optional[Union[int, Tuple[int, int]]] = None,
        patch_level: Optional[int] = None,
        transform: Optional[Callable] = None,
        include_label: bool = True,
        center_location: bool = True,
        additional_meta_keys: Optional[Sequence[str]] = None,
        reader="cuCIM",
        **kwargs,
    ):
        super().__init__(data, transform)

        # Ensure patch size is a two dimensional tuple
        if patch_size is None:
            self.patch_size = None
        else:
            self.patch_size = ensure_tuple_rep(patch_size, 2)

        # Create a default level that override all levels if it is not None
        self.patch_level = patch_level
        # Set the default WSIReader's level to 0 if level is not provided
        if patch_level is None:
            patch_level = 0

        # Setup the WSI reader
        self.wsi_reader: Union[WSIReader, BaseWSIReader]
        if isinstance(reader, str):
            self.wsi_reader = WSIReader(backend=reader,
                                        level=patch_level,
                                        **kwargs)
        elif inspect.isclass(reader) and issubclass(reader, BaseWSIReader):
            self.wsi_reader = reader(level=patch_level, **kwargs)
        elif isinstance(reader, BaseWSIReader):
            self.wsi_reader = reader
        else:
            raise ValueError(f"Unsupported reader type: {reader}.")
        self.backend = self.wsi_reader.backend

        self.include_label = include_label
        self.center_location = center_location
        self.additional_meta_keys = additional_meta_keys or []

        # Initialized an empty whole slide image object dict
        self.wsi_object_dict: Dict = {}
Exemplo n.º 6
0
    def __init__(
        self,
        data: List,
        size: Optional[Union[int, Tuple[int, int]]] = None,
        level: Optional[int] = None,
        transform: Optional[Callable] = None,
        reader="cuCIM",
        **kwargs,
    ):
        super().__init__(data, transform)

        # Ensure patch size is a two dimensional tuple
        if size is None:
            self.size = None
        else:
            self.size = ensure_tuple_rep(size, 2)

        # Create a default level that override all levels if it is not None
        self.level = level
        # Set the default WSIReader's level to 0 if level is not provided
        if level is None:
            level = 0

        # Setup the WSI reader
        self.wsi_reader: Union[WSIReader, BaseWSIReader]
        self.backend = ""
        if isinstance(reader, str):
            self.backend = reader.lower()
            self.wsi_reader = WSIReader(backend=self.backend,
                                        level=level,
                                        **kwargs)
        elif inspect.isclass(reader) and issubclass(reader, BaseWSIReader):
            self.wsi_reader = reader(level=level, **kwargs)
        elif isinstance(reader, BaseWSIReader):
            self.wsi_reader = reader
        else:
            raise ValueError(f"Unsupported reader type: {reader}.")

        # Initialized an empty whole slide image object dict
        self.wsi_object_dict: Dict = {}
Exemplo n.º 7
0
 def test_read_region_multi_wsi(self, file_path, patch_info, expected_img):
     kwargs = {"name": None, "offset": None} if self.backend == "tifffile" else {}
     reader = WSIReader(self.backend, **kwargs)
     img_obj = reader.read(file_path, **kwargs)
     if self.backend == "tifffile":
         with self.assertRaises(ValueError):
             reader.get_data(img_obj, **patch_info)[0]
     else:
         # Read twice to check multiple calls
         img = reader.get_data(img_obj, **patch_info)[0]
         img2 = reader.get_data(img_obj, **patch_info)[0]
         self.assertTupleEqual(img.shape, img2.shape)
         self.assertIsNone(assert_array_equal(img, img2))
         self.assertTupleEqual(img.shape, expected_img.shape)
         self.assertIsNone(assert_array_equal(img, expected_img))
Exemplo n.º 8
0
 def test_read_region(self, file_path, kwargs, patch_info, expected_img):
     reader = WSIReader(self.backend, **kwargs)
     with reader.read(file_path) as img_obj:
         if self.backend == "tifffile":
             with self.assertRaises(ValueError):
                 reader.get_data(img_obj, **patch_info)[0]
         else:
             # Read twice to check multiple calls
             img, meta = reader.get_data(img_obj, **patch_info)
             img2 = reader.get_data(img_obj, **patch_info)[0]
             self.assertTupleEqual(img.shape, img2.shape)
             self.assertIsNone(assert_array_equal(img, img2))
             self.assertTupleEqual(img.shape, expected_img.shape)
             self.assertIsNone(assert_array_equal(img, expected_img))
             self.assertEqual(meta["backend"], self.backend)
             self.assertEqual(meta["path"], str(os.path.abspath(file_path)))
             self.assertEqual(meta["patch_level"], patch_info["level"])
             assert_array_equal(meta["patch_size"], patch_info["size"])
             assert_array_equal(meta["patch_location"], patch_info["location"])
Exemplo n.º 9
0
 def test_read_region_multi_wsi(self, file_path_list, patch_info, expected_img):
     kwargs = {"name": None, "offset": None} if self.backend == "tifffile" else {}
     reader = WSIReader(self.backend, **kwargs)
     img_obj_list = reader.read(file_path_list, **kwargs)
     if self.backend == "tifffile":
         with self.assertRaises(ValueError):
             reader.get_data(img_obj_list, **patch_info)[0]
     else:
         # Read twice to check multiple calls
         img, meta = reader.get_data(img_obj_list, **patch_info)
         img2 = reader.get_data(img_obj_list, **patch_info)[0]
         self.assertTupleEqual(img.shape, img2.shape)
         self.assertIsNone(assert_array_equal(img, img2))
         self.assertTupleEqual(img.shape, expected_img.shape)
         self.assertIsNone(assert_array_equal(img, expected_img))
         self.assertEqual(meta["backend"], self.backend)
         self.assertEqual(meta["path"][0], str(os.path.abspath(file_path_list[0])))
         self.assertEqual(meta["patch_level"][0], patch_info["level"])
         assert_array_equal(meta["patch_size"][0], expected_img.shape[1:])
         assert_array_equal(meta["patch_location"][0], patch_info["location"])
Exemplo n.º 10
0
 def test_read_whole_image(self, file_path, level, expected_shape):
     reader = WSIReader(self.backend, level=level)
     with reader.read(file_path) as img_obj:
         img = reader.get_data(img_obj)[0]
     self.assertTupleEqual(img.shape, expected_shape)
Exemplo n.º 11
0
class PatchWSIDataset(Dataset):
    """
    This dataset extracts patches from whole slide images (without loading the whole image)
    It also reads labels for each patch and provides each patch with its associated class labels.

    Args:
        data: the list of input samples including image, location, and label (see the note below for more details).
        size: the size of patch to be extracted from the whole slide image.
        level: the level at which the patches to be extracted (default to 0).
        transform: transforms to be executed on input data.
        reader: the module to be used for loading whole slide imaging,
            - if `reader` is a string, it defines the backend of `monai.data.WSIReader`. Defaults to cuCIM.
            - if `reader` is a class (inherited from `BaseWSIReader`), it is initialized and set as wsi_reader.
            - if `reader` is an instance of a a class inherited from `BaseWSIReader`, it is set as the wsi_reader.
        kwargs: additional arguments to pass to `WSIReader` or provided whole slide reader class

    Note:
        The input data has the following form as an example:

        .. code-block:: python

            [
                {"image": "path/to/image1.tiff", "location": [200, 500], "label": 0},
                {"image": "path/to/image2.tiff", "location": [100, 700], "label": 1}
            ]

    """
    def __init__(
        self,
        data: List,
        size: Optional[Union[int, Tuple[int, int]]] = None,
        level: Optional[int] = None,
        transform: Optional[Callable] = None,
        reader="cuCIM",
        **kwargs,
    ):
        super().__init__(data, transform)

        # Ensure patch size is a two dimensional tuple
        if size is None:
            self.size = None
        else:
            self.size = ensure_tuple_rep(size, 2)

        # Create a default level that override all levels if it is not None
        self.level = level
        # Set the default WSIReader's level to 0 if level is not provided
        if level is None:
            level = 0

        # Setup the WSI reader
        self.wsi_reader: Union[WSIReader, BaseWSIReader]
        self.backend = ""
        if isinstance(reader, str):
            self.backend = reader.lower()
            self.wsi_reader = WSIReader(backend=self.backend,
                                        level=level,
                                        **kwargs)
        elif inspect.isclass(reader) and issubclass(reader, BaseWSIReader):
            self.wsi_reader = reader(level=level, **kwargs)
        elif isinstance(reader, BaseWSIReader):
            self.wsi_reader = reader
        else:
            raise ValueError(f"Unsupported reader type: {reader}.")

        # Initialized an empty whole slide image object dict
        self.wsi_object_dict: Dict = {}

    def _get_wsi_object(self, sample: Dict):
        image_path = sample["image"]
        if image_path not in self.wsi_object_dict:
            self.wsi_object_dict[image_path] = self.wsi_reader.read(image_path)
        return self.wsi_object_dict[image_path]

    def _get_label(self, sample: Dict):
        return np.array(sample["label"], dtype=np.float32)

    def _get_location(self, sample: Dict):
        size = self._get_size(sample)
        return [sample["location"][i] - size[i] // 2 for i in range(len(size))]

    def _get_level(self, sample: Dict):
        if self.level is None:
            return sample.get("level", 0)
        return self.level

    def _get_size(self, sample: Dict):
        if self.size is None:
            return ensure_tuple_rep(sample.get("size"), 2)
        return self.size

    def _get_data(self, sample: Dict):
        # Don't store OpenSlide objects to avoid issues with OpenSlide internal cache
        if self.backend == "openslide":
            self.wsi_object_dict = {}
        wsi_obj = self._get_wsi_object(sample)
        location = self._get_location(sample)
        level = self._get_level(sample)
        size = self._get_size(sample)
        return self.wsi_reader.get_data(wsi=wsi_obj,
                                        location=location,
                                        size=size,
                                        level=level)

    def _transform(self, index: int):
        # Get a single entry of data
        sample: Dict = self.data[index]
        # Extract patch image and associated metadata
        image, metadata = self._get_data(sample)
        # Get the label
        label = self._get_label(sample)

        # Create put all patch information together and apply transforms
        patch = {"image": image, "label": label, "metadata": metadata}
        return apply_transform(self.transform,
                               patch) if self.transform else patch
Exemplo n.º 12
0
class PatchWSIDataset(Dataset):
    """
    This dataset extracts patches from whole slide images (without loading the whole image)
    It also reads labels for each patch and provides each patch with its associated class labels.

    Args:
        data: the list of input samples including image, location, and label (see the note below for more details).
        size: the size of patch to be extracted from the whole slide image.
        level: the level at which the patches to be extracted (default to 0).
        transform: transforms to be executed on input data.
        include_label: whether to load and include labels in the output
        center_location: whether the input location information is the position of the center of the patch
        additional_meta_keys: the list of keys for items to be copied to the output metadata from the input data
        reader: the module to be used for loading whole slide imaging. If `reader` is

            - a string, it defines the backend of `monai.data.WSIReader`. Defaults to cuCIM.
            - a class (inherited from `BaseWSIReader`), it is initialized and set as wsi_reader.
            - an instance of a a class inherited from `BaseWSIReader`, it is set as the wsi_reader.

        kwargs: additional arguments to pass to `WSIReader` or provided whole slide reader class

    Note:
        The input data has the following form as an example:

        .. code-block:: python

            [
                {"image": "path/to/image1.tiff", "patch_location": [200, 500], "label": 0},
                {"image": "path/to/image2.tiff", "patch_location": [100, 700], "patch_size": [20, 20], "patch_level": 2, "label": 1}
            ]

    """
    def __init__(
        self,
        data: Sequence,
        patch_size: Optional[Union[int, Tuple[int, int]]] = None,
        patch_level: Optional[int] = None,
        transform: Optional[Callable] = None,
        include_label: bool = True,
        center_location: bool = True,
        additional_meta_keys: Optional[Sequence[str]] = None,
        reader="cuCIM",
        **kwargs,
    ):
        super().__init__(data, transform)

        # Ensure patch size is a two dimensional tuple
        if patch_size is None:
            self.patch_size = None
        else:
            self.patch_size = ensure_tuple_rep(patch_size, 2)

        # Create a default level that override all levels if it is not None
        self.patch_level = patch_level
        # Set the default WSIReader's level to 0 if level is not provided
        if patch_level is None:
            patch_level = 0

        # Setup the WSI reader
        self.wsi_reader: Union[WSIReader, BaseWSIReader]
        if isinstance(reader, str):
            self.wsi_reader = WSIReader(backend=reader,
                                        level=patch_level,
                                        **kwargs)
        elif inspect.isclass(reader) and issubclass(reader, BaseWSIReader):
            self.wsi_reader = reader(level=patch_level, **kwargs)
        elif isinstance(reader, BaseWSIReader):
            self.wsi_reader = reader
        else:
            raise ValueError(f"Unsupported reader type: {reader}.")
        self.backend = self.wsi_reader.backend

        self.include_label = include_label
        self.center_location = center_location
        self.additional_meta_keys = additional_meta_keys or []

        # Initialized an empty whole slide image object dict
        self.wsi_object_dict: Dict = {}

    def _get_wsi_object(self, sample: Dict):
        image_path = sample[CommonKeys.IMAGE]
        if image_path not in self.wsi_object_dict:
            self.wsi_object_dict[image_path] = self.wsi_reader.read(image_path)
        return self.wsi_object_dict[image_path]

    def _get_label(self, sample: Dict):
        return np.array(sample[CommonKeys.LABEL], dtype=np.float32)

    def _get_location(self, sample: Dict):
        if self.center_location:
            size = self._get_size(sample)
            return [
                sample[WSIPatchKeys.LOCATION][i] - size[i] // 2
                for i in range(len(size))
            ]
        else:
            return sample[WSIPatchKeys.LOCATION]

    def _get_level(self, sample: Dict):
        if self.patch_level is None:
            return sample.get(WSIPatchKeys.LEVEL, 0)
        return self.patch_level

    def _get_size(self, sample: Dict):
        if self.patch_size is None:
            return ensure_tuple_rep(sample.get(WSIPatchKeys.SIZE), 2)
        return self.patch_size

    def _get_data(self, sample: Dict):
        # Don't store OpenSlide objects to avoid issues with OpenSlide internal cache
        if self.backend == "openslide":
            self.wsi_object_dict = {}
        wsi_obj = self._get_wsi_object(sample)
        location = self._get_location(sample)
        level = self._get_level(sample)
        size = self._get_size(sample)
        return self.wsi_reader.get_data(wsi=wsi_obj,
                                        location=location,
                                        size=size,
                                        level=level)

    def _transform(self, index: int):
        # Get a single entry of data
        sample: Dict = self.data[index]

        # Extract patch image and associated metadata
        image, metadata = self._get_data(sample)
        output = {CommonKeys.IMAGE: image, CommonKeys.METADATA: metadata}

        # Include label in the output
        if self.include_label:
            output[CommonKeys.LABEL] = self._get_label(sample)

        for key in self.additional_meta_keys:
            metadata[key] = sample[key]

        # Apply transforms and return it
        return apply_transform(self.transform,
                               output) if self.transform else output