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]
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]
def it_knows_its_mask( self, request, tmpdir, RgbToGrayscale_, OtsuThreshold_, BinaryDilation_, RemoveSmallHoles_, RemoveSmallObjects_, ): slide, _ = base_test_slide(tmpdir, PILIMG.RGBA_COLOR_500X500_155_249_240) regions = [ Region(index=0, area=33, bbox=(0, 0, 2, 2), center=(0.5, 0.5), coords=None) ] main_tissue_areas_mask_filters_ = property_mock( request, _SlideFiltersComposition, "tissue_mask_filters") main_tissue_areas_mask_filters_.return_value = Compose([ RgbToGrayscale_, OtsuThreshold_, BinaryDilation_, RemoveSmallHoles_, RemoveSmallObjects_, ]) regions_from_binary_mask = function_mock( request, "histolab.masks.regions_from_binary_mask") regions_from_binary_mask.return_value = regions biggest_regions_ = method_mock(request, BiggestTissueBoxMask, "_regions", autospec=False) biggest_regions_.return_value = regions region_coordinates_ = function_mock( request, "histolab.masks.region_coordinates") region_coordinates_.return_values = CP(0, 0, 2, 2) rectangle_to_mask_ = function_mock(request, "histolab.util.rectangle_to_mask") rectangle_to_mask_((1000, 1000), CP(0, 0, 2, 2)).return_value = [ [True, True], [False, True], ] biggest_mask_tissue_box = BiggestTissueBoxMask() binary_mask = biggest_mask_tissue_box(slide) np.testing.assert_almost_equal(binary_mask, np.zeros((500, 500))) region_coordinates_.assert_called_once_with(regions[0]) biggest_regions_.assert_called_once_with(regions, n=1) rectangle_to_mask_.assert_called_once_with((1000, 1000), CP(x_ul=0, y_ul=0, x_br=2, y_br=2))
def it_knows_its_biggest_tissue_box_mask( self, request, tmpdir, RgbToGrayscale_, OtsuThreshold_, BinaryDilation_, RemoveSmallHoles_, RemoveSmallObjects_, ): 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") regions = [ Region(index=0, area=33, bbox=(0, 0, 2, 2), center=(0.5, 0.5)) ] main_tissue_areas_mask_filters_ = property_mock( request, _SlideFiltersComposition, "tissue_mask_filters") main_tissue_areas_mask_filters_.return_value = Compose([ RgbToGrayscale_, OtsuThreshold_, BinaryDilation_, RemoveSmallHoles_, RemoveSmallObjects_, ]) regions_from_binary_mask = function_mock( request, "histolab.slide.regions_from_binary_mask") regions_from_binary_mask.return_value = regions biggest_regions_ = method_mock(request, Slide, "_biggest_regions", autospec=False) biggest_regions_.return_value = regions region_coordinates_ = function_mock( request, "histolab.slide.region_coordinates") region_coordinates_.return_values = CP(0, 0, 2, 2) polygon_to_mask_array_ = function_mock( request, "histolab.util.polygon_to_mask_array") polygon_to_mask_array_((1000, 1000), CP(0, 0, 2, 2)).return_value = [ [True, True], [False, True], ] biggest_mask_tissue_box = slide.biggest_tissue_box_mask region_coordinates_.assert_called_once_with(regions[0]) biggest_regions_.assert_called_once_with(regions, n=1) polygon_to_mask_array_.assert_called_once_with((1000, 1000), CP(x_ul=0, y_ul=0, x_br=2, y_br=2)) np.testing.assert_almost_equal(biggest_mask_tissue_box, np.zeros((500, 500)))
def it_can_generate_random_tiles_even_when_coords_are_not_valid( self, tmpdir, _random_tile_coordinates ): random_tiler = RandomTiler((10, 10), 1, level=0, max_iter=1, check_tissue=False) _random_tile_coordinates.side_effect = [CP(-1, -1, -1, -1), CP(0, 10, 0, 10)] 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") generated_tiles = list(random_tiler._tiles_generator(slide)) assert generated_tiles[0][1] == CP(0, 10, 0, 10) assert isinstance(generated_tiles[0][0], Tile)
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)
def it_knows_its_coords(self): _coords = CP(0, 0, 50, 50) tile = Tile(None, _coords, 0) coords = tile.coords assert coords == _coords
def it_can_save_report(self, request, tmpdir): tmp_path_ = tmpdir.mkdir("path") coords = CP(0, 10, 0, 10) highest_score_tiles = [(0.8, coords), (0.7, coords)] highest_scaled_score_tiles = [(0.1, coords), (0.0, coords)] filenames = ["tile0.png", "tile1.png"] random_scorer_ = instance_mock(request, RandomScorer) score_tiler = ScoreTiler(random_scorer_, (10, 10), 2, 2) report_ = [ "filename,score,scaled_score", "tile0.png,0.8,0.1", "tile1.png,0.7,0.0", ] score_tiler._save_report( os.path.join(tmp_path_, "report.csv"), highest_score_tiles, highest_scaled_score_tiles, filenames, ) assert os.path.exists(os.path.join(tmp_path_, "report.csv")) with open(os.path.join(tmp_path_, "report.csv"), newline="") as f: reader = csv.reader(f) report = [",".join(row) for row in reader] assert report == report_
def it_can_generate_random_coordinates(self, request, tmpdir): slide, _ = base_test_slide(tmpdir, PILIMG.RGBA_COLOR_500X500_155_249_240) _box_mask_thumb = method_mock(request, BiggestTissueBoxMask, "__call__") _box_mask_thumb.return_value = NpArrayMock.ONES_500X500_BOOL _tile_size = property_mock(request, RandomTiler, "tile_size") _tile_size.return_value = (128, 128) _random_choice_true_mask2d = function_mock( request, "histolab.tiler.random_choice_true_mask2d") _random_choice_true_mask2d.return_value = (0, 0) _scale_coordinates = function_mock(request, "histolab.tiler.scale_coordinates") random_tiler = RandomTiler((128, 128), 10, 0) binary_mask = BiggestTissueBoxMask() random_tiler._random_tile_coordinates(slide, binary_mask) _box_mask_thumb.assert_called_once_with(binary_mask, slide) _tile_size.assert_has_calls([call((128, 128))]) _random_choice_true_mask2d.assert_called_once_with( NpArrayMock.ONES_500X500_BOOL) _scale_coordinates.assert_called_once_with( reference_coords=CP(x_ul=0, y_ul=0, x_br=128, y_br=128), reference_size=(500, 500), target_size=(500, 500), )
def it_can_calculate_scores(self, request): slide = instance_mock(request, Slide) coords = CP(0, 10, 0, 10) image = PILIMG.RGB_RANDOM_COLOR_500X500 tile = Tile(image, coords) _tiles_generator = method_mock(request, GridTiler, "_tiles_generator") # it needs to be a generator _tiles_generator.return_value = ((tile, coords) for i in range(3)) _scorer = instance_mock(request, RandomScorer) _scorer.side_effect = [0.5, 0.7] score_tiler = ScoreTiler(_scorer, (10, 10), 2, 0) binary_mask = BiggestTissueBoxMask() scores = score_tiler._scores(slide, binary_mask) assert _tiles_generator.call_args_list == [ call(score_tiler, slide, binary_mask), call(score_tiler, slide, binary_mask), ] assert _scorer.call_args_list == [call(tile), call(tile)] assert type(scores) == list assert type(scores[0]) == tuple assert type(scores[0][0]) == float assert type(scores[0][1]) == CP assert scores == [(0.5, coords), (0.7, coords)]
def but_it_raises_error_with_negative_n_tiles_value(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")) _scores = method_mock(request, ScoreTiler, "_scores") coords = CP(0, 10, 0, 10) _scores.return_value = [ (0.7, coords), (0.5, coords), (0.2, coords), (0.8, coords), (0.1, coords), ] _scorer = instance_mock(request, RandomScorer) score_tiler = ScoreTiler(_scorer, (10, 10), -1, 0) binary_mask = BiggestTissueBoxMask() with pytest.raises(ValueError) as err: score_tiler.extract(slide, binary_mask) assert isinstance(err.value, ValueError) assert str(err.value) == "'n_tiles' cannot be negative (-1)" _scores.assert_called_once_with(score_tiler, slide, binary_mask)
def it_knows_if_is_is_almost_white(self, tile_img, expected_result): coords = CP(0, 512, 0, 512) tile = Tile(tile_img, coords) is_almost_white = tile._is_almost_white assert is_almost_white == expected_result
def it_can_generate_random_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") _box_mask_thumb = method_mock(request, RandomTiler, "box_mask") _box_mask_thumb.return_value = NpArrayMock.ONES_500X500_BOOL _tile_size = property_mock(request, RandomTiler, "tile_size") _tile_size.return_value = (128, 128) _np_random_choice1 = function_mock(request, "numpy.random.choice") _np_random_choice1.return_value = 0 _np_random_choice2 = function_mock(request, "numpy.random.choice") _np_random_choice2.return_value = 0 _scale_coordinates = function_mock(request, "histolab.tiler.scale_coordinates") random_tiler = RandomTiler((128, 128), 10, 0) random_tiler._random_tile_coordinates(slide) _box_mask_thumb.assert_called_once_with(slide) _tile_size.assert_has_calls([call((128, 128))]) _scale_coordinates.assert_called_once_with( reference_coords=CP(x_ul=0, y_ul=0, x_br=128, y_br=128), reference_size=(500, 500), target_size=(500, 500), )
def it_can_generate_random_tiles_even_when_coords_are_not_valid( self, tmpdir, _random_tile_coordinates): random_tiler = RandomTiler((10, 10), 1, level=0, max_iter=1, check_tissue=False) _random_tile_coordinates.side_effect = [ CP(-1, -1, -1, -1), CP(0, 10, 0, 10) ] slide, _ = base_test_slide(tmpdir, PILIMG.RGBA_COLOR_500X500_155_249_240) generated_tiles = list(random_tiler._tiles_generator(slide)) assert generated_tiles[0][1] == CP(0, 10, 0, 10) assert isinstance(generated_tiles[0][0], Tile)
def test_region_coordinates(): region = Region(index=0, area=14, bbox=(0, 1, 1, 2), center=(0.5, 0.5), coords=None) region_coords_ = region_coordinates(region) assert region_coords_ == CP(x_ul=1, y_ul=0, x_br=2, y_br=1)
def but_it_has_wrong_image_type(self): """This test simulates a wrong user behaviour, using a None object instead of a PIL Image for image param""" with pytest.raises(AttributeError) as err: tile = Tile(None, CP(0, 0, 50, 50), 0) tile.has_enough_tissue() assert isinstance(err.value, AttributeError) assert str(err.value) == "'NoneType' object has no attribute 'convert'"
def it_constructs_from_args(self, request): _init = initializer_mock(request, Tile) _image = PILIMG.RGBA_COLOR_50X50_155_0_0 _level = 0 _coords = CP(0, 0, 50, 50) tile = Tile(_image, _coords, _level) _init.assert_called_once_with(ANY, _image, _coords, _level) assert isinstance(tile, Tile)
def it_can_extract_score_tiles_and_save_report(self, request, tmpdir): _extract_tile = method_mock(request, Slide, "extract_tile") 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")) coords = CP(0, 10, 0, 10) _tiles_generator = method_mock( request, ScoreTiler, "_tiles_generator", ) tile = Tile(image, coords) _extract_tile.return_value = tile _tiles_generator.return_value = ( [(0.8, coords), (0.7, coords)], [(0.8, coords), (0.7, coords)], ) _tile_filename = method_mock(request, GridTiler, "_tile_filename") _tile_filename.side_effect = [ f"tile_{i}_level2_0-10-0-10.png" for i in range(2) ] _save_report = method_mock(request, ScoreTiler, "_save_report", autospec=False) random_scorer = RandomScorer() score_tiler = ScoreTiler(random_scorer, (10, 10), 2, 0) binary_mask = BiggestTissueBoxMask() score_tiler.extract(slide, binary_mask, "report.csv") assert _extract_tile.call_args_list == [ call(slide, coords, 0, (10, 10)), call(slide, coords, 0, (10, 10)), ] _tiles_generator.assert_called_with(score_tiler, slide, binary_mask) assert _tile_filename.call_args_list == [ call(score_tiler, coords, 0), call(score_tiler, coords, 1), ] assert os.path.exists( os.path.join(tmp_path_, "processed", "tile_0_level2_0-10-0-10.png")) assert os.path.exists( os.path.join(tmp_path_, "processed", "tile_1_level2_0-10-0-10.png")) _save_report.assert_called_once_with( "report.csv", [(0.8, coords), (0.7, coords)], [(0.8, coords), (0.7, coords)], [f"tile_{i}_level2_0-10-0-10.png" for i in range(2)], )
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
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)
def it_can_generate_random_tiles_with_check_tissue_but_tiles_without_tissue( self, request, tmpdir, _random_tile_coordinates, ): 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 = [False, False] * 5 binary_mask = BiggestTissueBoxMask() tiles = [ Tile(PILIMG.RGBA_COLOR_500X500_155_249_240, CP(0, 10, 0, 10)), Tile(PILIMG.RGBA_COLOR_500X500_155_249_240, CP(0, 10, 0, 10)), ] _extract_tile.side_effect = tiles * 5 random_tiler = RandomTiler( (10, 10), 2, level=0, max_iter=10, check_tissue=True, tissue_percent=60, ) generated_tiles = list( random_tiler._tiles_generator(slide, binary_mask)) _random_tile_coordinates.assert_called_with(random_tiler, slide, binary_mask) assert (_has_enough_tissue.call_args_list == [ call(tiles[0], 60), call(tiles[1], 60), ] * 5) assert _random_tile_coordinates.call_count <= random_tiler.max_iter assert len(generated_tiles) == 0 for i, tile in enumerate(generated_tiles): assert tile[0] == tiles[i]
def it_can_scale_scores(self): coords = [CP(0, 10 * i, 0, 10) for i in range(3)] scores = [0.3, 0.4, 0.7] scores_ = list(zip(scores, coords)) score_tiler = ScoreTiler(None, (10, 10), 2, 0) expected_scaled_coords = list(zip([0.0, 0.2500000000000001, 1.0], coords)) scaled_scores = score_tiler._scale_scores(scores_) for (score, coords_), (expected_score, expected_coords) in zip( scaled_scores, expected_scaled_coords ): assert round(score, 5) == round(expected_score, 5) assert coords_ == expected_coords
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
def and_doesnt_raise_error_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") 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)
def it_can_calculate_highest_score_tiles(self, request, n_tiles, expected_value): slide = instance_mock(request, Slide) _scores = method_mock(request, ScoreTiler, "_scores") coords = CP(0, 10, 0, 10) _scores.return_value = [ (0.7, coords), (0.5, coords), (0.2, coords), (0.8, coords), (0.1, coords), ] _scorer = instance_mock(request, RandomScorer) score_tiler = ScoreTiler(_scorer, (10, 10), n_tiles, 0) highest_score_tiles = score_tiler._highest_score_tiles(slide) _scores.assert_called_once_with(score_tiler, slide) assert highest_score_tiles == expected_value
def but_it_raises_error_with_negative_n_tiles_value(self, request): slide = instance_mock(request, Slide) _scores = method_mock(request, ScoreTiler, "_scores") coords = CP(0, 10, 0, 10) _scores.return_value = [ (0.7, coords), (0.5, coords), (0.2, coords), (0.8, coords), (0.1, coords), ] _scorer = instance_mock(request, RandomScorer) score_tiler = ScoreTiler(_scorer, (10, 10), -1, 0) with pytest.raises(ValueError) as err: score_tiler.extract(slide) assert isinstance(err.value, ValueError) assert str(err.value) == "'n_tiles' cannot be negative (-1)"
def it_can_extract_score_tiles(self, request, tmpdir): _extract_tile = method_mock(request, Slide, "extract_tile") 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")) _highest_score_tiles = method_mock(request, ScoreTiler, "_highest_score_tiles") coords = CP(0, 10, 0, 10) tile = Tile(image, coords) _extract_tile.return_value = tile _highest_score_tiles.return_value = ( [(0.8, coords), (0.7, coords)], [(0.8, coords), (0.7, coords)], ) _tile_filename = method_mock(request, GridTiler, "_tile_filename") _tile_filename.side_effect = [ f"tile_{i}_level2_0-10-0-10.png" for i in range(2) ] _save_report = method_mock(request, ScoreTiler, "_save_report") random_scorer = RandomScorer() score_tiler = ScoreTiler(random_scorer, (10, 10), 2, 2) score_tiler.extract(slide) assert _extract_tile.call_args_list == [ call(slide, coords, 2), call(slide, coords, 2), ] _highest_score_tiles.assert_called_once_with(score_tiler, slide) assert _tile_filename.call_args_list == [ call(score_tiler, coords, 0), call(score_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") ) _save_report.assert_not_called()
def it_can_extract_random_tiles(self, request, tmpdir, caplog): 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, RandomTiler, "_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, RandomTiler, "_tile_filename") _tile_filename.side_effect = [ f"tile_{i}_level2_0-10-0-10.png" for i in range(2) ] _has_valid_tile_size = method_mock(request, RandomTiler, "_has_valid_tile_size") _has_valid_tile_size.return_value = True random_tiler = RandomTiler((10, 10), n_tiles=2, level=0) binary_mask = BiggestTissueBoxMask() with caplog.at_level(logging.INFO): random_tiler.extract(slide, binary_mask) assert re.sub(r":+\d{3}", "", caplog.text).splitlines() == [ "INFO tiler:tiler.py \t Tile 0 saved: tile_0_level2_0-10-0-10.png", "INFO tiler:tiler.py \t Tile 1 saved: tile_1_level2_0-10-0-10.png", "INFO tiler:tiler.py 2 Random Tiles have been saved.", ] assert _tile_filename.call_args_list == [ call(random_tiler, coords, 0), call(random_tiler, coords, 1), ] assert os.path.exists( os.path.join(tmp_path_, "processed", "tile_0_level2_0-10-0-10.png")) assert os.path.exists( os.path.join(tmp_path_, "processed", "tile_1_level2_0-10-0-10.png")) _has_valid_tile_size.assert_called_once_with(random_tiler, slide)
def it_can_generate_random_coordinates(self, request, tmpdir): slide, _ = base_test_slide(tmpdir, PILIMG.RGBA_COLOR_500X500_155_249_240) _box_mask_thumb = method_mock(request, RandomTiler, "box_mask") _box_mask_thumb.return_value = NpArrayMock.ONES_500X500_BOOL _tile_size = property_mock(request, RandomTiler, "tile_size") _tile_size.return_value = (128, 128) _np_random_choice1 = function_mock(request, "numpy.random.choice") _np_random_choice1.return_value = 0 _np_random_choice2 = function_mock(request, "numpy.random.choice") _np_random_choice2.return_value = 0 _scale_coordinates = function_mock(request, "histolab.tiler.scale_coordinates") random_tiler = RandomTiler((128, 128), 10, 0) random_tiler._random_tile_coordinates(slide) _box_mask_thumb.assert_called_once_with(slide) _tile_size.assert_has_calls([call((128, 128))]) _scale_coordinates.assert_called_once_with( reference_coords=CP(x_ul=0, y_ul=0, x_br=128, y_br=128), reference_size=(500, 500), target_size=(500, 500), )
def it_knows_if_it_has_only_some_tissue(self, tile_image, expected_value): tile = Tile(tile_image, CP(5, 5, 5, 5)) assert tile._has_only_some_tissue() == expected_value