Skip to content

Commit

Permalink
BiggestTissueBoxMask as default extraction_mask in Tiler(s)
Browse files Browse the repository at this point in the history
  • Loading branch information
ernestoarbitrio committed Mar 9, 2021
1 parent c93a378 commit bd1cc4a
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 21 deletions.
4 changes: 2 additions & 2 deletions src/histolab/filters/image_filters.py
Expand Up @@ -40,7 +40,7 @@ class Filter(Protocol):
def __call__(
self, img: Union[PIL.Image.Image, np.ndarray]
) -> Union[PIL.Image.Image, np.ndarray]:
pass
pass # pragma: no cover

def __repr__(self) -> str:
return self.__class__.__name__ + "()"
Expand All @@ -52,7 +52,7 @@ class ImageFilter(Filter, Protocol):

@abstractmethod
def __call__(self, img: PIL.Image.Image) -> Union[PIL.Image.Image, np.ndarray]:
pass
pass # pragma: no cover


class Compose(ImageFilter):
Expand Down
2 changes: 1 addition & 1 deletion src/histolab/filters/morphological_filters.py
Expand Up @@ -37,7 +37,7 @@ class MorphologicalFilter(Filter, Protocol):

@abstractmethod
def __call__(self, np_mask: np.ndarray) -> np.ndarray:
pass
pass # pragma: no cover


class RemoveSmallObjects(MorphologicalFilter):
Expand Down
2 changes: 1 addition & 1 deletion src/histolab/masks.py
Expand Up @@ -56,7 +56,7 @@ def __call__(self, slide):
@abstractmethod
def _mask(self, slide): # pragma: no cover
# This property will be supplied by the inheriting classes individually
pass
pass # pragma: no cover


class BiggestTissueBoxMask(BinaryMask):
Expand Down
2 changes: 1 addition & 1 deletion src/histolab/scorer.py
Expand Up @@ -41,7 +41,7 @@ class Scorer(Protocol):

@abstractmethod
def __call__(self, tile: Tile) -> float:
pass
pass # pragma: no cover


class RandomScorer(Scorer):
Expand Down
49 changes: 35 additions & 14 deletions src/histolab/tiler.py
Expand Up @@ -75,13 +75,18 @@ def box_mask(self, slide: Slide) -> np.ndarray:
return biggest_tissue_box_mask(slide)

@abstractmethod
def extract(self, slide: Slide, extraction_mask: BinaryMask, log_level: str):
pass
def extract(
self,
slide: Slide,
log_level: str,
extraction_mask: BinaryMask = BiggestTissueBoxMask(),
):
pass # pragma: no cover

def locate_tiles(
self,
slide: Slide,
extraction_mask: BinaryMask,
extraction_mask: BinaryMask = BiggestTissueBoxMask(),
scale_factor: int = 32,
alpha: int = 128,
outline: str = "red",
Expand All @@ -94,6 +99,7 @@ def locate_tiles(
Slide reference where placing the tiles
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`
scale_factor: int
Scaling factor for the returned image. Default is 32.
alpha: int
Expand Down Expand Up @@ -172,9 +178,9 @@ def _tile_filename(
return tile_filename

def _tiles_generator(
self, slide: Slide, extraction_mask: BinaryMask
self, slide: Slide, extraction_mask: BinaryMask = BiggestTissueBoxMask()
) -> Tuple[Tile, CoordinatePair]:
pass
pass # pragma: no cover

def _validate_level(self, slide: Slide) -> None:
"""Validate the Tiler's level according to the Slide.
Expand Down Expand Up @@ -259,7 +265,10 @@ def __init__(
self.suffix = suffix

def extract(
self, slide: Slide, extraction_mask: BinaryMask, log_level: str = "INFO"
self,
slide: Slide,
extraction_mask: BinaryMask = BiggestTissueBoxMask(),
log_level: str = "INFO",
) -> None:
"""Extract tiles arranged in a grid and save them to disk, following this
filename pattern:
Expand All @@ -271,6 +280,7 @@ def extract(
Slide from which to extract the tiles
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
log_level : str, {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
Threshold level for the log messages. Default "INFO"
Expand Down Expand Up @@ -351,7 +361,7 @@ def _grid_coordinates_from_bbox_coordinates(
yield tile_wsi_coords

def _grid_coordinates_generator(
self, slide: Slide, extraction_mask: BinaryMask
self, slide: Slide, extraction_mask: BinaryMask = BiggestTissueBoxMask()
) -> CoordinatePair:
"""Generate Coordinates at level 0 of grid tiles within the tissue.
Expand All @@ -362,6 +372,7 @@ def _grid_coordinates_generator(
tissue area.
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
Yields
-------
Expand All @@ -384,7 +395,7 @@ def _grid_coordinates_generator(
)

def _tiles_generator(
self, slide: Slide, extraction_mask: BinaryMask
self, slide: Slide, extraction_mask: BinaryMask = BiggestTissueBoxMask()
) -> Tuple[Tile, CoordinatePair]:
"""Generator of tiles arranged in a grid.
Expand All @@ -394,6 +405,7 @@ def _tiles_generator(
Slide from which to extract the tiles
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
Yields
-------
Expand Down Expand Up @@ -504,7 +516,10 @@ def __init__(
self.suffix = suffix

def extract(
self, slide: Slide, extraction_mask: BinaryMask, log_level: str = "INFO"
self,
slide: Slide,
extraction_mask: BinaryMask = BiggestTissueBoxMask(),
log_level: str = "INFO",
) -> None:
"""Extract random tiles and save them to disk, following this filename pattern:
`{prefix}tile_{tiles_counter}_level{level}_{x_ul_wsi}-{y_ul_wsi}-{x_br_wsi}-{y_br_wsi}{suffix}`
Expand All @@ -515,6 +530,7 @@ def extract(
Slide from which to extract the tiles
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
log_level: str, {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
Threshold level for the log messages. Default "INFO"
Expand Down Expand Up @@ -566,7 +582,7 @@ def tile_size(self, tile_size_: Tuple[int, int]):
# ------- implementation helpers -------

def _random_tile_coordinates(
self, slide: Slide, extraction_mask: BinaryMask
self, slide: Slide, extraction_mask: BinaryMask = BiggestTissueBoxMask()
) -> CoordinatePair:
"""Return 0-level Coordinates of a tile picked at random within the box.
Expand All @@ -576,6 +592,7 @@ def _random_tile_coordinates(
Slide from which calculate the coordinates. Needed to calculate the box.
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
Returns
-------
Expand Down Expand Up @@ -608,7 +625,7 @@ def _random_tile_coordinates(
return tile_wsi_coords

def _tiles_generator(
self, slide: Slide, extraction_mask: BinaryMask
self, slide: Slide, extraction_mask: BinaryMask = BiggestTissueBoxMask()
) -> Tuple[Tile, CoordinatePair]:
"""Generate Random Tiles within a slide box.
Expand All @@ -622,6 +639,7 @@ def _tiles_generator(
The Whole Slide Image from which to extract the tiles.
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
Yields
------
Expand Down Expand Up @@ -714,7 +732,7 @@ def __init__(
def extract(
self,
slide: Slide,
extraction_mask: BinaryMask,
extraction_mask: BinaryMask = BiggestTissueBoxMask(),
report_path: str = None,
log_level: str = "INFO",
) -> None:
Expand All @@ -730,6 +748,7 @@ def extract(
Slide from which to extract the tiles
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
report_path : str, optional
Path to the CSV report. If None, no report will be saved
log_level: str, {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
Expand Down Expand Up @@ -773,7 +792,7 @@ def extract(
# ------- implementation helpers -------

def _tiles_generator(
self, slide: Slide, extraction_mask: BinaryMask
self, slide: Slide, extraction_mask: BinaryMask = BiggestTissueBoxMask()
) -> Tuple[List[Tuple[float, CoordinatePair]], List[Tuple[float, CoordinatePair]]]:
r"""Calculate the tiles with the highest scores and their extraction coordinates
Expand All @@ -783,6 +802,7 @@ def _tiles_generator(
The slide to extract the tiles from.
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
Returns
-------
Expand Down Expand Up @@ -892,7 +912,7 @@ def _scale_scores(
return list(zip(scores_scaled, coords))

def _scores(
self, slide: Slide, extraction_mask: BinaryMask
self, slide: Slide, extraction_mask: BinaryMask = BiggestTissueBoxMask()
) -> List[Tuple[float, CoordinatePair]]:
"""Calculate the scores for all the tiles extracted from the ``slide``.
Expand All @@ -902,6 +922,7 @@ def _scores(
The slide to extract the tiles from.
extraction_mask : BinaryMask
BinaryMask object defining how to compute a binary mask from a Slide.
Default `BiggestTissueBoxMask`.
Returns
-------
Expand Down
5 changes: 3 additions & 2 deletions tests/integration/test_tiler.py
Expand Up @@ -210,11 +210,12 @@ def it_locates_tiles_on_the_slide(
r"Input image must be RGB. NOTE: the image will be converted to RGB before"
r" HED conversion."
)
binary_mask = BiggestTissueBoxMask()

with pytest.warns(UserWarning, match=expected_warning_regex):
# no binary mask object passed to locate_tiles
# default value = BiggestTissueBoxMask
tiles_location_img = scored_tiles_extractor.locate_tiles(
slide, binary_mask, scale_factor=10
slide, scale_factor=10
)
# --- Expanding test report with actual and expected images ---
expand_tests_report(request, expected=expected_img, actual=tiles_location_img)
Expand Down

0 comments on commit bd1cc4a

Please sign in to comment.