torch_em.data.datasets.medical.wmh
The WMH dataset contains annotations for white matter hyperintensity segmentation in brain MRI (FLAIR and T1) from the MICCAI 2017 WMH Segmentation Challenge.
The data comprises 60 training and 110 test subjects, acquired at three sites (Utrecht, Singapore and Amsterdam) on five different scanners. Each subject has a FLAIR and a T1 scan (the T1 has been registered to the FLAIR space and both have been bias field corrected in the provided 'pre' folder) and a manual annotation in FLAIR space.
NOTE: The label legend is as follows:
- background: 0, white matter hyperintensity: 1, other pathology: 2
The dataset is located at https://dataverse.nl/dataset.xhtml?persistentId=doi:10.34894/AECRSD. The challenge website is https://wmh.isi.uu.nl/.
This dataset is from the publication https://doi.org/10.1109/TMI.2019.2905770. Please cite it if you use this dataset in your research.
1"""The WMH dataset contains annotations for white matter hyperintensity segmentation 2in brain MRI (FLAIR and T1) from the MICCAI 2017 WMH Segmentation Challenge. 3 4The data comprises 60 training and 110 test subjects, acquired at three sites (Utrecht, Singapore and Amsterdam) 5on five different scanners. Each subject has a FLAIR and a T1 scan (the T1 has been registered to the FLAIR space 6and both have been bias field corrected in the provided 'pre' folder) and a manual annotation in FLAIR space. 7 8NOTE: The label legend is as follows: 9- background: 0, white matter hyperintensity: 1, other pathology: 2 10 11The dataset is located at https://dataverse.nl/dataset.xhtml?persistentId=doi:10.34894/AECRSD. 12The challenge website is https://wmh.isi.uu.nl/. 13 14This dataset is from the publication https://doi.org/10.1109/TMI.2019.2905770. 15Please cite it if you use this dataset in your research. 16""" 17 18import os 19from glob import glob 20from natsort import natsorted 21from typing import Union, Tuple, Literal, List, Optional 22 23import requests 24 25from torch.utils.data import Dataset, DataLoader 26 27import torch_em 28 29from .. import util 30 31 32DOI = "doi:10.34894/AECRSD" 33API_URL = "https://dataverse.nl/api" 34URL = f"{API_URL}/datasets/:persistentId/?persistentId={DOI}" 35 36# NOTE: The dataset is downloaded file-by-file via the dataverse API (the full-dataset zip times out), 37# so there is no single archive checksum. 38CHECKSUM = None 39 40SPLIT_DIRS = {"train": "training", "test": "test"} 41N_SUBJECTS = {"train": 60, "test": 110} 42FILENAMES = ["FLAIR.nii.gz", "T1.nii.gz", "wmh.nii.gz"] 43 44 45def _get_wmh_file_list(split): 46 response = requests.get(URL) 47 response.raise_for_status() 48 files = response.json()["data"]["latestVersion"]["files"] 49 50 to_download = [] 51 for f in files: 52 parts = f.get("directoryLabel", "").split("/") 53 fname = f["dataFile"]["filename"] 54 if parts[0] != SPLIT_DIRS[split] or fname not in FILENAMES: 55 continue 56 57 # The FLAIR and T1 scans are used from the preprocessed 'pre' folder (bias field corrected, T1 in FLAIR space). 58 # The annotation 'wmh.nii.gz' is located directly in the subject folder. 59 if parts[-1] == "pre": 60 parts = parts[:-1] 61 elif fname != "wmh.nii.gz": 62 continue 63 64 # The Amsterdam Philips scanner folder is named 'Philips_VU .PETMR_01.', we shorten it to 'Philips_VU'. 65 parts = [p.split(" ")[0] for p in parts] 66 to_download.append((os.path.join(*parts, fname), f["dataFile"]["id"])) 67 68 return to_download 69 70 71def get_wmh_data(path: Union[os.PathLike, str], split: Literal["train", "test"], download: bool = False) -> str: 72 """Download the WMH dataset. 73 74 Args: 75 path: Filepath to a folder where the data is downloaded for further processing. 76 split: The choice of data split. Either 'train' or 'test'. 77 download: Whether to download the data if it is not present. 78 79 Returns: 80 Filepath where the data for the split is stored. 81 """ 82 if split not in SPLIT_DIRS: 83 raise ValueError(f"'{split}' is not a valid split. Please choose from {list(SPLIT_DIRS.keys())}.") 84 85 data_dir = os.path.join(path, SPLIT_DIRS[split]) 86 label_paths = glob(os.path.join(data_dir, "**", "wmh.nii.gz"), recursive=True) 87 if len(label_paths) == N_SUBJECTS[split]: 88 return data_dir 89 90 if not download: 91 raise RuntimeError(f"Cannot find the data at {data_dir}, but download was set to False.") 92 93 for rel_path, file_id in _get_wmh_file_list(split): 94 fpath = os.path.join(path, rel_path) 95 os.makedirs(os.path.split(fpath)[0], exist_ok=True) 96 util.download_source(path=fpath, url=f"{API_URL}/access/datafile/{file_id}", download=download, checksum=None) 97 98 return data_dir 99 100 101def get_wmh_paths( 102 path: Union[os.PathLike, str], 103 split: Literal["train", "test"], 104 modality: Optional[Literal["FLAIR", "T1"]] = None, 105 site: Optional[Literal["Utrecht", "Singapore", "Amsterdam"]] = None, 106 download: bool = False, 107) -> Tuple[List[Union[str, Tuple[str, str]]], List[str]]: 108 """Get paths to the WMH data. 109 110 Args: 111 path: Filepath to a folder where the data is downloaded for further processing. 112 split: The choice of data split. Either 'train' or 'test'. 113 modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are returned as channels. 114 site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are returned. 115 download: Whether to download the data if it is not present. 116 117 Returns: 118 List of filepaths for the image data. 119 List of filepaths for the label data. 120 """ 121 data_dir = get_wmh_data(path, split, download) 122 123 site_dir = "*" if site is None else site 124 label_paths = natsorted(glob(os.path.join(data_dir, site_dir, "**", "wmh.nii.gz"), recursive=True)) 125 if len(label_paths) == 0: 126 raise ValueError(f"Could not find any data for split '{split}' and site '{site}'.") 127 128 flair_paths = [p.replace("wmh.nii.gz", "FLAIR.nii.gz") for p in label_paths] 129 t1_paths = [p.replace("wmh.nii.gz", "T1.nii.gz") for p in label_paths] 130 assert all(os.path.exists(p) for p in flair_paths + t1_paths) 131 132 if modality is None: 133 raw_paths = [(fp, tp) for fp, tp in zip(flair_paths, t1_paths)] 134 elif modality == "FLAIR": 135 raw_paths = flair_paths 136 elif modality == "T1": 137 raw_paths = t1_paths 138 else: 139 raise ValueError(f"'{modality}' is not a valid modality. Please choose from 'FLAIR' or 'T1'.") 140 141 return raw_paths, label_paths 142 143 144def get_wmh_dataset( 145 path: Union[os.PathLike, str], 146 patch_shape: Tuple[int, ...], 147 split: Literal["train", "test"], 148 modality: Optional[Literal["FLAIR", "T1"]] = None, 149 site: Optional[Literal["Utrecht", "Singapore", "Amsterdam"]] = None, 150 resize_inputs: bool = False, 151 download: bool = False, 152 **kwargs 153) -> Dataset: 154 """Get the WMH dataset for white matter hyperintensity segmentation. 155 156 Args: 157 path: Filepath to a folder where the data is downloaded for further processing. 158 patch_shape: The patch shape to use for training. 159 split: The choice of data split. Either 'train' or 'test'. 160 modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are used as channels. 161 site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are used. 162 resize_inputs: Whether to resize inputs to the desired patch shape. 163 download: Whether to download the data if it is not present. 164 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 165 166 Returns: 167 The segmentation dataset. 168 """ 169 raw_paths, label_paths = get_wmh_paths(path, split, modality, site, download) 170 171 if resize_inputs: 172 resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False} 173 kwargs, patch_shape = util.update_kwargs_for_resize_trafo( 174 kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs 175 ) 176 177 return torch_em.default_segmentation_dataset( 178 raw_paths=raw_paths, 179 raw_key="data", 180 label_paths=label_paths, 181 label_key="data", 182 patch_shape=patch_shape, 183 is_seg_dataset=True, 184 with_channels=modality is None, 185 **kwargs 186 ) 187 188 189def get_wmh_loader( 190 path: Union[os.PathLike, str], 191 batch_size: int, 192 patch_shape: Tuple[int, ...], 193 split: Literal["train", "test"], 194 modality: Optional[Literal["FLAIR", "T1"]] = None, 195 site: Optional[Literal["Utrecht", "Singapore", "Amsterdam"]] = None, 196 resize_inputs: bool = False, 197 download: bool = False, 198 **kwargs 199) -> DataLoader: 200 """Get the WMH dataloader for white matter hyperintensity segmentation. 201 202 Args: 203 path: Filepath to a folder where the data is downloaded for further processing. 204 batch_size: The batch size for training. 205 patch_shape: The patch shape to use for training. 206 split: The choice of data split. Either 'train' or 'test'. 207 modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are used as channels. 208 site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are used. 209 resize_inputs: Whether to resize inputs to the desired patch shape. 210 download: Whether to download the data if it is not present. 211 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader. 212 213 Returns: 214 The DataLoader. 215 """ 216 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 217 dataset = get_wmh_dataset(path, patch_shape, split, modality, site, resize_inputs, download, **ds_kwargs) 218 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
72def get_wmh_data(path: Union[os.PathLike, str], split: Literal["train", "test"], download: bool = False) -> str: 73 """Download the WMH dataset. 74 75 Args: 76 path: Filepath to a folder where the data is downloaded for further processing. 77 split: The choice of data split. Either 'train' or 'test'. 78 download: Whether to download the data if it is not present. 79 80 Returns: 81 Filepath where the data for the split is stored. 82 """ 83 if split not in SPLIT_DIRS: 84 raise ValueError(f"'{split}' is not a valid split. Please choose from {list(SPLIT_DIRS.keys())}.") 85 86 data_dir = os.path.join(path, SPLIT_DIRS[split]) 87 label_paths = glob(os.path.join(data_dir, "**", "wmh.nii.gz"), recursive=True) 88 if len(label_paths) == N_SUBJECTS[split]: 89 return data_dir 90 91 if not download: 92 raise RuntimeError(f"Cannot find the data at {data_dir}, but download was set to False.") 93 94 for rel_path, file_id in _get_wmh_file_list(split): 95 fpath = os.path.join(path, rel_path) 96 os.makedirs(os.path.split(fpath)[0], exist_ok=True) 97 util.download_source(path=fpath, url=f"{API_URL}/access/datafile/{file_id}", download=download, checksum=None) 98 99 return data_dir
Download the WMH dataset.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- split: The choice of data split. Either 'train' or 'test'.
- download: Whether to download the data if it is not present.
Returns:
Filepath where the data for the split is stored.
102def get_wmh_paths( 103 path: Union[os.PathLike, str], 104 split: Literal["train", "test"], 105 modality: Optional[Literal["FLAIR", "T1"]] = None, 106 site: Optional[Literal["Utrecht", "Singapore", "Amsterdam"]] = None, 107 download: bool = False, 108) -> Tuple[List[Union[str, Tuple[str, str]]], List[str]]: 109 """Get paths to the WMH data. 110 111 Args: 112 path: Filepath to a folder where the data is downloaded for further processing. 113 split: The choice of data split. Either 'train' or 'test'. 114 modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are returned as channels. 115 site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are returned. 116 download: Whether to download the data if it is not present. 117 118 Returns: 119 List of filepaths for the image data. 120 List of filepaths for the label data. 121 """ 122 data_dir = get_wmh_data(path, split, download) 123 124 site_dir = "*" if site is None else site 125 label_paths = natsorted(glob(os.path.join(data_dir, site_dir, "**", "wmh.nii.gz"), recursive=True)) 126 if len(label_paths) == 0: 127 raise ValueError(f"Could not find any data for split '{split}' and site '{site}'.") 128 129 flair_paths = [p.replace("wmh.nii.gz", "FLAIR.nii.gz") for p in label_paths] 130 t1_paths = [p.replace("wmh.nii.gz", "T1.nii.gz") for p in label_paths] 131 assert all(os.path.exists(p) for p in flair_paths + t1_paths) 132 133 if modality is None: 134 raw_paths = [(fp, tp) for fp, tp in zip(flair_paths, t1_paths)] 135 elif modality == "FLAIR": 136 raw_paths = flair_paths 137 elif modality == "T1": 138 raw_paths = t1_paths 139 else: 140 raise ValueError(f"'{modality}' is not a valid modality. Please choose from 'FLAIR' or 'T1'.") 141 142 return raw_paths, label_paths
Get paths to the WMH data.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- split: The choice of data split. Either 'train' or 'test'.
- modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are returned as channels.
- site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are returned.
- download: Whether to download the data if it is not present.
Returns:
List of filepaths for the image data. List of filepaths for the label data.
145def get_wmh_dataset( 146 path: Union[os.PathLike, str], 147 patch_shape: Tuple[int, ...], 148 split: Literal["train", "test"], 149 modality: Optional[Literal["FLAIR", "T1"]] = None, 150 site: Optional[Literal["Utrecht", "Singapore", "Amsterdam"]] = None, 151 resize_inputs: bool = False, 152 download: bool = False, 153 **kwargs 154) -> Dataset: 155 """Get the WMH dataset for white matter hyperintensity segmentation. 156 157 Args: 158 path: Filepath to a folder where the data is downloaded for further processing. 159 patch_shape: The patch shape to use for training. 160 split: The choice of data split. Either 'train' or 'test'. 161 modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are used as channels. 162 site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are used. 163 resize_inputs: Whether to resize inputs to the desired patch shape. 164 download: Whether to download the data if it is not present. 165 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 166 167 Returns: 168 The segmentation dataset. 169 """ 170 raw_paths, label_paths = get_wmh_paths(path, split, modality, site, download) 171 172 if resize_inputs: 173 resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False} 174 kwargs, patch_shape = util.update_kwargs_for_resize_trafo( 175 kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs 176 ) 177 178 return torch_em.default_segmentation_dataset( 179 raw_paths=raw_paths, 180 raw_key="data", 181 label_paths=label_paths, 182 label_key="data", 183 patch_shape=patch_shape, 184 is_seg_dataset=True, 185 with_channels=modality is None, 186 **kwargs 187 )
Get the WMH dataset for white matter hyperintensity segmentation.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- patch_shape: The patch shape to use for training.
- split: The choice of data split. Either 'train' or 'test'.
- modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are used as channels.
- site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are used.
- resize_inputs: Whether to resize inputs to the desired patch shape.
- 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.
190def get_wmh_loader( 191 path: Union[os.PathLike, str], 192 batch_size: int, 193 patch_shape: Tuple[int, ...], 194 split: Literal["train", "test"], 195 modality: Optional[Literal["FLAIR", "T1"]] = None, 196 site: Optional[Literal["Utrecht", "Singapore", "Amsterdam"]] = None, 197 resize_inputs: bool = False, 198 download: bool = False, 199 **kwargs 200) -> DataLoader: 201 """Get the WMH dataloader for white matter hyperintensity segmentation. 202 203 Args: 204 path: Filepath to a folder where the data is downloaded for further processing. 205 batch_size: The batch size for training. 206 patch_shape: The patch shape to use for training. 207 split: The choice of data split. Either 'train' or 'test'. 208 modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are used as channels. 209 site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are used. 210 resize_inputs: Whether to resize inputs to the desired patch shape. 211 download: Whether to download the data if it is not present. 212 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader. 213 214 Returns: 215 The DataLoader. 216 """ 217 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 218 dataset = get_wmh_dataset(path, patch_shape, split, modality, site, resize_inputs, download, **ds_kwargs) 219 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
Get the WMH dataloader for white matter hyperintensity segmentation.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- batch_size: The batch size for training.
- patch_shape: The patch shape to use for training.
- split: The choice of data split. Either 'train' or 'test'.
- modality: The choice of modality. Either 'FLAIR' or 'T1'. By default, both are used as channels.
- site: The acquisition site. One of 'Utrecht', 'Singapore' or 'Amsterdam'. By default, all sites are used.
- resize_inputs: Whether to resize inputs to the desired patch shape.
- 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.