Esempio n. 1
0
    def it_knows_its_biggest_tissue_box_mask(
        self,
        request,
        tmpdir,
        RgbToGrayscale_,
        OtsuThreshold_,
        BinaryDilation_,
        RemoveSmallHoles_,
        RemoveSmallObjects_,
    ):
        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")
        regions = [
            Region(index=0, area=33, bbox=(0, 0, 2, 2), center=(0.5, 0.5))
        ]
        main_tissue_areas_mask_filters_ = property_mock(
            request, Slide, "_main_tissue_areas_mask_filters")
        main_tissue_areas_mask_filters_.return_value = Compose([
            RgbToGrayscale_,
            OtsuThreshold_,
            BinaryDilation_,
            RemoveSmallHoles_,
            RemoveSmallObjects_,
        ])
        regions_from_binary_mask = function_mock(
            request, "histolab.slide.Slide._regions_from_binary_mask")
        regions_from_binary_mask.return_value = regions
        biggest_regions_ = function_mock(
            request, "histolab.slide.Slide._biggest_regions")
        biggest_regions_.return_value = regions
        region_coordinates_ = function_mock(
            request, "histolab.slide.Slide._region_coordinates")
        region_coordinates_.return_values = CoordinatePair(0, 0, 2, 2)
        polygon_to_mask_array_ = function_mock(
            request, "histolab.util.polygon_to_mask_array")
        polygon_to_mask_array_(
            (1000, 1000), CoordinatePair(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(slide, regions[0])
        biggest_regions_.assert_called_once_with(slide, regions, n=1)
        polygon_to_mask_array_.assert_called_once_with((1000, 1000),
                                                       CoordinatePair(x_ul=0,
                                                                      y_ul=0,
                                                                      x_br=2,
                                                                      y_br=2))
        np.testing.assert_almost_equal(biggest_mask_tissue_box.todense(),
                                       np.zeros((500, 500)))
Esempio n. 2
0
    def it_knows_its_coords(self):
        _coords = CoordinatePair(0, 0, 50, 50)
        tile = Tile(None, _coords, 0)

        coords = tile.coords

        assert coords == _coords
Esempio n. 3
0
    def it_knows_its_region_coordinates(self):
        region = Region(index=0, area=14, bbox=(0, 1, 1, 2), center=(0.5, 0.5))
        slide = Slide("a/b", "c/d")

        region_coords_ = slide._region_coordinates(region)

        assert region_coords_ == CoordinatePair(x_ul=1, y_ul=0, x_br=2, y_br=1)
Esempio n. 4
0
    def it_can_generate_random_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")
        _box_mask_lvl = method_mock(request, RandomTiler, "box_mask_lvl")
        _box_mask_lvl.return_value = SparseArrayMock.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_lvl.assert_called_once_with(random_tiler, slide)
        _tile_size.assert_has_calls([call((128, 128))])
        _scale_coordinates.assert_called_once_with(
            reference_coords=CoordinatePair(x_ul=0, y_ul=0, x_br=128,
                                            y_br=128),
            reference_size=(500, 500),
            target_size=(500, 500),
        )
Esempio n. 5
0
    def it_knows_if_is_is_almost_white(self, tile_img, expected_result):
        coords = CoordinatePair(0, 512, 0, 512)
        tile = Tile(tile_img, coords)

        is_almost_white = tile._is_almost_white

        assert is_almost_white == expected_result
Esempio n. 6
0
    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, CoordinatePair(0, 0, 50, 50), 0)
            tile.has_enough_tissue()

        assert isinstance(err.value, AttributeError)
        assert str(err.value) == "'NoneType' object has no attribute 'convert'"
Esempio n. 7
0
    def it_constructs_from_args(self, request):
        _init = initializer_mock(request, Tile)
        _image = PILIMG.RGBA_COLOR_50X50_155_0_0
        _level = 0
        _coords = CoordinatePair(0, 0, 50, 50)

        tile = Tile(_image, _coords, _level)

        _init.assert_called_once_with(ANY, _image, _coords, _level)
        assert isinstance(tile, Tile)
Esempio n. 8
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)
Esempio n. 9
0
class Describe_Slide(object):
    def it_constructs_from_args(self, request):
        _init_ = initializer_mock(request, Slide)
        _slide_path = "/foo/bar/myslide.svs"
        _processed_path = "/foo/bar/myslide/processed"

        slide = Slide(_slide_path, _processed_path)

        _init_.assert_called_once_with(ANY, _slide_path, _processed_path)
        assert isinstance(slide, Slide)

    def but_it_has_wrong_slide_path_type(self):
        """This test simulates a wrong user behaviour, using a None object instead of a
        str, or a path as slide_path param"""
        with pytest.raises(TypeError) as err:
            slide = Slide(None, "prc")
            slide.name

        assert isinstance(err.value, TypeError)
        assert (str(err.value) ==
                "expected str, bytes or os.PathLike object, not NoneType")

    def or_it_has_wrong_processed_path(self, request):
        """This test simulates a wrong user behaviour, using a None object instead of a
        str, or a path as processed_path param"""
        _resampled_dimensions = method_mock(request, Slide,
                                            "_resampled_dimensions")
        _resampled_dimensions.return_value = (1, 2, 3, 4)
        with pytest.raises(TypeError) as err:
            slide = Slide("path", None)
            slide.scaled_image_path(32)

        assert isinstance(err.value, TypeError)
        assert (str(err.value) ==
                "expected str, bytes or os.PathLike object, not NoneType")

    def it_generates_the_correct_breadcumb(self, request, breadcumb_fixture):
        (
            resampled_dims,
            dir_path,
            slide_path,
            proc_path,
            scale_factor,
            expected_path,
        ) = breadcumb_fixture
        _resampled_dimensions = method_mock(request, Slide,
                                            "_resampled_dimensions")
        _resampled_dimensions.return_value = resampled_dims
        slide = Slide(slide_path, proc_path)

        _breadcumb = slide._breadcumb(dir_path, scale_factor)

        assert _breadcumb == expected_path

    def it_knows_its_name(self, slide_name_fixture):
        _slide_path, expected_value = slide_name_fixture
        slide = Slide(_slide_path, "processed/")

        name = slide.name

        assert name == expected_value

    def it_knows_its_scaled_image_path(self, scaled_img_path_fixture,
                                       resampled_dims_):
        slide_path, proc_path, slide_dims, expected_value = scaled_img_path_fixture
        resampled_dims_.return_value = slide_dims
        slide = Slide(slide_path, proc_path)

        scaled_img_path = slide.scaled_image_path(scale_factor=22)

        assert scaled_img_path == expected_value

    def it_knows_its_thumbnails_path(self, resampled_dims_):
        slide_path, proc_path, slide_dims, expected_value = (
            "/foo/bar/myslide.svs",
            "/foo/bar/myslide/processed",
            (345, 111, 333, 444),
            "/foo/bar/myslide/processed/thumbnails/myslide.png",
        )
        resampled_dims_.return_value = slide_dims
        slide = Slide(slide_path, proc_path)

        thumbnail_path = slide.thumbnail_path

        assert thumbnail_path == expected_value

    def it_knows_its_wsi_extension(self, slide_ext_fixture):
        slide_path, expected_value = slide_ext_fixture
        slide = Slide(slide_path, "processed")

        _ext = slide._extension

        assert _ext == expected_value

    def it_knows_its_dimensions(self, 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")

        slide_dims = slide.dimensions

        assert slide_dims == (500, 500)

    def it_knows_its_resampled_dimensions(self, dimensions_):
        """This test prove that given the dimensions (mock object here), it does
        the correct maths operations:
            `large_w, large_h = self.dimensions`
            `new_w = math.floor(large_w / self._scale_factor)`
            `new_h = math.floor(large_h / self._scale_factor)`
            `return large_w, large_h, new_w, new_h`
        """
        dimensions_.return_value = (300, 500)
        slide = Slide("/a/b/foo", "processed")

        _resampled_dims = slide._resampled_dimensions(scale_factor=32)

        assert _resampled_dims == (300, 500, 9, 15)

    def but_it_raises_zero_division_error_when_scalefactor_is_0(
            self, dimensions_):
        """Considering the teset above, this one prove that a wrong behaviour of the
        user can cause a zerodivision error. In this case the scale_factor=0 generates
        the ZeroDivision Exception
        """
        dimensions_.return_value = (300, 500)
        slide = Slide("/a/b/foo", "processed")
        with pytest.raises(ZeroDivisionError) as err:
            slide._resampled_dimensions(scale_factor=0)

        assert isinstance(err.value, ZeroDivisionError)
        assert str(err.value) == "division by zero"

    def it_knows_its_resampled_array(self, tmpdir, resampled_dims_):
        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")
        resampled_dims_.return_value = (100, 200, 300, 400)

        resampled_array = slide.resampled_array(scale_factor=32)

        assert type(resampled_array) == np.ndarray
        assert resampled_array.shape == (400, 300, 3)

    def it_knows_its_thumbnail_size(self, 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")

        thumb_size = slide._thumbnail_size

        assert thumb_size == (500, 500)

    def it_creates_a_correct_slide_object(self, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILImageMock.DIMS_50X50_RGBA_COLOR_155_0_0
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")

        _wsi = slide._wsi

        assert type(_wsi) in (openslide.OpenSlide, openslide.ImageSlide)

    def but_it_raises_an_exception_if_file_not_found(self):
        with pytest.raises(FileNotFoundError) as err:
            slide = Slide("wrong/path/fake.wsi", "processed")
            slide._wsi

        assert isinstance(err.value, FileNotFoundError)
        assert str(err.value) == "The wsi path resource doesn't exist"

    def or_it_raises_an_PIL_exception(self, tmpdir):
        slide_path = tmpdir.mkdir("sub").join("hello.txt")
        slide_path.write("content")
        with pytest.raises(PIL.UnidentifiedImageError) as err:
            slide = Slide(os.path.join(slide_path), "processed")
            slide._wsi

        assert isinstance(err.value, PIL.UnidentifiedImageError)
        assert (str(err.value) ==
                f"cannot identify image file '{os.path.join(slide_path)}'")

    def it_can_resample_itself(self, tmpdir, resampled_dims_):
        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")
        resampled_dims_.return_value = (100, 200, 300, 400)

        _resample = slide._resample(32)

        # image array assertions
        assert type(_resample[1]) == np.ndarray
        # ---The np array shape should be (new_h X new_w X channels),---
        # ---in this case (look at resampled_dims mock) the new_h is 400---
        # ---the new_w is 300 and the color channels of the image are 3---
        assert _resample[1].shape == (400, 300, 3)
        # ---Here we prove that the 3 channels are compliant with the color---
        # ---definition and that each channel is a np.array (400x300) filled---
        # ---with the related color expressed during the image creation---
        np.testing.assert_almost_equal(_resample[1][:, :, 0],
                                       np.full((400, 300), 155))
        np.testing.assert_almost_equal(_resample[1][:, :, 1],
                                       np.full((400, 300), 249))
        np.testing.assert_almost_equal(_resample[1][:, :, 2],
                                       np.full((400, 300), 240))
        # PIL image assertions
        assert type(_resample[0]) == PIL.Image.Image
        assert _resample[0].size == (300, 400)
        assert _resample[0].width == 300
        assert _resample[0].height == 400
        assert _resample[0].mode == "RGB"

    def it_resamples_with_the_correct_scale_factor(self, tmpdir,
                                                   resampled_dims_):
        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")
        resampled_dims_.return_value = (500, 500, 15, 15)

        _resample = slide._resample(32)

        assert _resample[1].shape == (math.floor(500 / 32),
                                      math.floor(500 / 32), 3)

    def it_can_save_scaled_image(self, tmpdir, resampled_dims_):
        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, os.path.join(tmp_path_, "processed"))
        resampled_dims_.return_value = (100, 200, 300, 400)

        slide.save_scaled_image(32)

        assert slide.scaled_image_path(32) == os.path.join(
            tmp_path_, "processed", "mywsi-32x-100x200-300x400.png")
        assert os.path.exists(
            os.path.join(tmp_path_, slide.scaled_image_path(32)))

    def it_can_save_thumbnail(self, tmpdir, resampled_dims_):
        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, os.path.join(tmp_path_, "processed"))
        resampled_dims_.return_value = (100, 200, 300, 400)

        slide.save_thumbnail()

        assert slide.thumbnail_path == os.path.join(tmp_path_, "processed",
                                                    "thumbnails", "mywsi.png")
        assert os.path.exists(os.path.join(tmp_path_, slide.thumbnail_path))

    def it_knows_tissue_areas_mask_filters_composition(
        self,
        RgbToGrayscale_,
        OtsuThreshold_,
        BinaryDilation_,
        RemoveSmallHoles_,
        RemoveSmallObjects_,
    ):
        slide = Slide("/a/b", "c/d")

        main_tissue_areas_mask_filters_ = slide._main_tissue_areas_mask_filters

        RgbToGrayscale_.assert_called_once()
        OtsuThreshold_.assert_called_once()
        BinaryDilation_.assert_called_once()
        RemoveSmallHoles_.assert_called_once()
        RemoveSmallObjects_.assert_called_once()
        assert main_tissue_areas_mask_filters_.filters == [
            RgbToGrayscale_(),
            OtsuThreshold_(),
            BinaryDilation_(),
            RemoveSmallHoles_(),
            RemoveSmallObjects_(),
        ]

        assert type(main_tissue_areas_mask_filters_) == Compose

    def it_knows_regions_from_binary_mask(self, request):
        binary_mask = np.array([[True, False], [True, True]])
        label = function_mock(request, "histolab.slide.label")
        regionprops = function_mock(request, "histolab.slide.regionprops")
        RegionProps = namedtuple("RegionProps", ("area", "bbox", "centroid"))
        regions_props = [
            RegionProps(3, (0, 0, 2, 2),
                        (0.6666666666666666, 0.3333333333333333))
        ]
        regionprops.return_value = regions_props
        label(binary_mask).return_value = [[0, 1], [1, 1]]
        slide = Slide("/a/b", "c/d")

        regions_from_binary_mask_ = slide._regions_from_binary_mask(
            binary_mask)

        regionprops.assert_called_once_with(label(binary_mask))
        assert type(regions_from_binary_mask_) == list
        assert len(regions_from_binary_mask_) == 1
        assert type(regions_from_binary_mask_[0]) == Region
        assert regions_from_binary_mask_ == [
            Region(
                index=0,
                area=regions_props[0].area,
                bbox=regions_props[0].bbox,
                center=regions_props[0].centroid,
            )
        ]

    def it_knows_its_biggest_regions(self):
        regions = [
            Region(index=0, area=14, bbox=(0, 0, 2, 2), center=(0.5, 0.5)),
            Region(index=1, area=2, bbox=(0, 0, 2, 2), center=(0.5, 0.5)),
            Region(index=2, area=5, bbox=(0, 0, 2, 2), center=(0.5, 0.5)),
            Region(index=3, area=10, bbox=(0, 0, 2, 2), center=(0.5, 0.5)),
        ]
        slide = Slide("a/b", "c/d")

        biggest_regions = slide._biggest_regions(regions, 2)

        assert biggest_regions == [regions[0], regions[3]]

    @pytest.mark.parametrize("n", (0, 6))
    def but_it_raises_an_error_when_n_is_not_between_1_and_number_of_regions(
            self, n):
        regions = [
            Region(i, i + 1, (0, 0, 2, 2), (0.5, 0.5)) for i in range(4)
        ]
        slide = Slide("a/b", "c/d")
        with pytest.raises(ValueError) as err:
            slide._biggest_regions(regions, n)

        assert str(
            err.value) == f"n should be between 1 and {len(regions)}, got {n}"

    def it_knows_its_region_coordinates(self):
        region = Region(index=0, area=14, bbox=(0, 1, 1, 2), center=(0.5, 0.5))
        slide = Slide("a/b", "c/d")

        region_coords_ = slide._region_coordinates(region)

        assert region_coords_ == CoordinatePair(x_ul=1, y_ul=0, x_br=2, y_br=1)

    def it_knows_its_biggest_tissue_box_mask(
        self,
        request,
        tmpdir,
        RgbToGrayscale_,
        OtsuThreshold_,
        BinaryDilation_,
        RemoveSmallHoles_,
        RemoveSmallObjects_,
    ):
        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")
        regions = [
            Region(index=0, area=33, bbox=(0, 0, 2, 2), center=(0.5, 0.5))
        ]
        main_tissue_areas_mask_filters_ = property_mock(
            request, Slide, "_main_tissue_areas_mask_filters")
        main_tissue_areas_mask_filters_.return_value = Compose([
            RgbToGrayscale_,
            OtsuThreshold_,
            BinaryDilation_,
            RemoveSmallHoles_,
            RemoveSmallObjects_,
        ])
        regions_from_binary_mask = function_mock(
            request, "histolab.slide.Slide._regions_from_binary_mask")
        regions_from_binary_mask.return_value = regions
        biggest_regions_ = function_mock(
            request, "histolab.slide.Slide._biggest_regions")
        biggest_regions_.return_value = regions
        region_coordinates_ = function_mock(
            request, "histolab.slide.Slide._region_coordinates")
        region_coordinates_.return_values = CoordinatePair(0, 0, 2, 2)
        polygon_to_mask_array_ = function_mock(
            request, "histolab.util.polygon_to_mask_array")
        polygon_to_mask_array_(
            (1000, 1000), CoordinatePair(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(slide, regions[0])
        biggest_regions_.assert_called_once_with(slide, regions, n=1)
        polygon_to_mask_array_.assert_called_once_with((1000, 1000),
                                                       CoordinatePair(x_ul=0,
                                                                      y_ul=0,
                                                                      x_br=2,
                                                                      y_br=2))
        np.testing.assert_almost_equal(biggest_mask_tissue_box.todense(),
                                       np.zeros((500, 500)))

    @pytest.mark.skipif(not on_ci() or is_win32(),
                        reason="Only run on CIs; hangs on Windows CIs")
    def it_can_show_its_thumbnail(self, 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")

        slide.save_thumbnail()

        assert ImageShow.show(PIL.Image.open(slide.thumbnail_path))

    def but_it_raises_error_when_it_doesnt_exist(self):
        slide = Slide("a/b", "processed")

        with pytest.raises(FileNotFoundError) as err:
            slide.show()

        assert (str(err.value) ==
                "Cannot display the slide thumbnail:[Errno 2] No such file or "
                "directory: 'processed/thumbnails/b.png'")

    def it_knows_its_level_dimensions(self, 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")

        level_dimensions = slide.level_dimensions(level=0)

        assert level_dimensions == (500, 500)

    def but_it_raises_expection_when_level_does_not_exist(self, 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")
        with pytest.raises(ValueError) as err:
            slide.level_dimensions(level=3)

        assert str(err.value
                   ) == "Level 3 not available. Number of available levels: 1"

    def it_knows_if_coords_are_valid(self, valid_coords_fixture, tmpdir):
        coords, expected_result = valid_coords_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")

        _are_valid = slide._are_valid_coords(coords)

        assert type(_are_valid) == bool
        assert _are_valid == expected_result

    # fixtures -------------------------------------------------------

    @pytest.fixture(params=[("/a/b/mywsi.svs", ".svs"),
                            ("/a/b/mywsi.34s", ".34s")])
    def slide_ext_fixture(self, request):
        slide_path, expected_value = request.param
        return slide_path, expected_value

    @pytest.fixture(params=[
        (
            "/foo/bar/myslide.svs",
            "/foo/bar/myslide/processed",
            (345, 111, 333, 444),
            "/foo/bar/myslide/processed/myslide-22x-345x111-333x444.png",
        ),
        (
            "/foo/bar/myslide2.svs",
            "/foo/bar/myslide/processed",
            (345, 111, None, None),
            "/foo/bar/myslide/processed/myslide2-22x-345x111-NonexNone.png",
        ),
        (
            "/foo/bar/myslide2.svs",
            "/foo/bar/myslide/processed",
            (345, 111, 123, 123),
            "/foo/bar/myslide/processed/myslide2-22x-345x111-123x123.png",
        ),
        (
            "/foo/bar/myslide2.svs",
            "/foo/bar/myslide/processed",
            (None, None, None, None),
            "/foo/bar/myslide/processed/myslide2*.png",
        ),
    ])
    def scaled_img_path_fixture(self, request):
        slide_path, proc_path, slide_dims, expected_value = request.param
        return slide_path, proc_path, slide_dims, expected_value

    @pytest.fixture(params=[
        (
            (245, 123, 145, 99),
            "/foo/bar/b/0/9",
            "/foo/bar/myslide.svs",
            "processed",
            64,
            "/foo/bar/b/0/9/myslide-64x-245x123-145x99.png",
        ),
        (
            (245, 123, 145, 99),
            "/foo/bar/b/0/9",
            "/foo/bar/myslide.svs",
            "processed",
            32,
            "/foo/bar/b/0/9/myslide-32x-245x123-145x99.png",
        ),
        (
            (None, None, None, None),
            "/foo/bar/b/0/9",
            "/foo/bar/myslide.svs",
            "processed",
            64,
            "/foo/bar/b/0/9/myslide*.png",
        ),
        (
            (None, 234, 192, None),
            "/foo/bar/b/0/9",
            "/foo/bar/myslide.svs",
            "processed",
            64,
            "/foo/bar/b/0/9/myslide-64x-Nonex234-192xNone.png",
        ),
        (
            (123, 234, 192, None),
            "/foo/bar/b/0/9",
            "/foo/bar/myslide.svs",
            "processed",
            64,
            "/foo/bar/b/0/9/myslide-64x-123x234-192xNone.png",
        ),
        (
            (None, None, 192, None),
            "/foo/bar/b/0/9",
            "/foo/bar/myslide.svs",
            "processed",
            64,
            "/foo/bar/b/0/9/myslide-64x-NonexNone-192xNone.png",
        ),
    ])
    def breadcumb_fixture(self, request):
        (
            resampled_dims,
            dir_path,
            slide_path,
            proc_path,
            scale_factor,
            expected_path,
        ) = request.param
        return (
            resampled_dims,
            dir_path,
            slide_path,
            proc_path,
            scale_factor,
            expected_path,
        )

    @pytest.fixture(params=[("/foo/bar/myslide.svs", "myslide"),
                            ("/foo/myslide.svs", "myslide")])
    def slide_name_fixture(self, request):
        slide_path, expceted_value = request.param
        return slide_path, expceted_value

    @pytest.fixture(params=[
        (CoordinatePair(0, 128, 0, 128), True),
        (CoordinatePair(800000, 90000, 8000010, 90010), False),
        (CoordinatePair(800000, 90000, -1, 90010), False),
    ])
    def valid_coords_fixture(self, request):
        coords, expected_result = request.param
        return coords, expected_result

    # fixture components ---------------------------------------------

    @pytest.fixture
    def resampled_dims_(self, request):
        return method_mock(request, Slide, "_resampled_dimensions")

    @pytest.fixture
    def dimensions_(self, request):
        return property_mock(request, Slide, "dimensions")

    @pytest.fixture
    def RgbToGrayscale_(self, request):
        return class_mock(request,
                          "histolab.filters.image_filters.RgbToGrayscale")

    @pytest.fixture
    def OtsuThreshold_(self, request):
        return class_mock(request,
                          "histolab.filters.image_filters.OtsuThreshold")

    @pytest.fixture
    def BinaryDilation_(self, request):
        return class_mock(
            request, "histolab.filters.morphological_filters.BinaryDilation")

    @pytest.fixture
    def RemoveSmallHoles_(self, request):
        return class_mock(
            request, "histolab.filters.morphological_filters.RemoveSmallHoles")

    @pytest.fixture
    def RemoveSmallObjects_(self, request):
        return class_mock(
            request,
            "histolab.filters.morphological_filters.RemoveSmallObjects")
Esempio n. 10
0
class Describe_GridTiler(object):
    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)

    def but_it_has_wrong_tile_size_value(self, request):
        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))"

    def or_it_has_not_available_level_value(self, request, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILImageMock.DIMS_50X50_RGB_RANDOM_COLOR
        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((512, 512), 3)

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

        assert isinstance(err.value, ValueError)
        assert str(err.value
                   ) == "Level 3 not available. Number of available levels: 1"

    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)"

    @pytest.mark.parametrize("tile_size", ((512, 512), (128, 128), (10, 10)))
    def it_knows_its_tile_size(self, request, tile_size):
        grid_tiler = GridTiler(tile_size, 10, 0)

        tile_size_ = grid_tiler.tile_size

        assert type(tile_size_) == tuple
        assert tile_size_ == tile_size

    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

    @pytest.mark.parametrize(
        "check_tissue, expected_box",
        (
            (False, SparseArrayMock.ONES_500X500_BOOL),
            (True, SparseArrayMock.RANDOM_500X500_BOOL),
        ),
    )
    def it_knows_its_box_mask(self, request, tmpdir, check_tissue,
                              expected_box):
        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")
        _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) == sparse._coo.core.COO
        np.testing.assert_array_almost_equal(box_mask.todense(),
                                             expected_box.todense())

    @pytest.mark.parametrize(
        "bbox_coordinates, pixel_overlap, expected_n_tiles_row",
        (
            (CoordinatePair(x_ul=0, y_ul=0, x_br=6060, y_br=1917), 0, 11),
            (CoordinatePair(x_ul=0, y_ul=0, x_br=1921, y_br=2187), 0, 3),
            (CoordinatePair(x_ul=0, y_ul=0, x_br=1921, y_br=2187), 128, 5),
            (CoordinatePair(x_ul=0, y_ul=0, x_br=1921, y_br=2187), -128, 3),
        ),
    )
    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

    @pytest.mark.parametrize(
        "bbox_coordinates, pixel_overlap, expected_n_tiles_column",
        (
            (CoordinatePair(x_ul=0, y_ul=0, x_br=6060, y_br=1917), 0, 3),
            (CoordinatePair(x_ul=0, y_ul=0, x_br=6060, y_br=1917), -1, 3),
            (CoordinatePair(x_ul=0, y_ul=0, x_br=1921, y_br=2187), 0, 4),
            (CoordinatePair(x_ul=0, y_ul=0, x_br=1921, y_br=2187), 128, 5),
        ),
    )
    def it_can_calculate_n_tiles_column(self, request, bbox_coordinates,
                                        pixel_overlap,
                                        expected_n_tiles_column):
        grid_tiler = GridTiler((512, 512), 2, True, 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

    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 == []

    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)

    # fixtures -------------------------------------------------------

    @pytest.fixture(params=(
        (
            (512, 512),
            3,
            True,
            0,
            "",
            ".png",
            CoordinatePair(0, 512, 0, 512),
            3,
            "tile_3_level3_0-512-0-512.png",
        ),
        (
            (512, 512),
            0,
            True,
            0,
            "folder/",
            ".png",
            CoordinatePair(4, 127, 4, 127),
            10,
            "folder/tile_10_level0_4-127-4-127.png",
        ),
    ))
    def tile_filename_fixture(self, request):
        (
            tile_size,
            level,
            check_tissue,
            pixel_overlap,
            prefix,
            suffix,
            tile_coords,
            tiles_counter,
            expected_filename,
        ) = request.param
        return (
            tile_size,
            level,
            check_tissue,
            pixel_overlap,
            prefix,
            suffix,
            tile_coords,
            tiles_counter,
            expected_filename,
        )

    @pytest.fixture(params=(
        (
            CoordinatePair(0, 10, 0, 10),
            CoordinatePair(0, 10, 0, 10),
            True,
            [True, True],
            2,
        ),
        (
            CoordinatePair(0, 10, 0, 10),
            CoordinatePair(0, 10, 0, 10),
            False,
            [True, True],
            2,
        ),
        (
            CoordinatePair(0, 10, 0, 10),
            CoordinatePair(0, 10, 0, 10),
            False,
            [False, False],
            2,
        ),
        (
            CoordinatePair(0, 10, 0, 10),
            CoordinatePair(0, 10, 0, 10),
            True,
            [False, False],
            0,
        ),
        (
            CoordinatePair(0, 10, 0, 10),
            CoordinatePair(0, 10, 0, 10),
            True,
            [True, False],
            1,
        ),
    ))
    def grid_tiles_fixture(self, request):
        (
            coords1,
            coords2,
            check_tissue,
            has_enough_tissue,
            expected_n_tiles,
        ) = request.param
        return (
            coords1,
            coords2,
            check_tissue,
            has_enough_tissue,
            expected_n_tiles,
        )
Esempio n. 11
0
class Describe_RandomTiler(object):
    def it_constructs_from_args(self, request):
        _init = initializer_mock(request, RandomTiler)

        random_tiler = RandomTiler((512, 512), 10, 2, 7, True, "", ".png", 1e4)

        _init.assert_called_once_with(ANY, (512, 512), 10, 2, 7, True, "",
                                      ".png", 1e4)
        assert isinstance(random_tiler, RandomTiler)
        assert isinstance(random_tiler, Tiler)

    def but_it_has_wrong_tile_size_value(self, request):
        with pytest.raises(ValueError) as err:
            RandomTiler((512, -1), 10, 0)

        assert isinstance(err.value, ValueError)
        assert str(err.value) == "Tile size must be greater than 0 ((512, -1))"

    def or_it_has_not_available_level_value(self, request, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILImageMock.DIMS_50X50_RGB_RANDOM_COLOR
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        random_tiler = RandomTiler((512, 512), 10, 3)

        with pytest.raises(ValueError) as err:
            random_tiler.extract(slide)

        assert isinstance(err.value, ValueError)
        assert str(err.value
                   ) == "Level 3 not available. Number of available levels: 1"

    def or_it_has_negative_level_value(self, request):
        with pytest.raises(ValueError) as err:
            RandomTiler((512, 512), 10, -1)

        assert isinstance(err.value, ValueError)
        assert str(err.value) == "Level cannot be negative (-1)"

    def or_it_has_wrong_max_iter(self, request):
        with pytest.raises(ValueError) as err:
            RandomTiler((512, 512), 10, 0, max_iter=3)

        assert isinstance(err.value, ValueError)
        assert (
            str(err.value) ==
            "The maximum number of iterations (3) must be grater than or equal to the maximum number of tiles (10)."
        )

    def or_it_has_wrong_seed(self, request, tmpdir):
        tmp_path_ = tmpdir.mkdir("myslide")
        image = PILImageMock.DIMS_50X50_RGB_RANDOM_COLOR
        image.save(os.path.join(tmp_path_, "mywsi.png"), "PNG")
        slide_path = os.path.join(tmp_path_, "mywsi.png")
        slide = Slide(slide_path, "processed")
        random_tiler = RandomTiler((512, 512), 10, 0, seed=-1)

        with pytest.raises(ValueError) as err:
            random_tiler.extract(slide)

        assert isinstance(err.value, ValueError)
        assert str(err.value) == "Seed must be between 0 and 2**32 - 1"

    @pytest.mark.parametrize("tile_size", ((512, 512), (128, 128), (10, 10)))
    def it_knows_its_tile_size(self, request, tile_size):
        random_tiler = RandomTiler(tile_size, 10, 0)

        tile_size_ = random_tiler.tile_size

        assert type(tile_size_) == tuple
        assert tile_size_ == tile_size

    @pytest.mark.parametrize("max_iter", (1000, 10, 3000))
    def it_knows_its_max_iter(self, request, max_iter):
        random_tiler = RandomTiler((128, 128), 10, 0, max_iter=max_iter)

        max_iter_ = random_tiler.max_iter

        assert type(max_iter_) == int
        assert max_iter_ == max_iter

    def it_knows_its_tile_filename(self, request, tile_filename_fixture):
        (
            tile_size,
            n_tiles,
            level,
            seed,
            check_tissue,
            prefix,
            suffix,
            tile_coords,
            tiles_counter,
            expected_filename,
        ) = tile_filename_fixture
        random_tiler = RandomTiler(tile_size, n_tiles, level, seed,
                                   check_tissue, prefix, suffix)

        _filename = random_tiler._tile_filename(tile_coords, tiles_counter)

        assert type(_filename) == str
        assert _filename == expected_filename

    def it_can_generate_random_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")
        _box_mask_lvl = method_mock(request, RandomTiler, "box_mask_lvl")
        _box_mask_lvl.return_value = SparseArrayMock.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_lvl.assert_called_once_with(random_tiler, slide)
        _tile_size.assert_has_calls([call((128, 128))])
        _scale_coordinates.assert_called_once_with(
            reference_coords=CoordinatePair(x_ul=0, y_ul=0, x_br=128,
                                            y_br=128),
            reference_size=(500, 500),
            target_size=(500, 500),
        )

    @pytest.mark.parametrize(
        "check_tissue, expected_box",
        (
            (False, SparseArrayMock.RANDOM_500X500_BOOL),
            (True, SparseArrayMock.RANDOM_500X500_BOOL),
        ),
    )
    def it_knows_its_box_mask(self, request, tmpdir, check_tissue,
                              expected_box):
        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")
        _biggest_tissue_box_mask = property_mock(request, Slide,
                                                 "biggest_tissue_box_mask")
        _biggest_tissue_box_mask.return_value = expected_box
        random_tiler = RandomTiler((128, 128),
                                   10,
                                   0,
                                   check_tissue=check_tissue)

        box_mask = random_tiler.box_mask(slide)

        _biggest_tissue_box_mask.assert_called_once_with()
        assert type(box_mask) == sparse._coo.core.COO
        np.testing.assert_array_almost_equal(box_mask.todense(),
                                             expected_box.todense())

    @pytest.mark.parametrize(
        "coords1, coords2, check_tissue, has_enough_tissue, max_iter, expected_n_tiles",
        (
            (
                CoordinatePair(0, 10, 0, 10),
                CoordinatePair(0, 10, 0, 10),
                True,
                [True, True],
                10,
                2,
            ),
            (
                CoordinatePair(0, 10, 0, 10),
                CoordinatePair(0, 10, 0, 10),
                True,
                [True, False],
                2,
                1,
            ),
            (
                CoordinatePair(0, 10, 0, 10),
                CoordinatePair(5900, 6000, 5900, 6000),  # wrong coordinates
                True,
                [True, True],
                2,
                2,
            ),
            (
                CoordinatePair(0, 10, 0, 10),
                CoordinatePair(0, 10, 0, 10),
                False,
                [True, True],
                10,
                2,
            ),
            (
                CoordinatePair(0, 10, 0, 10),
                CoordinatePair(0, 10, 0, 10),
                False,
                [False, False],
                10,
                2,
            ),
            (
                CoordinatePair(0, 10, 0, 10),
                CoordinatePair(0, 10, 0, 10),
                True,
                [False, False],
                10,
                0,
            ),
        ),
    )
    def it_can_generate_random_tiles(
        self,
        request,
        tmpdir,
        coords1,
        coords2,
        check_tissue,
        has_enough_tissue,
        max_iter,
        expected_n_tiles,
    ):
        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 * (max_iter // 2)
        _random_tile_coordinates = method_mock(request, RandomTiler,
                                               "_random_tile_coordinates")
        _random_tile_coordinates.side_effect = [coords1, coords2
                                                ] * (max_iter // 2)
        tile1 = Tile(image, coords1)
        tile2 = Tile(image, coords2)
        _extract_tile.side_effect = [tile1, tile2] * (max_iter // 2)
        random_tiler = RandomTiler((10, 10),
                                   2,
                                   level=0,
                                   max_iter=max_iter,
                                   check_tissue=check_tissue)

        generated_tiles = list(random_tiler._random_tiles_generator(slide))

        _random_tile_coordinates.assert_called_with(random_tiler, slide)
        assert _random_tile_coordinates.call_count <= random_tiler.max_iter

        _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)]

    @pytest.mark.parametrize(
        "level, box_mask, expected_box_mask_lvl",
        (
            (
                0,
                SparseArrayMock.RANDOM_500X500_BOOL,
                SparseArrayMock.RANDOM_500X500_BOOL,
            ),  # TODO: use image with more than 1 level
        ),
    )
    def it_knows_its_box_mask_lvl(self, request, tmpdir, level, box_mask,
                                  expected_box_mask_lvl):
        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")
        _box_mask = method_mock(request, RandomTiler, "box_mask")
        _box_mask.return_value = box_mask
        random_tiler = RandomTiler((128, 128), 10, level)

        box_mask_lvl = random_tiler.box_mask_lvl(slide)

        assert type(box_mask_lvl) == sparse._coo.core.COO
        np.testing.assert_array_almost_equal(box_mask_lvl.todense(),
                                             expected_box_mask_lvl.todense())

    # fixtures -------------------------------------------------------

    @pytest.fixture(params=(
        (
            (512, 512),
            10,
            3,
            7,
            True,
            "",
            ".png",
            CoordinatePair(0, 512, 0, 512),
            3,
            "tile_3_level3_0-512-0-512.png",
        ),
        (
            (512, 512),
            10,
            0,
            7,
            True,
            "folder/",
            ".png",
            CoordinatePair(4, 127, 4, 127),
            10,
            "folder/tile_10_level0_4-127-4-127.png",
        ),
    ))
    def tile_filename_fixture(self, request):
        (
            tile_size,
            n_tiles,
            level,
            seed,
            check_tissue,
            prefix,
            suffix,
            tile_coords,
            tiles_counter,
            expected_filename,
        ) = request.param
        return (
            tile_size,
            n_tiles,
            level,
            seed,
            check_tissue,
            prefix,
            suffix,
            tile_coords,
            tiles_counter,
            expected_filename,
        )
Esempio n. 12
0
def test_scale_coordinates(ref_coords, ref_size, target_size, expected_value):
    x_ul, y_ul, x_br, y_br = expected_value

    scaled_coords = scale_coordinates(ref_coords, ref_size, target_size)

    assert scaled_coords == CoordinatePair(x_ul, y_ul, x_br, y_br)
Esempio n. 13
0
def test_region_coordinates():
    region = Region(index=0, area=14, bbox=(0, 1, 1, 2), center=(0.5, 0.5))
    region_coords_ = region_coordinates(region)

    assert region_coords_ == CoordinatePair(x_ul=1, y_ul=0, x_br=2, y_br=1)
Esempio n. 14
0
    lazyproperty,
    np_to_pil,
    polygon_to_mask_array,
    region_coordinates,
    resize_mask,
    scale_coordinates,
    threshold_to_mask,
)

from ..util import load_expectation


@pytest.mark.parametrize(
    "ref_coords, ref_size, target_size, expected_value",
    (
        (CoordinatePair(0, 2, 4, 5), (10, 10), (5, 5), (0, 1, 2, 2)),
        (CoordinatePair(90, 112, 124, 125), (100, 100), (95, 95),
         (85, 106, 117, 118)),
    ),
)
def test_scale_coordinates(ref_coords, ref_size, target_size, expected_value):
    x_ul, y_ul, x_br, y_br = expected_value

    scaled_coords = scale_coordinates(ref_coords, ref_size, target_size)

    assert scaled_coords == CoordinatePair(x_ul, y_ul, x_br, y_br)


@pytest.mark.parametrize(
    "img_array, expected_mode, expected_size, expected_type, expected_array",
    (