torch_em.data.datasets.medical.idrid

The IDRID dataset contains annotations for retinal lesions and optic disc segmentation in Fundus images.

The database is located at https://ieee-dataport.org/open-access/indian-diabetic-retinopathy-image-dataset-idrid The dataloader makes use of an open-source version of the original dataset hosted on Kaggle.

The dataset is from the IDRiD challenge:

The 'refined' version (selected with version="refined") uses the same 81 IDRiD images, but replaces the lesion annotations with the 'Refined IDRiD' release: expert-corrected and validated annotations for the four original lesion types (microaneurysms, haemorrhages, hard exudates, soft / cotton-wool exudates), plus three additional proliferative DR lesion types (neovascularization, vitreous haemorrhage, intraretinal microvascular abnormalities) and anatomical context (optic disc, fovea, blood vessels, retinal region), all merged into a single unified multi-class label mask per image. It is located at https://doi.org/10.5281/zenodo.18676805 (CC BY 4.0). The task argument does not apply to this version, as the label masks are not split by lesion type. Please cite the dataset if you use this version: https://www.mdpi.com/2306-5729/11/2/30.

  1"""The IDRID dataset contains annotations for retinal lesions and optic disc segmentation
  2in Fundus images.
  3
  4The database is located at https://ieee-dataport.org/open-access/indian-diabetic-retinopathy-image-dataset-idrid
  5The dataloader makes use of an open-source version of the original dataset hosted on Kaggle.
  6
  7The dataset is from the IDRiD challenge:
  8- https://idrid.grand-challenge.org/
  9- Porwal et al. - https://doi.org/10.1016/j.media.2019.101561
 10Please cite them if you use this dataset for your research.
 11
 12The 'refined' version (selected with `version="refined"`) uses the same 81 IDRiD images, but replaces
 13the lesion annotations with the 'Refined IDRiD' release: expert-corrected and validated annotations for
 14the four original lesion types (microaneurysms, haemorrhages, hard exudates, soft / cotton-wool exudates),
 15plus three additional proliferative DR lesion types (neovascularization, vitreous haemorrhage, intraretinal
 16microvascular abnormalities) and anatomical context (optic disc, fovea, blood vessels, retinal region), all
 17merged into a single unified multi-class label mask per image. It is located at
 18https://doi.org/10.5281/zenodo.18676805 (CC BY 4.0). The `task` argument does not apply to this version, as
 19the label masks are not split by lesion type. Please cite the dataset if you use this version:
 20https://www.mdpi.com/2306-5729/11/2/30.
 21"""
 22
 23import os
 24from glob import glob
 25from pathlib import Path
 26from typing import Union, Tuple, Literal, List
 27
 28from torch.utils.data import Dataset, DataLoader
 29
 30import torch_em
 31
 32from .. import util
 33
 34
 35TASKS = {
 36    "microaneurysms": r"1. Microaneurysms",
 37    "haemorrhages": r"2. Haemorrhages",
 38    "hard_exudates": r"3. Hard Exudates",
 39    "soft_exudates": r"4. Soft Exudates",
 40    "optic_disc": r"5. Optic Disc"
 41}
 42
 43VERSIONS = ["v1", "refined"]
 44
 45URL_REFINED = {
 46    "train": "https://zenodo.org/records/18676805/files/Train.tar",
 47    "test": "https://zenodo.org/records/18676805/files/Test.tar",
 48}
 49CHECKSUM_REFINED = {
 50    "train": "cb368cbfcdcbb2a9d22b95a99301aa4a06e2d7d510a2a151d488216f570136ba",
 51    "test": "3482c23e9c7a179960ea2a831ffe665bcbc825d497403ba5d0f386642eb4d821",
 52}
 53
 54
 55def get_idrid_data(
 56    path: Union[os.PathLike, str], download: bool = False, version: Literal["v1", "refined"] = "v1"
 57) -> str:
 58    """Download the IDRID dataset.
 59
 60    Args:
 61        path: Filepath to a folder where the data is downloaded for further processing.
 62        download: Whether to download the data if it is not present.
 63        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
 64            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
 65
 66    Returns:
 67        Filepath where the data is downloaded.
 68    """
 69    if version not in VERSIONS:
 70        raise ValueError(f"'{version}' is not a valid version. Please choose one of {VERSIONS}.")
 71
 72    if version == "refined":
 73        data_dir = os.path.join(path, "refined")
 74        if os.path.exists(data_dir):
 75            return data_dir
 76
 77        os.makedirs(data_dir, exist_ok=True)
 78
 79        for split, url in URL_REFINED.items():
 80            tar_path = os.path.join(path, f"{split.capitalize()}.tar")
 81            util.download_source(path=tar_path, url=url, download=download, checksum=CHECKSUM_REFINED[split])
 82            util.unzip_tarfile(tar_path=tar_path, dst=data_dir, remove=False)
 83
 84        return data_dir
 85
 86    data_dir = os.path.join(path, "data", "A.%20Segmentation")
 87    if os.path.exists(data_dir):
 88        return data_dir
 89
 90    os.makedirs(path, exist_ok=True)
 91
 92    util.download_source_kaggle(
 93        path=path, dataset_name="aaryapatel98/indian-diabetic-retinopathy-image-dataset", download=download,
 94    )
 95    zip_path = os.path.join(path, "indian-diabetic-retinopathy-image-dataset.zip")
 96    util.unzip(zip_path=zip_path, dst=os.path.join(path, "data"))
 97
 98    return data_dir
 99
100
101def get_idrid_paths(
102    path: Union[os.PathLike, str],
103    split: Literal['train', 'test'],
104    task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'],
105    download: bool = False,
106    version: Literal["v1", "refined"] = "v1",
107) -> Tuple[List[str], List[str]]:
108    """Get paths to the IDRID 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.
113        task: The choice of labels for the specific task. Ignored when `version` is 'refined'.
114        download: Whether to download the data if it is not present.
115        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
116            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
117
118    Returns:
119        List of filepaths for the image data.
120        List of filepaths for the label data.
121    """
122    assert split in ["train", "test"]
123
124    data_dir = get_idrid_data(path=path, download=download, version=version)
125
126    if version == "refined":
127        split_dir = "Train" if split == "train" else "Test"
128        image_paths = sorted(glob(os.path.join(data_dir, split_dir, "Images", "*")))
129
130        label_dir = os.path.join(data_dir, split_dir, "Labels")
131        gt_paths = []
132        for image_path in image_paths:
133            stem = Path(image_path).stem
134            label_path = os.path.join(label_dir, f"{stem}.png")
135            if not os.path.exists(label_path):
136                label_path = os.path.join(label_dir, f"{stem}_vessel.png")
137            if not os.path.exists(label_path):
138                raise RuntimeError(f"Could not find the matching label for the image at '{image_path}'.")
139            gt_paths.append(label_path)
140
141        return image_paths, gt_paths
142
143    assert task in list(TASKS.keys())
144
145    split = r"a. Training Set" if split == "train" else r"b. Testing Set"
146    gt_paths = sorted(
147        glob(
148            os.path.join(data_dir, r"A. Segmentation", r"2. All Segmentation Groundtruths", split, TASKS[task], "*.tif")
149        )
150    )
151
152    image_dir = os.path.join(data_dir, r"A. Segmentation", r"1. Original Images", split)
153    image_paths = [os.path.join(image_dir, f"{Path(p).stem[:-3]}.jpg") for p in gt_paths]
154
155    return image_paths, gt_paths
156
157
158def get_idrid_dataset(
159    path: Union[os.PathLike, str],
160    patch_shape: Tuple[int, int],
161    split: Literal['train', 'test'],
162    task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'] = 'optic_disc',
163    resize_inputs: bool = False,
164    download: bool = False,
165    version: Literal["v1", "refined"] = "v1",
166    **kwargs
167) -> Dataset:
168    """Get the IDRID dataset for segmentation of retinal lesions and optic disc in fundus images.
169
170    Args:
171        path: Filepath to a folder where the data is downloaded for further processing.
172        patch_shape: The patch shape to use for training.
173        split: The choice of data split.
174        task: The choice of labels for the specific task. Ignored when `version` is 'refined'.
175        resize_inputs: Whether to resize the inputs to the expected patch shape.
176        download: Whether to download the data if it is not present.
177        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
178            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
179        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
180
181    Returns:
182        The segmentation dataset.
183    """
184    image_paths, gt_paths = get_idrid_paths(path, split, task, download, version)
185
186    if resize_inputs:
187        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
188        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
189            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
190        )
191
192    return torch_em.default_segmentation_dataset(
193        raw_paths=image_paths,
194        raw_key=None,
195        label_paths=gt_paths,
196        label_key=None,
197        patch_shape=patch_shape,
198        is_seg_dataset=False,
199        **kwargs
200    )
201
202
203def get_idrid_loader(
204    path: Union[os.PathLike, str],
205    batch_size: int,
206    patch_shape: Tuple[int, int],
207    split: Literal['train', 'test'],
208    task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'] = 'optic_disc',
209    resize_inputs: bool = False,
210    download: bool = False,
211    version: Literal["v1", "refined"] = "v1",
212    **kwargs
213) -> DataLoader:
214    """Get the IDRID dataloader for segmentation of retinal lesions and optic disc in fundus images.
215
216    Args:
217        path: Filepath to a folder where the data is downloaded for further processing.
218        batch_size: The batch size for training.
219        patch_shape: The patch shape to use for training.
220        split: The choice of data split.
221        task: The choice of labels for the specific task. Ignored when `version` is 'refined'.
222        resize_inputs: Whether to resize the inputs to the expected patch shape.
223        download: Whether to download the data if it is not present.
224        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
225            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
226        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
227
228    Returns:
229        The DataLoader.
230    """
231    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
232    dataset = get_idrid_dataset(path, patch_shape, split, task, resize_inputs, download, version, **ds_kwargs)
233    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
TASKS = {'microaneurysms': '1. Microaneurysms', 'haemorrhages': '2. Haemorrhages', 'hard_exudates': '3. Hard Exudates', 'soft_exudates': '4. Soft Exudates', 'optic_disc': '5. Optic Disc'}
VERSIONS = ['v1', 'refined']
URL_REFINED = {'train': 'https://zenodo.org/records/18676805/files/Train.tar', 'test': 'https://zenodo.org/records/18676805/files/Test.tar'}
CHECKSUM_REFINED = {'train': 'cb368cbfcdcbb2a9d22b95a99301aa4a06e2d7d510a2a151d488216f570136ba', 'test': '3482c23e9c7a179960ea2a831ffe665bcbc825d497403ba5d0f386642eb4d821'}
def get_idrid_data( path: Union[os.PathLike, str], download: bool = False, version: Literal['v1', 'refined'] = 'v1') -> str:
56def get_idrid_data(
57    path: Union[os.PathLike, str], download: bool = False, version: Literal["v1", "refined"] = "v1"
58) -> str:
59    """Download the IDRID dataset.
60
61    Args:
62        path: Filepath to a folder where the data is downloaded for further processing.
63        download: Whether to download the data if it is not present.
64        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
65            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
66
67    Returns:
68        Filepath where the data is downloaded.
69    """
70    if version not in VERSIONS:
71        raise ValueError(f"'{version}' is not a valid version. Please choose one of {VERSIONS}.")
72
73    if version == "refined":
74        data_dir = os.path.join(path, "refined")
75        if os.path.exists(data_dir):
76            return data_dir
77
78        os.makedirs(data_dir, exist_ok=True)
79
80        for split, url in URL_REFINED.items():
81            tar_path = os.path.join(path, f"{split.capitalize()}.tar")
82            util.download_source(path=tar_path, url=url, download=download, checksum=CHECKSUM_REFINED[split])
83            util.unzip_tarfile(tar_path=tar_path, dst=data_dir, remove=False)
84
85        return data_dir
86
87    data_dir = os.path.join(path, "data", "A.%20Segmentation")
88    if os.path.exists(data_dir):
89        return data_dir
90
91    os.makedirs(path, exist_ok=True)
92
93    util.download_source_kaggle(
94        path=path, dataset_name="aaryapatel98/indian-diabetic-retinopathy-image-dataset", download=download,
95    )
96    zip_path = os.path.join(path, "indian-diabetic-retinopathy-image-dataset.zip")
97    util.unzip(zip_path=zip_path, dst=os.path.join(path, "data"))
98
99    return data_dir

Download the IDRID dataset.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • download: Whether to download the data if it is not present.
  • version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or 'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
Returns:

Filepath where the data is downloaded.

def get_idrid_paths( path: Union[os.PathLike, str], split: Literal['train', 'test'], task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'], download: bool = False, version: Literal['v1', 'refined'] = 'v1') -> Tuple[List[str], List[str]]:
102def get_idrid_paths(
103    path: Union[os.PathLike, str],
104    split: Literal['train', 'test'],
105    task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'],
106    download: bool = False,
107    version: Literal["v1", "refined"] = "v1",
108) -> Tuple[List[str], List[str]]:
109    """Get paths to the IDRID 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.
114        task: The choice of labels for the specific task. Ignored when `version` is 'refined'.
115        download: Whether to download the data if it is not present.
116        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
117            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
118
119    Returns:
120        List of filepaths for the image data.
121        List of filepaths for the label data.
122    """
123    assert split in ["train", "test"]
124
125    data_dir = get_idrid_data(path=path, download=download, version=version)
126
127    if version == "refined":
128        split_dir = "Train" if split == "train" else "Test"
129        image_paths = sorted(glob(os.path.join(data_dir, split_dir, "Images", "*")))
130
131        label_dir = os.path.join(data_dir, split_dir, "Labels")
132        gt_paths = []
133        for image_path in image_paths:
134            stem = Path(image_path).stem
135            label_path = os.path.join(label_dir, f"{stem}.png")
136            if not os.path.exists(label_path):
137                label_path = os.path.join(label_dir, f"{stem}_vessel.png")
138            if not os.path.exists(label_path):
139                raise RuntimeError(f"Could not find the matching label for the image at '{image_path}'.")
140            gt_paths.append(label_path)
141
142        return image_paths, gt_paths
143
144    assert task in list(TASKS.keys())
145
146    split = r"a. Training Set" if split == "train" else r"b. Testing Set"
147    gt_paths = sorted(
148        glob(
149            os.path.join(data_dir, r"A. Segmentation", r"2. All Segmentation Groundtruths", split, TASKS[task], "*.tif")
150        )
151    )
152
153    image_dir = os.path.join(data_dir, r"A. Segmentation", r"1. Original Images", split)
154    image_paths = [os.path.join(image_dir, f"{Path(p).stem[:-3]}.jpg") for p in gt_paths]
155
156    return image_paths, gt_paths

Get paths to the IDRID data.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • split: The choice of data split.
  • task: The choice of labels for the specific task. Ignored when version is 'refined'.
  • download: Whether to download the data if it is not present.
  • version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or 'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
Returns:

List of filepaths for the image data. List of filepaths for the label data.

def get_idrid_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], split: Literal['train', 'test'], task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'] = 'optic_disc', resize_inputs: bool = False, download: bool = False, version: Literal['v1', 'refined'] = 'v1', **kwargs) -> torch.utils.data.dataset.Dataset:
159def get_idrid_dataset(
160    path: Union[os.PathLike, str],
161    patch_shape: Tuple[int, int],
162    split: Literal['train', 'test'],
163    task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'] = 'optic_disc',
164    resize_inputs: bool = False,
165    download: bool = False,
166    version: Literal["v1", "refined"] = "v1",
167    **kwargs
168) -> Dataset:
169    """Get the IDRID dataset for segmentation of retinal lesions and optic disc in fundus images.
170
171    Args:
172        path: Filepath to a folder where the data is downloaded for further processing.
173        patch_shape: The patch shape to use for training.
174        split: The choice of data split.
175        task: The choice of labels for the specific task. Ignored when `version` is 'refined'.
176        resize_inputs: Whether to resize the inputs to the expected patch shape.
177        download: Whether to download the data if it is not present.
178        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
179            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
180        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
181
182    Returns:
183        The segmentation dataset.
184    """
185    image_paths, gt_paths = get_idrid_paths(path, split, task, download, version)
186
187    if resize_inputs:
188        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
189        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
190            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
191        )
192
193    return torch_em.default_segmentation_dataset(
194        raw_paths=image_paths,
195        raw_key=None,
196        label_paths=gt_paths,
197        label_key=None,
198        patch_shape=patch_shape,
199        is_seg_dataset=False,
200        **kwargs
201    )

Get the IDRID dataset for segmentation of retinal lesions and optic disc in fundus images.

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.
  • task: The choice of labels for the specific task. Ignored when version is 'refined'.
  • resize_inputs: Whether to resize the inputs to the expected patch shape.
  • download: Whether to download the data if it is not present.
  • version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or 'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
  • kwargs: Additional keyword arguments for torch_em.default_segmentation_dataset.
Returns:

The segmentation dataset.

def get_idrid_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], split: Literal['train', 'test'], task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'] = 'optic_disc', resize_inputs: bool = False, download: bool = False, version: Literal['v1', 'refined'] = 'v1', **kwargs) -> torch.utils.data.dataloader.DataLoader:
204def get_idrid_loader(
205    path: Union[os.PathLike, str],
206    batch_size: int,
207    patch_shape: Tuple[int, int],
208    split: Literal['train', 'test'],
209    task: Literal['microaneurysms', 'haemorrhages', 'hard_exudates', 'soft_exudates', 'optic_disc'] = 'optic_disc',
210    resize_inputs: bool = False,
211    download: bool = False,
212    version: Literal["v1", "refined"] = "v1",
213    **kwargs
214) -> DataLoader:
215    """Get the IDRID dataloader for segmentation of retinal lesions and optic disc in fundus images.
216
217    Args:
218        path: Filepath to a folder where the data is downloaded for further processing.
219        batch_size: The batch size for training.
220        patch_shape: The patch shape to use for training.
221        split: The choice of data split.
222        task: The choice of labels for the specific task. Ignored when `version` is 'refined'.
223        resize_inputs: Whether to resize the inputs to the expected patch shape.
224        download: Whether to download the data if it is not present.
225        version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or
226            'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
227        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
228
229    Returns:
230        The DataLoader.
231    """
232    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
233    dataset = get_idrid_dataset(path, patch_shape, split, task, resize_inputs, download, version, **ds_kwargs)
234    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the IDRID dataloader for segmentation of retinal lesions and optic disc in fundus images.

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.
  • task: The choice of labels for the specific task. Ignored when version is 'refined'.
  • resize_inputs: Whether to resize the inputs to the expected patch shape.
  • download: Whether to download the data if it is not present.
  • version: The version of the dataset. Either 'v1' (the original IDRiD lesion annotations) or 'refined' (the 'Refined IDRiD' release with expert-corrected and additional lesion annotations).
  • kwargs: Additional keyword arguments for torch_em.default_segmentation_dataset or for the PyTorch DataLoader.
Returns:

The DataLoader.