torch_em.data.datasets.medical.cadis

The CaDIS dataset contains annotations for anatomy and surgical instrument segmentation in RGB video frames of cataract surgery.

The dataset consists of 4670 frames sampled from 25 videos of the training set of the CATARACTS challenge (https://cataracts.grand-challenge.org). Each frame is densely labeled at the pixel level into up to 36 semantic classes: 4 anatomical structures (pupil, iris, cornea, skin), 29 surgical instrument classes and 3 other object classes (surgical tape, hand, eye retractors). The labels are stored as single-channel images, where the pixel value is the class index.

NOTE: The official train/val/test split assigns videos 5, 7 and 16 to validation and videos 2, 12 and 22 to test, with the remaining videos used for training (see VAL_VIDEOS and TEST_VIDEOS).

NOTE: The dataset is hosted on the CATARACTS Grand Challenge platform at https://cataracts.grand-challenge.org/CaDIS/ and requires registration, so it cannot be downloaded automatically. As of writing this, the direct download link on that page is not yet public ("Uploading - Link coming up soon"), so the data must currently be requested from the challenge organizers. To obtain it:

  • Visit https://cataracts.grand-challenge.org/CaDIS/ and register / log in via the challenge portal.
  • Follow the instructions on the 'Data' / 'Download' pages of the challenge to request access to CaDIS.
  • Once you have the data, place it such that each video folder is located at '/CADIS/segmentation/Video/Images/' and '/CADIS/segmentation/Video/Labels/', matching the structure of the original release.

This dataset is from the publication https://doi.org/10.1016/j.media.2021.102053. Please cite it if you use this dataset in your research.

  1"""The CaDIS dataset contains annotations for anatomy and surgical instrument segmentation
  2in RGB video frames of cataract surgery.
  3
  4The dataset consists of 4670 frames sampled from 25 videos of the training set of the CATARACTS
  5challenge (https://cataracts.grand-challenge.org). Each frame is densely labeled at the pixel level
  6into up to 36 semantic classes: 4 anatomical structures (pupil, iris, cornea, skin), 29 surgical
  7instrument classes and 3 other object classes (surgical tape, hand, eye retractors). The labels are
  8stored as single-channel images, where the pixel value is the class index.
  9
 10NOTE: The official train/val/test split assigns videos 5, 7 and 16 to validation and videos 2, 12
 11and 22 to test, with the remaining videos used for training (see `VAL_VIDEOS` and `TEST_VIDEOS`).
 12
 13NOTE: The dataset is hosted on the CATARACTS Grand Challenge platform at
 14https://cataracts.grand-challenge.org/CaDIS/ and requires registration, so it cannot be downloaded
 15automatically. As of writing this, the direct download link on that page is not yet public
 16("Uploading - Link coming up soon"), so the data must currently be requested from the challenge
 17organizers. To obtain it:
 18- Visit https://cataracts.grand-challenge.org/CaDIS/ and register / log in via the challenge portal.
 19- Follow the instructions on the 'Data' / 'Download' pages of the challenge to request access to CaDIS.
 20- Once you have the data, place it such that each video folder is located at
 21  '<path>/CADIS/segmentation/Video<NN>/Images/*' and '<path>/CADIS/segmentation/Video<NN>/Labels/*',
 22  matching the structure of the original release.
 23
 24This dataset is from the publication https://doi.org/10.1016/j.media.2021.102053.
 25Please cite it if you use this dataset in your research.
 26"""
 27
 28import os
 29import re
 30from glob import glob
 31from natsort import natsorted
 32from typing import Union, Tuple, List, Literal
 33
 34from torch.utils.data import Dataset, DataLoader
 35
 36import torch_em
 37
 38from .. import util
 39
 40
 41VAL_VIDEOS = [5, 7, 16]
 42TEST_VIDEOS = [2, 12, 22]
 43
 44IMAGE_EXTENSIONS = ("*.png", "*.jpg", "*.jpeg")
 45
 46
 47def _video_number(video_dir):
 48    match = re.search(r"(\d+)", os.path.basename(video_dir))
 49    if match is None:
 50        raise ValueError(f"Could not parse a video number from '{video_dir}'.")
 51    return int(match.group(1))
 52
 53
 54def get_cadis_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 55    """Obtain the CaDIS dataset.
 56
 57    Args:
 58        path: Filepath to a folder where the manually downloaded data is stored.
 59        download: Whether to download the data if it is not present. The data cannot be downloaded
 60            automatically, so this raises if the data has not been downloaded manually.
 61
 62    Returns:
 63        Filepath to the folder with the per-video 'Images' and 'Labels' subfolders.
 64    """
 65    data_dir = os.path.join(path, "CADIS", "segmentation")
 66    if os.path.exists(data_dir) and glob(os.path.join(data_dir, "Video*")):
 67        return data_dir
 68
 69    msg = "'torch_em' cannot download this dataset, because CaDIS is distributed via the CATARACTS Grand "
 70    msg += "Challenge and requires registration. Please visit 'https://cataracts.grand-challenge.org/CaDIS/', "
 71    msg += "register / log in and request access to the data via the challenge's 'Data' page, then place it "
 72    msg += f"such that video folders are located at '{data_dir}/Video<NN>/Images' and '.../Video<NN>/Labels'."
 73    raise NotImplementedError(msg)
 74
 75
 76def get_cadis_paths(
 77    path: Union[os.PathLike, str], split: Literal["train", "val", "test"], download: bool = False
 78) -> Tuple[List[str], List[str]]:
 79    """Get paths to the CaDIS data.
 80
 81    Args:
 82        path: Filepath to a folder where the manually downloaded data is stored.
 83        split: The choice of data split.
 84        download: Whether to download the data if it is not present.
 85
 86    Returns:
 87        List of filepaths for the image data.
 88        List of filepaths for the label data.
 89    """
 90    data_dir = get_cadis_data(path, download)
 91
 92    video_dirs = natsorted(glob(os.path.join(data_dir, "Video*")))
 93    assert video_dirs, f"Did not find any 'Video*' folders in '{data_dir}'."
 94
 95    if split == "val":
 96        video_dirs = [v for v in video_dirs if _video_number(v) in VAL_VIDEOS]
 97    elif split == "test":
 98        video_dirs = [v for v in video_dirs if _video_number(v) in TEST_VIDEOS]
 99    elif split == "train":
100        video_dirs = [v for v in video_dirs if _video_number(v) not in VAL_VIDEOS + TEST_VIDEOS]
101    else:
102        raise ValueError(f"'{split}' is not a valid split.")
103
104    image_paths, label_paths = [], []
105    for video_dir in video_dirs:
106        vimage_paths = []
107        for ext in IMAGE_EXTENSIONS:
108            vimage_paths.extend(glob(os.path.join(video_dir, "Images", ext)))
109        vimage_paths = natsorted(vimage_paths)
110
111        vlabel_paths = natsorted(glob(os.path.join(video_dir, "Labels", "*.png")))
112
113        assert vimage_paths and len(vimage_paths) == len(vlabel_paths), \
114            f"The images and labels for '{video_dir}' do not match."
115
116        image_paths.extend(vimage_paths)
117        label_paths.extend(vlabel_paths)
118
119    return image_paths, label_paths
120
121
122def get_cadis_dataset(
123    path: Union[os.PathLike, str],
124    patch_shape: Tuple[int, int],
125    split: Literal["train", "val", "test"],
126    resize_inputs: bool = False,
127    download: bool = False,
128    **kwargs
129) -> Dataset:
130    """Get the CaDIS dataset for anatomy and surgical instrument segmentation.
131
132    Args:
133        path: Filepath to a folder where the manually downloaded data is stored.
134        patch_shape: The patch shape to use for training.
135        split: The choice of data split.
136        resize_inputs: Whether to resize inputs to the desired patch shape.
137        download: Whether to download the data if it is not present.
138        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
139
140    Returns:
141        The segmentation dataset.
142    """
143    image_paths, label_paths = get_cadis_paths(path, split, download)
144
145    if resize_inputs:
146        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
147        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
148            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
149        )
150
151    return torch_em.default_segmentation_dataset(
152        raw_paths=image_paths,
153        raw_key=None,
154        label_paths=label_paths,
155        label_key=None,
156        is_seg_dataset=False,
157        patch_shape=patch_shape,
158        **kwargs
159    )
160
161
162def get_cadis_loader(
163    path: Union[os.PathLike, str],
164    batch_size: int,
165    patch_shape: Tuple[int, int],
166    split: Literal["train", "val", "test"],
167    resize_inputs: bool = False,
168    download: bool = False,
169    **kwargs
170) -> DataLoader:
171    """Get the CaDIS dataloader for anatomy and surgical instrument segmentation.
172
173    Args:
174        path: Filepath to a folder where the manually downloaded data is stored.
175        batch_size: The batch size for training.
176        patch_shape: The patch shape to use for training.
177        split: The choice of data split.
178        resize_inputs: Whether to resize inputs to the desired patch shape.
179        download: Whether to download the data if it is not present.
180        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
181
182    Returns:
183        The DataLoader.
184    """
185    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
186    dataset = get_cadis_dataset(path, patch_shape, split, resize_inputs, download, **ds_kwargs)
187    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
VAL_VIDEOS = [5, 7, 16]
TEST_VIDEOS = [2, 12, 22]
IMAGE_EXTENSIONS = ('*.png', '*.jpg', '*.jpeg')
def get_cadis_data(path: Union[os.PathLike, str], download: bool = False) -> str:
55def get_cadis_data(path: Union[os.PathLike, str], download: bool = False) -> str:
56    """Obtain the CaDIS dataset.
57
58    Args:
59        path: Filepath to a folder where the manually downloaded data is stored.
60        download: Whether to download the data if it is not present. The data cannot be downloaded
61            automatically, so this raises if the data has not been downloaded manually.
62
63    Returns:
64        Filepath to the folder with the per-video 'Images' and 'Labels' subfolders.
65    """
66    data_dir = os.path.join(path, "CADIS", "segmentation")
67    if os.path.exists(data_dir) and glob(os.path.join(data_dir, "Video*")):
68        return data_dir
69
70    msg = "'torch_em' cannot download this dataset, because CaDIS is distributed via the CATARACTS Grand "
71    msg += "Challenge and requires registration. Please visit 'https://cataracts.grand-challenge.org/CaDIS/', "
72    msg += "register / log in and request access to the data via the challenge's 'Data' page, then place it "
73    msg += f"such that video folders are located at '{data_dir}/Video<NN>/Images' and '.../Video<NN>/Labels'."
74    raise NotImplementedError(msg)

Obtain the CaDIS dataset.

Arguments:
  • path: Filepath to a folder where the manually downloaded data is stored.
  • download: Whether to download the data if it is not present. The data cannot be downloaded automatically, so this raises if the data has not been downloaded manually.
Returns:

Filepath to the folder with the per-video 'Images' and 'Labels' subfolders.

def get_cadis_paths( path: Union[os.PathLike, str], split: Literal['train', 'val', 'test'], download: bool = False) -> Tuple[List[str], List[str]]:
 77def get_cadis_paths(
 78    path: Union[os.PathLike, str], split: Literal["train", "val", "test"], download: bool = False
 79) -> Tuple[List[str], List[str]]:
 80    """Get paths to the CaDIS data.
 81
 82    Args:
 83        path: Filepath to a folder where the manually downloaded data is stored.
 84        split: The choice of data split.
 85        download: Whether to download the data if it is not present.
 86
 87    Returns:
 88        List of filepaths for the image data.
 89        List of filepaths for the label data.
 90    """
 91    data_dir = get_cadis_data(path, download)
 92
 93    video_dirs = natsorted(glob(os.path.join(data_dir, "Video*")))
 94    assert video_dirs, f"Did not find any 'Video*' folders in '{data_dir}'."
 95
 96    if split == "val":
 97        video_dirs = [v for v in video_dirs if _video_number(v) in VAL_VIDEOS]
 98    elif split == "test":
 99        video_dirs = [v for v in video_dirs if _video_number(v) in TEST_VIDEOS]
100    elif split == "train":
101        video_dirs = [v for v in video_dirs if _video_number(v) not in VAL_VIDEOS + TEST_VIDEOS]
102    else:
103        raise ValueError(f"'{split}' is not a valid split.")
104
105    image_paths, label_paths = [], []
106    for video_dir in video_dirs:
107        vimage_paths = []
108        for ext in IMAGE_EXTENSIONS:
109            vimage_paths.extend(glob(os.path.join(video_dir, "Images", ext)))
110        vimage_paths = natsorted(vimage_paths)
111
112        vlabel_paths = natsorted(glob(os.path.join(video_dir, "Labels", "*.png")))
113
114        assert vimage_paths and len(vimage_paths) == len(vlabel_paths), \
115            f"The images and labels for '{video_dir}' do not match."
116
117        image_paths.extend(vimage_paths)
118        label_paths.extend(vlabel_paths)
119
120    return image_paths, label_paths

Get paths to the CaDIS data.

Arguments:
  • path: Filepath to a folder where the manually downloaded data is stored.
  • split: The choice of data split.
  • 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_cadis_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], split: Literal['train', 'val', 'test'], resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
123def get_cadis_dataset(
124    path: Union[os.PathLike, str],
125    patch_shape: Tuple[int, int],
126    split: Literal["train", "val", "test"],
127    resize_inputs: bool = False,
128    download: bool = False,
129    **kwargs
130) -> Dataset:
131    """Get the CaDIS dataset for anatomy and surgical instrument segmentation.
132
133    Args:
134        path: Filepath to a folder where the manually downloaded data is stored.
135        patch_shape: The patch shape to use for training.
136        split: The choice of data split.
137        resize_inputs: Whether to resize inputs to the desired patch shape.
138        download: Whether to download the data if it is not present.
139        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
140
141    Returns:
142        The segmentation dataset.
143    """
144    image_paths, label_paths = get_cadis_paths(path, split, download)
145
146    if resize_inputs:
147        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
148        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
149            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
150        )
151
152    return torch_em.default_segmentation_dataset(
153        raw_paths=image_paths,
154        raw_key=None,
155        label_paths=label_paths,
156        label_key=None,
157        is_seg_dataset=False,
158        patch_shape=patch_shape,
159        **kwargs
160    )

Get the CaDIS dataset for anatomy and surgical instrument segmentation.

Arguments:
  • path: Filepath to a folder where the manually downloaded data is stored.
  • patch_shape: The patch shape to use for training.
  • split: The choice of data split.
  • 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.

def get_cadis_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], split: Literal['train', 'val', 'test'], resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
163def get_cadis_loader(
164    path: Union[os.PathLike, str],
165    batch_size: int,
166    patch_shape: Tuple[int, int],
167    split: Literal["train", "val", "test"],
168    resize_inputs: bool = False,
169    download: bool = False,
170    **kwargs
171) -> DataLoader:
172    """Get the CaDIS dataloader for anatomy and surgical instrument segmentation.
173
174    Args:
175        path: Filepath to a folder where the manually downloaded data is stored.
176        batch_size: The batch size for training.
177        patch_shape: The patch shape to use for training.
178        split: The choice of data split.
179        resize_inputs: Whether to resize inputs to the desired patch shape.
180        download: Whether to download the data if it is not present.
181        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
182
183    Returns:
184        The DataLoader.
185    """
186    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
187    dataset = get_cadis_dataset(path, patch_shape, split, resize_inputs, download, **ds_kwargs)
188    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the CaDIS dataloader for anatomy and surgical instrument segmentation.

Arguments:
  • path: Filepath to a folder where the manually downloaded data is stored.
  • batch_size: The batch size for training.
  • patch_shape: The patch shape to use for training.
  • split: The choice of data split.
  • 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 or for the PyTorch DataLoader.
Returns:

The DataLoader.