Example #1
0
    def it_can_generate_grid_tiles_with_no_check_tissue(
        self,
        request,
        tmpdir,
        tile1,
        tile2,
        has_enough_tissue,
        expected_n_tiles,
    ):
        slide, _ = base_test_slide(tmpdir,
                                   PILIMG.RGBA_COLOR_500X500_155_249_240)
        _extract_tile = method_mock(request, Slide, "extract_tile")
        _has_enough_tissue = method_mock(request, Tile, "has_enough_tissue")
        _has_enough_tissue.side_effect = has_enough_tissue
        _grid_coordinates_generator = method_mock(
            request, GridTiler, "_grid_coordinates_generator")
        _grid_coordinates_generator.return_value = [
            CP(0, 10, 0, 10), CP(0, 10, 0, 10)
        ]
        _extract_tile.side_effect = [tile1, tile2]
        grid_tiler = GridTiler((10, 10), level=0, check_tissue=False)
        tiles = [tile1, tile2]

        generated_tiles = list(grid_tiler._tiles_generator(slide))

        _grid_coordinates_generator.assert_called_once_with(grid_tiler, slide)
        assert _extract_tile.call_args_list == ([
            call(slide, CP(0, 10, 0, 10), 0),
            call(slide, CP(0, 10, 0, 10), 0)
        ])
        _has_enough_tissue.assert_not_called()
        assert len(generated_tiles) == expected_n_tiles
        for i, tile in enumerate(generated_tiles):
            assert tile[0] == tiles[i]
Example #2
0
    def it_locates_tiles_on_the_slide(
        self,
        request,
        fixture_slide,
        binary_mask,
        tile_size,
        level,
        check_tissue,
        expectation,
    ):
        slide = Slide(fixture_slide, "")
        grid_tiles_extractor = GridTiler(
            tile_size=tile_size,
            level=level,
            check_tissue=check_tissue,
        )
        expected_img = load_expectation(expectation, type_="png")

        tiles_location_img = grid_tiles_extractor.locate_tiles(slide,
                                                               binary_mask,
                                                               scale_factor=10)

        # --- Expanding test report with actual and expected images ---
        expand_tests_report(request,
                            expected=expected_img,
                            actual=tiles_location_img)

        np.testing.assert_array_almost_equal(tiles_location_img, expected_img)
Example #3
0
    def it_can_extract_grid_tiles(self, request, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILIMG.RGBA_COLOR_500X500_155_249_240
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, os.path.join(tmp_path_, "processed"))
        _tiles_generator = method_mock(request, GridTiler, "_tiles_generator")
        coords = CP(0, 10, 0, 10)
        tile = Tile(image, coords)
        _tiles_generator.return_value = [(tile, coords), (tile, coords)]
        _tile_filename = method_mock(request, GridTiler, "_tile_filename")
        _tile_filename.side_effect = [
            os.path.join(tmp_path_, "processed", "tiles",
                         f"tile_{i}_level2_0-10-0-10.png") for i in range(2)
        ]
        _has_valid_tile_size = method_mock(request, GridTiler,
                                           "_has_valid_tile_size")
        _has_valid_tile_size.return_value = True
        grid_tiler = GridTiler((10, 10), level=0)

        grid_tiler.extract(slide)

        assert _tile_filename.call_args_list == [
            call(grid_tiler, coords, 0),
            call(grid_tiler, coords, 1),
        ]
        assert os.path.exists(
            os.path.join(tmp_path_, "processed", "tiles",
                         "tile_0_level2_0-10-0-10.png"))
        assert os.path.exists(
            os.path.join(tmp_path_, "processed", "tiles",
                         "tile_1_level2_0-10-0-10.png"))
        _has_valid_tile_size.assert_called_once_with(grid_tiler, slide)
Example #4
0
    def it_can_generate_grid_tiles(
        self,
        request,
        tmpdir,
        tile1,
        tile2,
        check_tissue,
        has_enough_tissue,
        expected_n_tiles,
    ):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILIMG.RGBA_COLOR_500X500_155_249_240
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        _extract_tile = method_mock(request, Slide, "extract_tile")
        _has_enough_tissue = method_mock(request, Tile, "has_enough_tissue")
        _has_enough_tissue.side_effect = has_enough_tissue
        _grid_coordinates_generator = method_mock(
            request, GridTiler, "_grid_coordinates_generator"
        )
        _grid_coordinates_generator.return_value = [CP(0, 10, 0, 10), CP(0, 10, 0, 10)]
        _extract_tile.side_effect = [tile1, tile2]
        grid_tiler = GridTiler((10, 10), level=0, check_tissue=check_tissue)
        tiles = [tile1, tile2]

        generated_tiles = list(grid_tiler._tiles_generator(slide))

        _grid_coordinates_generator.assert_called_once_with(grid_tiler, slide)
        assert _extract_tile.call_args_list == (
            [call(slide, CP(0, 10, 0, 10), 0), call(slide, CP(0, 10, 0, 10), 0)]
        )
        assert len(generated_tiles) == expected_n_tiles
        for i, tile in enumerate(generated_tiles):
            assert tile[0] == tiles[i]
Example #5
0
    def it_can_calculate_n_tiles_row(self, request, bbox_coordinates,
                                     pixel_overlap, expected_n_tiles_row):
        grid_tiler = GridTiler((512, 512), 2, True, pixel_overlap)

        n_tiles_row = grid_tiler._n_tiles_row(bbox_coordinates)

        assert type(n_tiles_row) == int
        assert n_tiles_row == expected_n_tiles_row
Example #6
0
    def it_can_calculate_n_tiles_column(self, bbox_coordinates, pixel_overlap,
                                        expected_n_tiles_column):
        grid_tiler = GridTiler((512, 512), 2, True, 80, pixel_overlap)

        n_tiles_column = grid_tiler._n_tiles_column(bbox_coordinates)

        assert type(n_tiles_column) == int
        assert n_tiles_column == expected_n_tiles_column
Example #7
0
    def it_knows_if_it_has_valid_tile_size(self, tmpdir, tile_size,
                                           expected_result):
        slide, _ = base_test_slide(tmpdir,
                                   PILIMG.RGBA_COLOR_500X500_155_249_240)
        grid_tiler = GridTiler(tile_size, 0, True)

        result = grid_tiler._has_valid_tile_size(slide)

        assert type(result) == bool
        assert result == expected_result
Example #8
0
    def or_it_has_not_available_level_value(self, tmpdir):
        slide, _ = base_test_slide(tmpdir, PILIMG.RGB_RANDOM_COLOR_500X500)
        binary_mask = BiggestTissueBoxMask()
        grid_tiler = GridTiler((128, 128), 3)

        with pytest.raises(LevelError) as err:
            grid_tiler.extract(slide, binary_mask)

        assert isinstance(err.value, LevelError)
        assert str(err.value
                   ) == "Level 3 not available. Number of available levels: 1"
Example #9
0
    def it_knows_whether_coordinates_are_within_extraction_mask(
            self, tile_coords, expected_result):
        grid_tiler = GridTiler((2, 2),
                               level=0)  # tile size doens't matter here
        mask = COMPLEX_MASK4

        coords_within_extraction_mask = (
            grid_tiler._are_coordinates_within_extraction_mask(
                tile_coords, mask))

        assert type(coords_within_extraction_mask) == bool
        assert coords_within_extraction_mask == expected_result
Example #10
0
    def and_doesnt_raise_error_with_wrong_coordinates(self, request, tmpdir):
        slide, _ = base_test_slide(tmpdir,
                                   PILIMG.RGBA_COLOR_500X500_155_249_240)
        coords = CP(5800, 6000, 5800, 6000)
        _grid_coordinates_generator = method_mock(
            request, GridTiler, "_grid_coordinates_generator")
        _grid_coordinates_generator.return_value = [coords]
        grid_tiler = GridTiler((10, 10))
        generated_tiles = list(grid_tiler._tiles_generator(slide))

        assert len(generated_tiles) == 0
        _grid_coordinates_generator.assert_called_once_with(grid_tiler, slide)
Example #11
0
    def or_it_has_not_available_level_value(self, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILIMG.RGB_RANDOM_COLOR_500X500
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        grid_tiler = GridTiler((128, 128), 3)

        with pytest.raises(LevelError) as err:
            grid_tiler.extract(slide)

        assert isinstance(err.value, LevelError)
        assert str(err.value) == "Level 3 not available. Number of available levels: 1"
Example #12
0
    def it_knows_its_box_mask(self, request, tmpdir, check_tissue,
                              expected_box):
        slide, _ = base_test_slide(tmpdir,
                                   PILIMG.RGBA_COLOR_500X500_155_249_240)
        _biggest_tissue_box_mask = property_mock(request, Slide,
                                                 "biggest_tissue_box_mask")
        _biggest_tissue_box_mask.return_value = expected_box
        grid_tiler = GridTiler((128, 128), 0, check_tissue=check_tissue)

        box_mask = grid_tiler.box_mask(slide)

        _biggest_tissue_box_mask.assert_called_once_with()
        assert type(box_mask) == np.ndarray
        np.testing.assert_array_almost_equal(box_mask, expected_box)
Example #13
0
    def and_doesnt_raise_error_with_wrong_coordinates(self, request, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILImageMock.DIMS_500X500_RGBA_COLOR_155_249_240
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        coords = CoordinatePair(5800, 6000, 5800, 6000)
        _grid_coordinates_generator = method_mock(
            request, GridTiler, "_grid_coordinates_generator")
        _grid_coordinates_generator.return_value = [coords]
        grid_tiler = GridTiler((10, 10))
        generated_tiles = list(grid_tiler._grid_tiles_generator(slide))

        assert len(generated_tiles) == 0
        _grid_coordinates_generator.assert_called_once_with(grid_tiler, slide)
Example #14
0
    def it_knows_its_tile_filename(
        self,
        level,
        pixel_overlap,
        prefix,
        tile_coords,
        tiles_counter,
        expected_filename,
    ):
        grid_tiler = GridTiler((512, 512), level, True, pixel_overlap, prefix, ".png")

        _filename = grid_tiler._tile_filename(tile_coords, tiles_counter)

        assert type(_filename) == str
        assert _filename == expected_filename
Example #15
0
    def it_knows_its_tile_size(self, tile_size):
        grid_tiler = GridTiler(tile_size, 10, True, 0)

        tile_size_ = grid_tiler.tile_size

        assert type(tile_size_) == tuple
        assert tile_size_ == tile_size
Example #16
0
    def it_constructs_from_args(self, request):
        _init = initializer_mock(request, GridTiler)

        grid_tiler = GridTiler((512, 512), 2, True, 0, "", ".png")

        _init.assert_called_once_with(ANY, (512, 512), 2, True, 0, "", ".png")
        assert isinstance(grid_tiler, GridTiler)
        assert isinstance(grid_tiler, Tiler)
Example #17
0
    def it_knows_its_box_mask(self, request, tmpdir, check_tissue, expected_box):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILIMG.RGBA_COLOR_500X500_155_249_240
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        _biggest_tissue_box_mask = property_mock(
            request, Slide, "biggest_tissue_box_mask"
        )
        _biggest_tissue_box_mask.return_value = expected_box
        grid_tiler = GridTiler((128, 128), 0, check_tissue=check_tissue)

        box_mask = grid_tiler.box_mask(slide)

        _biggest_tissue_box_mask.assert_called_once_with()
        assert type(box_mask) == np.ndarray
        np.testing.assert_array_almost_equal(box_mask, expected_box)
Example #18
0
    def it_locates_tiles_on_the_slide(self, request, fixture_slide,
                                      expectation, tmpdir):
        slide = Slide(fixture_slide, os.path.join(tmpdir, "processed"))
        grid_tiles_extractor = GridTiler(
            tile_size=(512, 512),
            level=0,
            check_tissue=False,
        )
        expected_img = load_expectation(expectation, type_="png")
        tiles_location_img = grid_tiles_extractor.locate_tiles(slide,
                                                               scale_factor=10)
        # --- Expanding test report with actual and expected images ---
        expand_tests_report(request,
                            expected=expected_img,
                            actual=tiles_location_img)

        np.testing.assert_array_almost_equal(np.asarray(tiles_location_img),
                                             expected_img)
Example #19
0
    def it_knows_its_tile_filename(self, request, tile_filename_fixture):
        (
            tile_size,
            level,
            check_tissue,
            pixel_overlap,
            prefix,
            suffix,
            tile_coords,
            tiles_counter,
            expected_filename,
        ) = tile_filename_fixture
        grid_tiler = GridTiler(tile_size, level, check_tissue, pixel_overlap,
                               prefix, suffix)

        _filename = grid_tiler._tile_filename(tile_coords, tiles_counter)

        assert type(_filename) == str
        assert _filename == expected_filename
Example #20
0
    def but_it_raises_tilesizeerror_if_tilesize_larger_than_slidesize(
            self, request, tmpdir, image, size):
        tmp_path_ = tmpdir.mkdir("myslide")
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, os.path.join(tmp_path_, "processed"))
        _has_valid_tile_size = method_mock(request, GridTiler,
                                           "_has_valid_tile_size")
        _has_valid_tile_size.return_value = False
        grid_tiler = GridTiler((50, 52), level=0)

        with pytest.raises(TileSizeError) as err:
            grid_tiler.extract(slide)

        assert isinstance(err.value, TileSizeError)
        assert (str(
            err.value
        ) == f"Tile size (50, 52) is larger than slide size {size} at level 0")
        _has_valid_tile_size.assert_called_once_with(grid_tiler, slide)
Example #21
0
    def but_with_wrong_coordinates(self, request, tmpdir):
        slide, _ = base_test_slide(tmpdir,
                                   PILIMG.RGBA_COLOR_500X500_155_249_240)
        _has_enough_tissue = method_mock(request, Tile, "has_enough_tissue")
        _has_enough_tissue.return_value = False
        _grid_coordinates_generator = method_mock(
            request, GridTiler, "_grid_coordinates_generator")
        coords1 = CP(600, 610, 600, 610)
        coords2 = CP(0, 10, 0, 10)
        _grid_coordinates_generator.return_value = [coords1, coords2]
        grid_tiler = GridTiler((10, 10), level=0, check_tissue=False)

        generated_tiles = list(grid_tiler._tiles_generator(slide))

        _grid_coordinates_generator.assert_called_once_with(grid_tiler, slide)
        assert len(generated_tiles) == 1
        # generated_tiles[0][0] is a Tile object but we don't know what object it is
        # because Slide.extract_tile is not mocked (for the exception to happen inside)
        assert isinstance(generated_tiles[0][0], Tile)
        assert generated_tiles[0][1] == coords2
Example #22
0
    def it_can_generate_grid_tiles(
        self,
        request,
        tmpdir,
        grid_tiles_fixture,
    ):
        (
            coords1,
            coords2,
            check_tissue,
            has_enough_tissue,
            expected_n_tiles,
        ) = grid_tiles_fixture
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILImageMock.DIMS_500X500_RGBA_COLOR_155_249_240
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        _extract_tile = method_mock(request, Slide, "extract_tile")
        _has_enough_tissue = method_mock(request, Tile, "has_enough_tissue")
        _has_enough_tissue.side_effect = has_enough_tissue
        _grid_coordinates_generator = method_mock(
            request, GridTiler, "_grid_coordinates_generator")
        _grid_coordinates_generator.return_value = [coords1, coords2]
        tile1 = Tile(image, coords1)
        tile2 = Tile(image, coords2)
        _extract_tile.side_effect = [tile1, tile2]
        grid_tiler = GridTiler((10, 10), level=0, check_tissue=check_tissue)

        generated_tiles = list(grid_tiler._grid_tiles_generator(slide))

        _grid_coordinates_generator.assert_called_once_with(grid_tiler, slide)
        _extract_tile.call_args_list == ([call(coords1, 0), call(coords2, 0)])
        assert len(generated_tiles) == expected_n_tiles
        if expected_n_tiles == 2:
            assert generated_tiles == [(tile1, coords1), (tile2, coords2)]
        if expected_n_tiles == 1:
            assert generated_tiles == [(tile1, coords1)]
        if expected_n_tiles == 0:
            assert generated_tiles == []
Example #23
0
    def but_with_wrong_coordinates(self, request, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILIMG.RGBA_COLOR_500X500_155_249_240
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        _has_enough_tissue = method_mock(request, Tile, "has_enough_tissue")
        _has_enough_tissue.return_value = False
        _grid_coordinates_generator = method_mock(
            request, GridTiler, "_grid_coordinates_generator"
        )
        coords1 = CP(600, 610, 600, 610)
        coords2 = CP(0, 10, 0, 10)
        _grid_coordinates_generator.return_value = [coords1, coords2]
        grid_tiler = GridTiler((10, 10), level=0, check_tissue=False)

        generated_tiles = list(grid_tiler._tiles_generator(slide))

        _grid_coordinates_generator.assert_called_once_with(grid_tiler, slide)
        assert len(generated_tiles) == 1
        # generated_tiles[0][0] is a Tile object but we don't know what object it is
        # because Slide.extract_tile is not mocked (for the exception to happen inside)
        assert isinstance(generated_tiles[0][0], Tile)
        assert generated_tiles[0][1] == coords2
from histolab.tiler import GridTiler
from histolab.slide import Slide

prostate_svs, prostate_path = prostate_tissue()
#TODO CHANGE PATHS HERE!
SVS_PATH = prostate_path
N_TILES = 175
TILE_SIZE = 512
EXTRACTION_LVL = 1

# %%
slide_obj= Slide(str(SVS_PATH), processed_path=".", slide_filters="texture")
slide_obj
# %%
tiler = GridTiler(
    tile_size= (TILE_SIZE, TILE_SIZE),
    level = EXTRACTION_LVL,
    check_tissue=True,
    pixel_overlap= 0,
    prefix=  str(Path(__file__).parent / slide_obj.name),
    suffix=".png",
    partial=1.0,
    maximum=N_TILES,
)

# %%
# create and save the extraction map as png
plot = tiler.extraction_plot(slide_obj)
Image.fromarray(plot).save('tile_extraction_example.png')
# %%
Example #25
0
    def but_it_has_wrong_tile_size_value(self):
        with pytest.raises(ValueError) as err:
            GridTiler((512, -1))

        assert isinstance(err.value, ValueError)
        assert str(err.value) == "Tile size must be greater than 0 ((512, -1))"
Example #26
0
    def or_it_has_negative_level_value(self, request):
        with pytest.raises(ValueError) as err:
            GridTiler((512, 512), -1)

        assert isinstance(err.value, ValueError)
        assert str(err.value) == "Level cannot be negative (-1)"
Example #27
0
"""
https://histolab.readthedocs.io/en/latest/api/tiler.html
Extract tiles arranged in a grid 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}
"""
tile_sz = 300
level = 0
# check_tissue = True
check_tissue = False

grid_tiler = GridTiler(
    tile_size=(tile_sz, tile_sz),  # (width, height) of the extracted tiles
    level=level,  # Level from which extract the tiles. Default is 0.
    check_tissue=
    check_tissue,  # Whether to check if the tile has enough tissue to be saved. Default is True.
    pixel_overlap=
    0,  # Number of overlapping pixels (for both height and width) between two adjacent tiles.
    prefix=
    '',  # Prefix to be added to the tile filename. Default is an empty string.
    suffix=".png"  # default
)

# Find the smallest slide
idx = meta_df['openslide.level[0].height'].isin(
    [meta_df['openslide.level[0].height'].min()])
img_name = meta_df.loc[idx, 'aperio.ImageID'].values[0]
fname = imgpath / f'{img_name}.svs'

# Slide instance
# path: path to WSI file
# processed_path: path to save thumbnails and scaled images