Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[TEST] add test for WholeSlideImagePatches class #151

Open
kaczmarj opened this issue Jul 18, 2023 · 0 comments
Open

[TEST] add test for WholeSlideImagePatches class #151

kaczmarj opened this issue Jul 18, 2023 · 0 comments
Labels
help wanted Extra attention is needed test Create a test for this issue

Comments

@kaczmarj
Copy link
Member

kaczmarj commented Jul 18, 2023

add tests for the torch dataset child class WholeSlideImagePatches.

class WholeSlideImagePatches(torch.utils.data.Dataset):
"""Dataset of one whole slide image.
This object retrieves patches from a whole slide image on the fly.
Parameters
----------
wsi_path : str, Path
Path to whole slide image file.
patch_path : str, Path
Path to npy file with coordinates of input image.
um_px : float
Scale of the resulting patches. For example, 0.5 for ~20x magnification.
patch_size : int
The size of patches in pixels.
transform : callable, optional
A callable to modify a retrieved patch. The callable must accept a
PIL.Image.Image instance and return a torch.Tensor.
roi_path : str, Path, optional
Path to GeoJSON file that outlines the region of interest (ROI). Only patches
within the ROI(s) will be used.
"""
def __init__(
self,
wsi_path: str | Path,
patch_path: str | Path,
um_px: float,
patch_size: int,
transform: Optional[Callable[[Image.Image], torch.Tensor]] = None,
roi_path: Optional[str | Path] = None,
):
self.wsi_path = wsi_path
self.patch_path = patch_path
self.um_px = float(um_px)
self.patch_size = int(patch_size)
self.transform = transform
self.roi_path = roi_path
assert Path(wsi_path).exists(), "wsi path not found"
assert Path(patch_path).exists(), "patch path not found"
if roi_path is not None:
assert Path(roi_path).exists(), "roi path not found"
self.patches = _read_patch_coords(self.patch_path)
# If an ROI is given, keep patches that intersect it.
if self.roi_path is not None:
self.patches = _filter_patches_in_rois(
geojson_path=self.roi_path, coords=self.patches
)
if self.patches.shape[0] == 0:
raise ValueError("No patches left after taking intersection with ROI")
assert self.patches.ndim == 2, "expected 2D array of patch coordinates"
# x, y, width, height
assert self.patches.shape[1] == 4, "expected second dimension to have len 4"
def worker_init(self, *_):
self.slide = WSI(self.wsi_path)
def __len__(self):
return self.patches.shape[0]
def __getitem__(
self, idx: int
) -> Tuple[Union[Image.Image, torch.Tensor], torch.Tensor]:
coords: Sequence[int] = self.patches[idx]
assert len(coords) == 4, "expected 4 coords (minx, miny, width, height)"
minx, miny, width, height = coords
patch_im = self.slide.read_region(
location=(minx, miny), level=0, size=(width, height)
)
patch_im = patch_im.convert("RGB")
if self.transform is not None:
patch_im = self.transform(patch_im)
return patch_im, torch.as_tensor([minx, miny, width, height])

you may want to create your own reference tiff image, as in

def tiff_image(tmp_path: Path) -> Path:
x = np.empty((4096, 4096, 3), dtype="uint8")
x[...] = [160, 32, 240] # rgb for purple
path = Path(tmp_path / "images" / "purple.tif")
path.parent.mkdir(exist_ok=True)
tifffile.imwrite(
path,
data=x,
compression="zlib",
tile=(256, 256),
# 0.25 micrometers per pixel.
resolution=(40_000, 40_000),
resolutionunit=tifffile.RESUNIT.CENTIMETER,
)
return path

@kaczmarj kaczmarj added the test Create a test for this issue label Jul 18, 2023
@kaczmarj kaczmarj added the help wanted Extra attention is needed label Feb 22, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
help wanted Extra attention is needed test Create a test for this issue
Projects
None yet
Development

No branches or pull requests

1 participant