| |
| |
| |
|
|
| import atexit |
| from collections import OrderedDict |
| from typing import Any, Tuple |
|
|
| from .extended import ExtendedVisionDataset |
| from pathlib import Path |
| from openslide import OpenSlide |
| import numpy as np |
| import cv2 |
|
|
| _SLIDE_CACHE: "OrderedDict[str, OpenSlide]" = OrderedDict() |
| _SLIDE_CACHE_LIMIT = 512 |
|
|
|
|
| def _close_all_slides(): |
| for slide in _SLIDE_CACHE.values(): |
| slide.close() |
| _SLIDE_CACHE.clear() |
|
|
|
|
| atexit.register(_close_all_slides) |
|
|
|
|
| class SlideDataset(ExtendedVisionDataset): |
| def __init__(self, root, sample_list_path, *args, **kwargs) -> None: |
| super().__init__(root, *args, **kwargs) |
| self.sample_list_path = Path(sample_list_path) |
| if not self.sample_list_path.is_file(): |
| raise FileNotFoundError(f"Sample list not found at {self.sample_list_path}") |
|
|
| with self.sample_list_path.open("r") as f: |
| self.image_files = [line.strip() for line in f if line.strip()] |
|
|
| print(f"This many resolved paths {len(self.image_files)} from {self.sample_list_path}") |
|
|
| def get_all(self, index): |
| parts = self.image_files[index].split(" ") |
| path = parts[0] |
| image = _SLIDE_CACHE.get(path) |
| if image is None: |
| image = OpenSlide(path) |
| _SLIDE_CACHE[path] = image |
| if len(_SLIDE_CACHE) > _SLIDE_CACHE_LIMIT: |
| _, old = _SLIDE_CACHE.popitem(last=False) |
| old.close() |
| else: |
| _SLIDE_CACHE.move_to_end(path) |
| return image, path |
|
|
| def __getitem__(self, index: int) -> Tuple[Any, Any]: |
| path = self.image_files[index] |
| parts = path.split(" ") |
| path, x, y, level = parts |
| x = int(x) |
| y = int(y) |
| level = int(level) |
|
|
| image = _SLIDE_CACHE.get(path) |
| if image is None: |
| image = OpenSlide(path) |
| _SLIDE_CACHE[path] = image |
| if len(_SLIDE_CACHE) > _SLIDE_CACHE_LIMIT: |
| _, old = _SLIDE_CACHE.popitem(last=False) |
| old.close() |
| else: |
| _SLIDE_CACHE.move_to_end(path) |
|
|
| patch_size = 224 |
|
|
| patch = image.read_region((x, y), level=level, size=(patch_size, patch_size)) |
|
|
| res = patch.convert("RGB") |
| if self.transforms is not None: |
| return self.transforms(res, None), index |
|
|
| return res, None, index |
| |
| def hsv(self, tile_rgb, patch_size): |
| tile = np.array(tile_rgb) |
| tile = cv2.cvtColor(tile, cv2.COLOR_RGB2HSV) |
| min_ratio = .6 |
| |
| lower_bound = np.array([90, 8, 103]) |
| upper_bound = np.array([180, 255, 255]) |
|
|
| mask = cv2.inRange(tile, lower_bound, upper_bound) |
|
|
| ratio = np.count_nonzero(mask) / mask.size |
| if ratio > min_ratio: |
| return tile_rgb |
| else: |
| return None |
|
|
| def __len__(self) -> int: |
| return len(self.image_files) |
|
|