torch_em.data.datasets.medical.riga_plus

The RIGA+ dataset contains annotations for optic disc and optic cup segmentation in fundus images, gathered from the original RIGA dataset (BinRushed, Magrabia and three MESSIDOR subsets), for the task of glaucoma assessment and unsupervised domain adaptation.

The dataset is hosted on Zenodo at https://zenodo.org/records/6325549 ("RIGA+ Dataset for Unsupervised Domain Adaptation in Medical Image Segmentation").

NOTE: There is a second, differently-scoped dataset that also carries the "RIGA+" name, hosted at https://zenodo.org/records/8009107 ("A Fundus Image Dataset for Domain Generalization in Joint Segmentation of Optic Disc and Optic Cup"). It combines images from REFUGE, Drishti-GS, ORIGA and RIGA into a single collection and is not covered by this module.

The five domains provided by this dataset (BinRushed, Magrabia, MESSIDOR_Base1, MESSIDOR_Base2 and MESSIDOR_Base3) each ship six independent optic disc / cup annotations per image (one per rater). The label masks are grayscale images with 3 pixel values: 0 (optic cup), 128 (optic disc, excluding the cup) and 255 (background).

Please cite the dataset if you use it for your research.

  1"""The RIGA+ dataset contains annotations for optic disc and optic cup segmentation in fundus images,
  2gathered from the original RIGA dataset (BinRushed, Magrabia and three MESSIDOR subsets), for the task
  3of glaucoma assessment and unsupervised domain adaptation.
  4
  5The dataset is hosted on Zenodo at https://zenodo.org/records/6325549 ("RIGA+ Dataset for Unsupervised
  6Domain Adaptation in Medical Image Segmentation").
  7
  8NOTE: There is a second, differently-scoped dataset that also carries the "RIGA+" name, hosted at
  9https://zenodo.org/records/8009107 ("A Fundus Image Dataset for Domain Generalization in Joint
 10Segmentation of Optic Disc and Optic Cup"). It combines images from REFUGE, Drishti-GS, ORIGA and RIGA
 11into a single collection and is not covered by this module.
 12
 13The five domains provided by this dataset (BinRushed, Magrabia, MESSIDOR_Base1, MESSIDOR_Base2 and
 14MESSIDOR_Base3) each ship six independent optic disc / cup annotations per image (one per rater). The
 15label masks are grayscale images with 3 pixel values: 0 (optic cup), 128 (optic disc, excluding the
 16cup) and 255 (background).
 17
 18Please cite the dataset if you use it for your research.
 19"""
 20
 21import os
 22from typing import Union, Tuple, Literal, List
 23
 24import pandas as pd
 25
 26from torch.utils.data import Dataset, DataLoader
 27
 28import torch_em
 29
 30from .. import util
 31
 32
 33URL = "https://zenodo.org/records/6325549/files/RIGAPlus.zip"
 34CHECKSUM = "f9fa96df2faa70852ccd4c73d0e79ed6eb258b5a37e72292f5efa3f81f195d20"
 35
 36DOMAINS = ["BinRushed", "Magrabia", "MESSIDOR_Base1", "MESSIDOR_Base2", "MESSIDOR_Base3"]
 37
 38
 39def get_riga_plus_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 40    """Download the RIGA+ dataset.
 41
 42    Args:
 43        path: Filepath to a folder where the data is downloaded for further processing.
 44        download: Whether to download the data if it is not present.
 45
 46    Returns:
 47        Filepath where the data is downloaded.
 48    """
 49    data_dir = os.path.join(path, "RIGA")
 50    if os.path.exists(data_dir):
 51        return path
 52
 53    os.makedirs(path, exist_ok=True)
 54
 55    zip_path = os.path.join(path, "RIGAPlus.zip")
 56    util.download_source(path=zip_path, url=URL, download=download, checksum=CHECKSUM)
 57    util.unzip(zip_path=zip_path, dst=path)
 58
 59    return path
 60
 61
 62def get_riga_plus_paths(
 63    path: Union[os.PathLike, str],
 64    split: Literal["train", "test"],
 65    domain: Union[str, List[str]] = DOMAINS,
 66    rater: int = 1,
 67    download: bool = False,
 68) -> Tuple[List[str], List[str]]:
 69    """Get paths to the RIGA+ data.
 70
 71    Args:
 72        path: Filepath to a folder where the data is downloaded for further processing.
 73        split: The choice of data split, as provided by the official 'train' / 'test' csv files.
 74        domain: The choice of domain(s) to use. One or several of 'BinRushed', 'Magrabia',
 75            'MESSIDOR_Base1', 'MESSIDOR_Base2' and 'MESSIDOR_Base3'.
 76        rater: The choice of rater (1 to 6) for the ground-truth optic disc / cup masks.
 77        download: Whether to download the data if it is not present.
 78
 79    Returns:
 80        List of filepaths for the image data.
 81        List of filepaths for the label data.
 82    """
 83    root_dir = get_riga_plus_data(path=path, download=download)
 84
 85    assert split in ["train", "test"], f"'{split}' is not a valid split."
 86    assert 1 <= rater <= 6, f"'{rater}' is not a valid rater choice, must be in [1, 6]."
 87
 88    domains = [domain] if isinstance(domain, str) else domain
 89    for d in domains:
 90        assert d in DOMAINS, f"'{d}' is not a valid domain, must be one of {DOMAINS}."
 91
 92    image_paths, gt_paths = [], []
 93    for d in domains:
 94        csv_path = os.path.join(root_dir, f"{d}_{split}.csv")
 95        df = pd.read_csv(csv_path)
 96        for image_rel_path, mask_rel_path in zip(df["image"], df["mask"]):
 97            stem, ext = os.path.splitext(mask_rel_path)
 98            image_paths.append(os.path.join(root_dir, image_rel_path))
 99            gt_paths.append(os.path.join(root_dir, f"{stem}-{rater}{ext}"))
100
101    assert len(image_paths) == len(gt_paths) and len(image_paths) > 0
102    for image_path, gt_path in zip(image_paths, gt_paths):
103        assert os.path.exists(image_path), image_path
104        assert os.path.exists(gt_path), gt_path
105
106    return image_paths, gt_paths
107
108
109def get_riga_plus_dataset(
110    path: Union[os.PathLike, str],
111    patch_shape: Tuple[int, int],
112    split: Literal["train", "test"],
113    domain: Union[str, List[str]] = DOMAINS,
114    rater: int = 1,
115    resize_inputs: bool = False,
116    download: bool = False,
117    **kwargs
118) -> Dataset:
119    """Get the RIGA+ dataset for segmentation of optic disc and optic cup in fundus images.
120
121    Args:
122        path: Filepath to a folder where the data is downloaded for further processing.
123        patch_shape: The patch shape to use for training.
124        split: The choice of data split.
125        domain: The choice of domain(s) to use.
126        rater: The choice of rater for the ground-truth optic disc / cup masks.
127        resize_inputs: Whether to resize the inputs to the expected patch shape.
128        download: Whether to download the data if it is not present.
129        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
130
131    Returns:
132        The segmentation dataset.
133    """
134    image_paths, gt_paths = get_riga_plus_paths(path, split, domain, rater, download)
135
136    if resize_inputs:
137        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
138        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
139            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
140        )
141
142    return torch_em.default_segmentation_dataset(
143        raw_paths=image_paths,
144        raw_key=None,
145        label_paths=gt_paths,
146        label_key=None,
147        patch_shape=patch_shape,
148        is_seg_dataset=False,
149        **kwargs
150    )
151
152
153def get_riga_plus_loader(
154    path: Union[os.PathLike, str],
155    batch_size: int,
156    patch_shape: Tuple[int, int],
157    split: Literal["train", "test"],
158    domain: Union[str, List[str]] = DOMAINS,
159    rater: int = 1,
160    resize_inputs: bool = False,
161    download: bool = False,
162    **kwargs
163) -> DataLoader:
164    """Get the RIGA+ dataloader for segmentation of optic disc and optic cup in fundus images.
165
166    Args:
167        path: Filepath to a folder where the data is downloaded for further processing.
168        batch_size: The batch size for training.
169        patch_shape: The patch shape to use for training.
170        split: The choice of data split.
171        domain: The choice of domain(s) to use.
172        rater: The choice of rater for the ground-truth optic disc / cup masks.
173        resize_inputs: Whether to resize the inputs to the expected patch shape.
174        download: Whether to download the data if it is not present.
175        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
176
177    Returns:
178        The DataLoader.
179    """
180    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
181    dataset = get_riga_plus_dataset(path, patch_shape, split, domain, rater, resize_inputs, download, **ds_kwargs)
182    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
URL = 'https://zenodo.org/records/6325549/files/RIGAPlus.zip'
CHECKSUM = 'f9fa96df2faa70852ccd4c73d0e79ed6eb258b5a37e72292f5efa3f81f195d20'
DOMAINS = ['BinRushed', 'Magrabia', 'MESSIDOR_Base1', 'MESSIDOR_Base2', 'MESSIDOR_Base3']
def get_riga_plus_data(path: Union[os.PathLike, str], download: bool = False) -> str:
40def get_riga_plus_data(path: Union[os.PathLike, str], download: bool = False) -> str:
41    """Download the RIGA+ dataset.
42
43    Args:
44        path: Filepath to a folder where the data is downloaded for further processing.
45        download: Whether to download the data if it is not present.
46
47    Returns:
48        Filepath where the data is downloaded.
49    """
50    data_dir = os.path.join(path, "RIGA")
51    if os.path.exists(data_dir):
52        return path
53
54    os.makedirs(path, exist_ok=True)
55
56    zip_path = os.path.join(path, "RIGAPlus.zip")
57    util.download_source(path=zip_path, url=URL, download=download, checksum=CHECKSUM)
58    util.unzip(zip_path=zip_path, dst=path)
59
60    return path

Download the RIGA+ 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.
Returns:

Filepath where the data is downloaded.

def get_riga_plus_paths( path: Union[os.PathLike, str], split: Literal['train', 'test'], domain: Union[str, List[str]] = ['BinRushed', 'Magrabia', 'MESSIDOR_Base1', 'MESSIDOR_Base2', 'MESSIDOR_Base3'], rater: int = 1, download: bool = False) -> Tuple[List[str], List[str]]:
 63def get_riga_plus_paths(
 64    path: Union[os.PathLike, str],
 65    split: Literal["train", "test"],
 66    domain: Union[str, List[str]] = DOMAINS,
 67    rater: int = 1,
 68    download: bool = False,
 69) -> Tuple[List[str], List[str]]:
 70    """Get paths to the RIGA+ data.
 71
 72    Args:
 73        path: Filepath to a folder where the data is downloaded for further processing.
 74        split: The choice of data split, as provided by the official 'train' / 'test' csv files.
 75        domain: The choice of domain(s) to use. One or several of 'BinRushed', 'Magrabia',
 76            'MESSIDOR_Base1', 'MESSIDOR_Base2' and 'MESSIDOR_Base3'.
 77        rater: The choice of rater (1 to 6) for the ground-truth optic disc / cup masks.
 78        download: Whether to download the data if it is not present.
 79
 80    Returns:
 81        List of filepaths for the image data.
 82        List of filepaths for the label data.
 83    """
 84    root_dir = get_riga_plus_data(path=path, download=download)
 85
 86    assert split in ["train", "test"], f"'{split}' is not a valid split."
 87    assert 1 <= rater <= 6, f"'{rater}' is not a valid rater choice, must be in [1, 6]."
 88
 89    domains = [domain] if isinstance(domain, str) else domain
 90    for d in domains:
 91        assert d in DOMAINS, f"'{d}' is not a valid domain, must be one of {DOMAINS}."
 92
 93    image_paths, gt_paths = [], []
 94    for d in domains:
 95        csv_path = os.path.join(root_dir, f"{d}_{split}.csv")
 96        df = pd.read_csv(csv_path)
 97        for image_rel_path, mask_rel_path in zip(df["image"], df["mask"]):
 98            stem, ext = os.path.splitext(mask_rel_path)
 99            image_paths.append(os.path.join(root_dir, image_rel_path))
100            gt_paths.append(os.path.join(root_dir, f"{stem}-{rater}{ext}"))
101
102    assert len(image_paths) == len(gt_paths) and len(image_paths) > 0
103    for image_path, gt_path in zip(image_paths, gt_paths):
104        assert os.path.exists(image_path), image_path
105        assert os.path.exists(gt_path), gt_path
106
107    return image_paths, gt_paths

Get paths to the RIGA+ data.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • split: The choice of data split, as provided by the official 'train' / 'test' csv files.
  • domain: The choice of domain(s) to use. One or several of 'BinRushed', 'Magrabia', 'MESSIDOR_Base1', 'MESSIDOR_Base2' and 'MESSIDOR_Base3'.
  • rater: The choice of rater (1 to 6) for the ground-truth optic disc / cup masks.
  • 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.

def get_riga_plus_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], split: Literal['train', 'test'], domain: Union[str, List[str]] = ['BinRushed', 'Magrabia', 'MESSIDOR_Base1', 'MESSIDOR_Base2', 'MESSIDOR_Base3'], rater: int = 1, resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
110def get_riga_plus_dataset(
111    path: Union[os.PathLike, str],
112    patch_shape: Tuple[int, int],
113    split: Literal["train", "test"],
114    domain: Union[str, List[str]] = DOMAINS,
115    rater: int = 1,
116    resize_inputs: bool = False,
117    download: bool = False,
118    **kwargs
119) -> Dataset:
120    """Get the RIGA+ dataset for segmentation of optic disc and optic cup in fundus images.
121
122    Args:
123        path: Filepath to a folder where the data is downloaded for further processing.
124        patch_shape: The patch shape to use for training.
125        split: The choice of data split.
126        domain: The choice of domain(s) to use.
127        rater: The choice of rater for the ground-truth optic disc / cup masks.
128        resize_inputs: Whether to resize the inputs to the expected patch shape.
129        download: Whether to download the data if it is not present.
130        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
131
132    Returns:
133        The segmentation dataset.
134    """
135    image_paths, gt_paths = get_riga_plus_paths(path, split, domain, rater, download)
136
137    if resize_inputs:
138        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
139        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
140            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
141        )
142
143    return torch_em.default_segmentation_dataset(
144        raw_paths=image_paths,
145        raw_key=None,
146        label_paths=gt_paths,
147        label_key=None,
148        patch_shape=patch_shape,
149        is_seg_dataset=False,
150        **kwargs
151    )

Get the RIGA+ dataset for segmentation of optic disc and optic cup 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.
  • domain: The choice of domain(s) to use.
  • rater: The choice of rater for the ground-truth optic disc / cup masks.
  • resize_inputs: Whether to resize the inputs to the expected 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.

def get_riga_plus_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], split: Literal['train', 'test'], domain: Union[str, List[str]] = ['BinRushed', 'Magrabia', 'MESSIDOR_Base1', 'MESSIDOR_Base2', 'MESSIDOR_Base3'], rater: int = 1, resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
154def get_riga_plus_loader(
155    path: Union[os.PathLike, str],
156    batch_size: int,
157    patch_shape: Tuple[int, int],
158    split: Literal["train", "test"],
159    domain: Union[str, List[str]] = DOMAINS,
160    rater: int = 1,
161    resize_inputs: bool = False,
162    download: bool = False,
163    **kwargs
164) -> DataLoader:
165    """Get the RIGA+ dataloader for segmentation of optic disc and optic cup in fundus images.
166
167    Args:
168        path: Filepath to a folder where the data is downloaded for further processing.
169        batch_size: The batch size for training.
170        patch_shape: The patch shape to use for training.
171        split: The choice of data split.
172        domain: The choice of domain(s) to use.
173        rater: The choice of rater for the ground-truth optic disc / cup masks.
174        resize_inputs: Whether to resize the inputs to the expected patch shape.
175        download: Whether to download the data if it is not present.
176        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
177
178    Returns:
179        The DataLoader.
180    """
181    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
182    dataset = get_riga_plus_dataset(path, patch_shape, split, domain, rater, resize_inputs, download, **ds_kwargs)
183    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the RIGA+ dataloader for segmentation of optic disc and optic cup 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.
  • domain: The choice of domain(s) to use.
  • rater: The choice of rater for the ground-truth optic disc / cup masks.
  • resize_inputs: Whether to resize the inputs to the expected patch shape.
  • download: Whether to download the data if it is not present.
  • kwargs: Additional keyword arguments for torch_em.default_segmentation_dataset or for the PyTorch DataLoader.
Returns:

The DataLoader.