torch_em.data.datasets.histopathology.glysac
The GLySAC dataset contains annotations for nuclei instance segmentation and classification in H&E stained gastric cancer histopathology images.
The dataset contains 59 image tiles of size 1000x1000 pixels with instance segmentation masks and cell type annotations. Three cell classes are provided: lymphocytes, epithelial cells (normal and tumor), and other cells.
NOTE: The dataset is hosted on Google Drive and requires gdown to download. Install it with: conda install -c conda-forge gdown==4.6.3
The dataset is located at https://drive.google.com/file/d/1g1_xYFWgp3cRLKrlSwD2U5JDjooC0yHp/view This dataset is from the publication https://doi.org/10.1109/jbhi.2022.3149936. Please cite it if you use this dataset in your research.
1"""The GLySAC dataset contains annotations for nuclei instance segmentation and 2classification in H&E stained gastric cancer histopathology images. 3 4The dataset contains 59 image tiles of size 1000x1000 pixels with instance 5segmentation masks and cell type annotations. Three cell classes are provided: 6lymphocytes, epithelial cells (normal and tumor), and other cells. 7 8NOTE: The dataset is hosted on Google Drive and requires gdown to download. 9Install it with: conda install -c conda-forge gdown==4.6.3 10 11The dataset is located at https://drive.google.com/file/d/1g1_xYFWgp3cRLKrlSwD2U5JDjooC0yHp/view 12This dataset is from the publication https://doi.org/10.1109/jbhi.2022.3149936. 13Please cite it if you use this dataset in your research. 14""" 15 16import os 17from glob import glob 18from tqdm import tqdm 19from natsort import natsorted 20from typing import List, Literal, Tuple, Union 21 22import h5py 23import imageio.v3 as imageio 24from scipy.io import loadmat 25from torch.utils.data import Dataset, DataLoader 26 27import torch_em 28 29from .. import util 30 31 32GDRIVE_ID = "1g1_xYFWgp3cRLKrlSwD2U5JDjooC0yHp" 33URL = f"https://drive.google.com/uc?id={GDRIVE_ID}" 34CHECKSUM = None 35 36 37def _find_split_dir(data_dir: str, split: str) -> str: 38 """Resolve the split folder. Distributions of this dataset differ in capitalization.""" 39 for folder in (split.capitalize(), split, split.upper()): 40 candidate = os.path.join(data_dir, folder) 41 if os.path.exists(candidate): 42 return candidate 43 raise RuntimeError(f"Could not find a folder for split '{split}' in '{data_dir}'.") 44 45 46def _create_h5_files(data_dir: str, split: str) -> None: 47 split_dir = _find_split_dir(data_dir, split) 48 image_dir = os.path.join(split_dir, "Images") 49 label_dir = os.path.join(split_dir, "Labels") 50 h5_dir = os.path.join(data_dir, "h5", split) 51 os.makedirs(h5_dir, exist_ok=True) 52 53 # Distributions of this dataset ship the images either as png or as tif. 54 image_paths = natsorted(glob(os.path.join(image_dir, "*.png")) + glob(os.path.join(image_dir, "*.tif"))) 55 for image_path in tqdm(image_paths, desc=f"Preprocessing {split}"): 56 fname = os.path.splitext(os.path.basename(image_path))[0] 57 h5_path = os.path.join(h5_dir, f"{fname}.h5") 58 if os.path.exists(h5_path): 59 continue 60 61 label_path = os.path.join(label_dir, f"{fname}.mat") 62 raw = imageio.imread(image_path)[..., :3] 63 mat = loadmat(label_path) 64 inst_map = mat["inst_map"].astype("int32") 65 type_map = mat["type_map"].astype("int32") 66 67 with h5py.File(h5_path, "w") as f: 68 f.create_dataset("raw", data=raw.transpose(2, 0, 1), compression="gzip") 69 f.create_dataset("labels/instances", data=inst_map, compression="gzip") 70 f.create_dataset("labels/semantic", data=type_map, compression="gzip") 71 72 73def get_glysac_data(path: Union[os.PathLike, str], download: bool = False) -> str: 74 """Download the GLySAC dataset. 75 76 Args: 77 path: Filepath to a folder where the downloaded data will be saved. 78 download: Whether to download the data if it is not present. 79 80 Returns: 81 The filepath to the data directory. 82 """ 83 # Distributions of this dataset unpack either as 'glysac_dataset' or as 'GLySAC'. 84 for folder in ("glysac_dataset", "GLySAC"): 85 data_dir = os.path.join(path, folder) 86 if os.path.exists(data_dir): 87 return data_dir 88 89 data_dir = os.path.join(path, "glysac_dataset") 90 91 os.makedirs(path, exist_ok=True) 92 zip_path = os.path.join(path, "glysac_dataset.zip") 93 util.download_source_gdrive(path=zip_path, url=URL, download=download, checksum=CHECKSUM) 94 util.unzip(zip_path, path) 95 96 return data_dir 97 98 99def get_glysac_paths( 100 path: Union[os.PathLike, str], 101 split: Literal["train", "test"], 102 download: bool = False, 103) -> List[str]: 104 """Get paths to the GLySAC data. 105 106 Args: 107 path: Filepath to a folder where the downloaded data will be saved. 108 split: The data split to use. Either 'train' or 'test'. 109 download: Whether to download the data if it is not present. 110 111 Returns: 112 List of filepaths for the h5 data. 113 """ 114 if split not in ("train", "test"): 115 raise ValueError(f"'{split}' is not a valid split. Choose from 'train' or 'test'.") 116 117 data_dir = get_glysac_data(path, download) 118 _create_h5_files(data_dir, split) 119 120 h5_paths = natsorted(glob(os.path.join(data_dir, "h5", split, "*.h5"))) 121 if len(h5_paths) == 0: 122 raise RuntimeError(f"No data found for split '{split}'. Check the dataset at {data_dir}.") 123 124 return h5_paths 125 126 127def get_glysac_dataset( 128 path: Union[os.PathLike, str], 129 patch_shape: Tuple[int, int], 130 split: Literal["train", "test"], 131 label_choice: Literal["instances", "semantic"] = "instances", 132 download: bool = False, 133 **kwargs, 134) -> Dataset: 135 """Get the GLySAC dataset for gastric nuclei segmentation. 136 137 Args: 138 path: Filepath to a folder where the downloaded data will be saved. 139 patch_shape: The patch shape to use for training. 140 split: The data split to use. Either 'train' or 'test'. 141 label_choice: The type of labels to load. Either 'instances' for instance segmentation 142 or 'semantic' for cell type classification (4 classes: other, lymphocyte, epithelial, ambiguous). 143 download: Whether to download the data if it is not present. 144 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 145 146 Returns: 147 The segmentation dataset. 148 """ 149 if label_choice not in ("instances", "semantic"): 150 raise ValueError(f"'{label_choice}' is not a valid label choice. Use 'instances' or 'semantic'.") 151 152 h5_paths = get_glysac_paths(path, split, download) 153 154 if label_choice == "instances": 155 kwargs, _ = util.add_instance_label_transform(kwargs, add_binary_target=True) 156 kwargs = util.ensure_transforms(ndim=2, **kwargs) 157 158 return torch_em.default_segmentation_dataset( 159 raw_paths=h5_paths, 160 raw_key="raw", 161 label_paths=h5_paths, 162 label_key=f"labels/{label_choice}", 163 patch_shape=patch_shape, 164 with_channels=True, 165 ndim=2, 166 **kwargs, 167 ) 168 169 170def get_glysac_loader( 171 path: Union[os.PathLike, str], 172 batch_size: int, 173 patch_shape: Tuple[int, int], 174 split: Literal["train", "test"], 175 label_choice: Literal["instances", "semantic"] = "instances", 176 download: bool = False, 177 **kwargs, 178) -> DataLoader: 179 """Get the GLySAC dataloader for gastric nuclei segmentation. 180 181 Args: 182 path: Filepath to a folder where the downloaded data will be saved. 183 batch_size: The batch size for training. 184 patch_shape: The patch shape to use for training. 185 split: The data split to use. Either 'train' or 'test'. 186 label_choice: The type of labels to load. Either 'instances' for instance segmentation 187 or 'semantic' for cell type classification (4 classes: other, lymphocyte, epithelial, ambiguous). 188 download: Whether to download the data if it is not present. 189 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader. 190 191 Returns: 192 The DataLoader. 193 """ 194 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 195 dataset = get_glysac_dataset(path, patch_shape, split, label_choice, download, **ds_kwargs) 196 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
74def get_glysac_data(path: Union[os.PathLike, str], download: bool = False) -> str: 75 """Download the GLySAC dataset. 76 77 Args: 78 path: Filepath to a folder where the downloaded data will be saved. 79 download: Whether to download the data if it is not present. 80 81 Returns: 82 The filepath to the data directory. 83 """ 84 # Distributions of this dataset unpack either as 'glysac_dataset' or as 'GLySAC'. 85 for folder in ("glysac_dataset", "GLySAC"): 86 data_dir = os.path.join(path, folder) 87 if os.path.exists(data_dir): 88 return data_dir 89 90 data_dir = os.path.join(path, "glysac_dataset") 91 92 os.makedirs(path, exist_ok=True) 93 zip_path = os.path.join(path, "glysac_dataset.zip") 94 util.download_source_gdrive(path=zip_path, url=URL, download=download, checksum=CHECKSUM) 95 util.unzip(zip_path, path) 96 97 return data_dir
Download the GLySAC dataset.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- download: Whether to download the data if it is not present.
Returns:
The filepath to the data directory.
100def get_glysac_paths( 101 path: Union[os.PathLike, str], 102 split: Literal["train", "test"], 103 download: bool = False, 104) -> List[str]: 105 """Get paths to the GLySAC data. 106 107 Args: 108 path: Filepath to a folder where the downloaded data will be saved. 109 split: The data split to use. Either 'train' or 'test'. 110 download: Whether to download the data if it is not present. 111 112 Returns: 113 List of filepaths for the h5 data. 114 """ 115 if split not in ("train", "test"): 116 raise ValueError(f"'{split}' is not a valid split. Choose from 'train' or 'test'.") 117 118 data_dir = get_glysac_data(path, download) 119 _create_h5_files(data_dir, split) 120 121 h5_paths = natsorted(glob(os.path.join(data_dir, "h5", split, "*.h5"))) 122 if len(h5_paths) == 0: 123 raise RuntimeError(f"No data found for split '{split}'. Check the dataset at {data_dir}.") 124 125 return h5_paths
Get paths to the GLySAC data.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- split: The data split to use. Either 'train' or 'test'.
- download: Whether to download the data if it is not present.
Returns:
List of filepaths for the h5 data.
128def get_glysac_dataset( 129 path: Union[os.PathLike, str], 130 patch_shape: Tuple[int, int], 131 split: Literal["train", "test"], 132 label_choice: Literal["instances", "semantic"] = "instances", 133 download: bool = False, 134 **kwargs, 135) -> Dataset: 136 """Get the GLySAC dataset for gastric nuclei segmentation. 137 138 Args: 139 path: Filepath to a folder where the downloaded data will be saved. 140 patch_shape: The patch shape to use for training. 141 split: The data split to use. Either 'train' or 'test'. 142 label_choice: The type of labels to load. Either 'instances' for instance segmentation 143 or 'semantic' for cell type classification (4 classes: other, lymphocyte, epithelial, ambiguous). 144 download: Whether to download the data if it is not present. 145 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 146 147 Returns: 148 The segmentation dataset. 149 """ 150 if label_choice not in ("instances", "semantic"): 151 raise ValueError(f"'{label_choice}' is not a valid label choice. Use 'instances' or 'semantic'.") 152 153 h5_paths = get_glysac_paths(path, split, download) 154 155 if label_choice == "instances": 156 kwargs, _ = util.add_instance_label_transform(kwargs, add_binary_target=True) 157 kwargs = util.ensure_transforms(ndim=2, **kwargs) 158 159 return torch_em.default_segmentation_dataset( 160 raw_paths=h5_paths, 161 raw_key="raw", 162 label_paths=h5_paths, 163 label_key=f"labels/{label_choice}", 164 patch_shape=patch_shape, 165 with_channels=True, 166 ndim=2, 167 **kwargs, 168 )
Get the GLySAC dataset for gastric nuclei segmentation.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- patch_shape: The patch shape to use for training.
- split: The data split to use. Either 'train' or 'test'.
- label_choice: The type of labels to load. Either 'instances' for instance segmentation or 'semantic' for cell type classification (4 classes: other, lymphocyte, epithelial, ambiguous).
- download: Whether to download the data if it is not present.
- kwargs: Additional keyword arguments for
torch_em.default_segmentation_dataset.
Returns:
The segmentation dataset.
171def get_glysac_loader( 172 path: Union[os.PathLike, str], 173 batch_size: int, 174 patch_shape: Tuple[int, int], 175 split: Literal["train", "test"], 176 label_choice: Literal["instances", "semantic"] = "instances", 177 download: bool = False, 178 **kwargs, 179) -> DataLoader: 180 """Get the GLySAC dataloader for gastric nuclei segmentation. 181 182 Args: 183 path: Filepath to a folder where the downloaded data will be saved. 184 batch_size: The batch size for training. 185 patch_shape: The patch shape to use for training. 186 split: The data split to use. Either 'train' or 'test'. 187 label_choice: The type of labels to load. Either 'instances' for instance segmentation 188 or 'semantic' for cell type classification (4 classes: other, lymphocyte, epithelial, ambiguous). 189 download: Whether to download the data if it is not present. 190 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader. 191 192 Returns: 193 The DataLoader. 194 """ 195 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 196 dataset = get_glysac_dataset(path, patch_shape, split, label_choice, download, **ds_kwargs) 197 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
Get the GLySAC dataloader for gastric nuclei segmentation.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- batch_size: The batch size for training.
- patch_shape: The patch shape to use for training.
- split: The data split to use. Either 'train' or 'test'.
- label_choice: The type of labels to load. Either 'instances' for instance segmentation or 'semantic' for cell type classification (4 classes: other, lymphocyte, epithelial, ambiguous).
- download: Whether to download the data if it is not present.
- kwargs: Additional keyword arguments for
torch_em.default_segmentation_datasetor for the PyTorch DataLoader.
Returns:
The DataLoader.