torch_em.data.datasets.medical.amd_dme_3d_oct

The AMD-DME-3D-OCT dataset contains annotations for pigment epithelial detachment (PED) and intraretinal fluid (IRF) segmentation in full 3D optical coherence tomography (OCT) volumes.

The dataset consists of 224 volumes (122 AMD and 102 DME), of which 104 (62 AMD, 42 DME) come with volumetric annotations. The remaining 120 volumes are unlabeled and are not used by this loader. Each annotated volume was independently segmented by three junior ophthalmologists, and the resulting masks were reviewed and corrected by an experienced ophthalmologist. The label volumes are binary (PED and IRF are merged into a single foreground class), matching each 512x512x512 raw volume ('.tif') to its mask ('_mask.tif').

NOTE: This is a distinct, volumetric (3D) dataset. It is not the same as the already-integrated torch_em.data.datasets.medical.amd_sd, which ships 2D B-scan annotations for wet AMD lesions only.

The data is located at https://doi.org/10.6084/m9.figshare.30582035, released under a CC-BY-4.0 license. NOTE: The archive is a single ~19.6 GB 7z file, which requires the 'p7zip' CLI to extract (see torch_em.data.datasets.util.unzip_7z).

This dataset is from the publication https://doi.org/10.1038/s41597-025-06497-1. Please cite it if you use this dataset for your research.

  1"""The AMD-DME-3D-OCT dataset contains annotations for pigment epithelial detachment (PED) and
  2intraretinal fluid (IRF) segmentation in full 3D optical coherence tomography (OCT) volumes.
  3
  4The dataset consists of 224 volumes (122 AMD and 102 DME), of which 104 (62 AMD, 42 DME) come with
  5volumetric annotations. The remaining 120 volumes are unlabeled and are not used by this loader.
  6Each annotated volume was independently segmented by three junior ophthalmologists, and the
  7resulting masks were reviewed and corrected by an experienced ophthalmologist. The label volumes
  8are binary (PED and IRF are merged into a single foreground class), matching each 512x512x512 raw
  9volume ('<case><eye><picture>.tif') to its mask ('<case><eye><picture>_mask.tif').
 10
 11NOTE: This is a distinct, volumetric (3D) dataset. It is not the same as the already-integrated
 12`torch_em.data.datasets.medical.amd_sd`, which ships 2D B-scan annotations for wet AMD lesions only.
 13
 14The data is located at https://doi.org/10.6084/m9.figshare.30582035, released under a CC-BY-4.0 license.
 15NOTE: The archive is a single ~19.6 GB 7z file, which requires the 'p7zip' CLI to extract
 16(see `torch_em.data.datasets.util.unzip_7z`).
 17
 18This dataset is from the publication https://doi.org/10.1038/s41597-025-06497-1.
 19Please cite it if you use this dataset for your research.
 20"""
 21
 22import os
 23from glob import glob
 24from natsort import natsorted
 25from typing import Union, Tuple, Literal, List
 26
 27from torch.utils.data import Dataset, DataLoader
 28
 29import torch_em
 30
 31from .. import util
 32
 33
 34URL = "https://ndownloader.figshare.com/files/59443823"
 35CHECKSUM = "31d1e2c581be375654a3d757eaa2710f4e91628b0779c39f2a5d04afe4ba0318"
 36
 37DISEASES = ["AMD", "DME"]
 38
 39
 40def get_amd_dme_3d_oct_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 41    """Download the AMD-DME-3D-OCT 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, "AMD_DME_3D_Dataset")
 51    if all(os.path.exists(os.path.join(data_dir, f"{disease}_labeled")) for disease in DISEASES):
 52        return data_dir
 53
 54    os.makedirs(path, exist_ok=True)
 55
 56    archive_path = os.path.join(path, "AMD_DME_3D_Dataset.7z")
 57    util.download_source(path=archive_path, url=URL, download=download, checksum=CHECKSUM)
 58    util.unzip_7z(path_7z=archive_path, dst=path, remove=False)
 59
 60    assert all(os.path.exists(os.path.join(data_dir, f"{disease}_labeled")) for disease in DISEASES), \
 61        f"The extraction of the AMD-DME-3D-OCT archive did not create the expected folders in '{data_dir}'."
 62
 63    return data_dir
 64
 65
 66def get_amd_dme_3d_oct_paths(
 67    path: Union[os.PathLike, str], disease: Literal["AMD", "DME"] = "AMD", download: bool = False,
 68) -> Tuple[List[str], List[str]]:
 69    """Get paths to the AMD-DME-3D-OCT data.
 70
 71    Args:
 72        path: Filepath to a folder where the data is downloaded for further processing.
 73        disease: The choice of disease. Either 'AMD' or 'DME'.
 74        download: Whether to download the data if it is not present.
 75
 76    Returns:
 77        List of filepaths for the image data.
 78        List of filepaths for the label data.
 79    """
 80    if disease not in DISEASES:
 81        raise ValueError(f"'{disease}' is not a valid choice of disease. Choose one of {DISEASES}.")
 82
 83    data_dir = get_amd_dme_3d_oct_data(path, download)
 84
 85    label_paths = natsorted(glob(os.path.join(data_dir, f"{disease}_labeled", "label", "*_mask.tif")))
 86    raw_paths = [
 87        os.path.join(data_dir, f"{disease}_labeled", "input", os.path.basename(p).replace("_mask.tif", ".tif"))
 88        for p in label_paths
 89    ]
 90
 91    assert len(raw_paths) == len(label_paths) and len(raw_paths) > 0
 92    assert all(os.path.exists(p) for p in raw_paths)
 93
 94    return raw_paths, label_paths
 95
 96
 97def get_amd_dme_3d_oct_dataset(
 98    path: Union[os.PathLike, str],
 99    patch_shape: Tuple[int, int, int],
100    disease: Literal["AMD", "DME"] = "AMD",
101    resize_inputs: bool = False,
102    download: bool = False,
103    **kwargs
104) -> Dataset:
105    """Get the AMD-DME-3D-OCT dataset for PED and IRF segmentation in 3D OCT volumes.
106
107    Args:
108        path: Filepath to a folder where the data is downloaded for further processing.
109        patch_shape: The patch shape to use for training.
110        disease: The choice of disease. Either 'AMD' or 'DME'.
111        resize_inputs: Whether to resize the inputs to the patch shape.
112        download: Whether to download the data if it is not present.
113        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
114
115    Returns:
116        The segmentation dataset.
117    """
118    raw_paths, label_paths = get_amd_dme_3d_oct_paths(path, disease, download)
119
120    if resize_inputs:
121        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False}
122        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
123            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
124        )
125
126    return torch_em.default_segmentation_dataset(
127        raw_paths=raw_paths,
128        raw_key=None,
129        label_paths=label_paths,
130        label_key=None,
131        is_seg_dataset=True,
132        patch_shape=patch_shape,
133        ndim=3,
134        **kwargs
135    )
136
137
138def get_amd_dme_3d_oct_loader(
139    path: Union[os.PathLike, str],
140    batch_size: int,
141    patch_shape: Tuple[int, int, int],
142    disease: Literal["AMD", "DME"] = "AMD",
143    resize_inputs: bool = False,
144    download: bool = False,
145    **kwargs
146) -> DataLoader:
147    """Get the AMD-DME-3D-OCT dataloader for PED and IRF segmentation in 3D OCT volumes.
148
149    Args:
150        path: Filepath to a folder where the data is downloaded for further processing.
151        batch_size: The batch size for training.
152        patch_shape: The patch shape to use for training.
153        disease: The choice of disease. Either 'AMD' or 'DME'.
154        resize_inputs: Whether to resize the inputs to the patch shape.
155        download: Whether to download the data if it is not present.
156        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
157
158    Returns:
159        The DataLoader.
160    """
161    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
162    dataset = get_amd_dme_3d_oct_dataset(path, patch_shape, disease, resize_inputs, download, **ds_kwargs)
163    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
URL = 'https://ndownloader.figshare.com/files/59443823'
CHECKSUM = '31d1e2c581be375654a3d757eaa2710f4e91628b0779c39f2a5d04afe4ba0318'
DISEASES = ['AMD', 'DME']
def get_amd_dme_3d_oct_data(path: Union[os.PathLike, str], download: bool = False) -> str:
41def get_amd_dme_3d_oct_data(path: Union[os.PathLike, str], download: bool = False) -> str:
42    """Download the AMD-DME-3D-OCT dataset.
43
44    Args:
45        path: Filepath to a folder where the data is downloaded for further processing.
46        download: Whether to download the data if it is not present.
47
48    Returns:
49        Filepath where the data is downloaded.
50    """
51    data_dir = os.path.join(path, "AMD_DME_3D_Dataset")
52    if all(os.path.exists(os.path.join(data_dir, f"{disease}_labeled")) for disease in DISEASES):
53        return data_dir
54
55    os.makedirs(path, exist_ok=True)
56
57    archive_path = os.path.join(path, "AMD_DME_3D_Dataset.7z")
58    util.download_source(path=archive_path, url=URL, download=download, checksum=CHECKSUM)
59    util.unzip_7z(path_7z=archive_path, dst=path, remove=False)
60
61    assert all(os.path.exists(os.path.join(data_dir, f"{disease}_labeled")) for disease in DISEASES), \
62        f"The extraction of the AMD-DME-3D-OCT archive did not create the expected folders in '{data_dir}'."
63
64    return data_dir

Download the AMD-DME-3D-OCT 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_amd_dme_3d_oct_paths( path: Union[os.PathLike, str], disease: Literal['AMD', 'DME'] = 'AMD', download: bool = False) -> Tuple[List[str], List[str]]:
67def get_amd_dme_3d_oct_paths(
68    path: Union[os.PathLike, str], disease: Literal["AMD", "DME"] = "AMD", download: bool = False,
69) -> Tuple[List[str], List[str]]:
70    """Get paths to the AMD-DME-3D-OCT data.
71
72    Args:
73        path: Filepath to a folder where the data is downloaded for further processing.
74        disease: The choice of disease. Either 'AMD' or 'DME'.
75        download: Whether to download the data if it is not present.
76
77    Returns:
78        List of filepaths for the image data.
79        List of filepaths for the label data.
80    """
81    if disease not in DISEASES:
82        raise ValueError(f"'{disease}' is not a valid choice of disease. Choose one of {DISEASES}.")
83
84    data_dir = get_amd_dme_3d_oct_data(path, download)
85
86    label_paths = natsorted(glob(os.path.join(data_dir, f"{disease}_labeled", "label", "*_mask.tif")))
87    raw_paths = [
88        os.path.join(data_dir, f"{disease}_labeled", "input", os.path.basename(p).replace("_mask.tif", ".tif"))
89        for p in label_paths
90    ]
91
92    assert len(raw_paths) == len(label_paths) and len(raw_paths) > 0
93    assert all(os.path.exists(p) for p in raw_paths)
94
95    return raw_paths, label_paths

Get paths to the AMD-DME-3D-OCT data.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • disease: The choice of disease. Either 'AMD' or 'DME'.
  • 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_amd_dme_3d_oct_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int, int], disease: Literal['AMD', 'DME'] = 'AMD', resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
 98def get_amd_dme_3d_oct_dataset(
 99    path: Union[os.PathLike, str],
100    patch_shape: Tuple[int, int, int],
101    disease: Literal["AMD", "DME"] = "AMD",
102    resize_inputs: bool = False,
103    download: bool = False,
104    **kwargs
105) -> Dataset:
106    """Get the AMD-DME-3D-OCT dataset for PED and IRF segmentation in 3D OCT volumes.
107
108    Args:
109        path: Filepath to a folder where the data is downloaded for further processing.
110        patch_shape: The patch shape to use for training.
111        disease: The choice of disease. Either 'AMD' or 'DME'.
112        resize_inputs: Whether to resize the inputs to the patch shape.
113        download: Whether to download the data if it is not present.
114        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
115
116    Returns:
117        The segmentation dataset.
118    """
119    raw_paths, label_paths = get_amd_dme_3d_oct_paths(path, disease, download)
120
121    if resize_inputs:
122        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False}
123        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
124            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
125        )
126
127    return torch_em.default_segmentation_dataset(
128        raw_paths=raw_paths,
129        raw_key=None,
130        label_paths=label_paths,
131        label_key=None,
132        is_seg_dataset=True,
133        patch_shape=patch_shape,
134        ndim=3,
135        **kwargs
136    )

Get the AMD-DME-3D-OCT dataset for PED and IRF segmentation in 3D OCT volumes.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • patch_shape: The patch shape to use for training.
  • disease: The choice of disease. Either 'AMD' or 'DME'.
  • resize_inputs: Whether to resize the inputs to the 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_amd_dme_3d_oct_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int, int], disease: Literal['AMD', 'DME'] = 'AMD', resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
139def get_amd_dme_3d_oct_loader(
140    path: Union[os.PathLike, str],
141    batch_size: int,
142    patch_shape: Tuple[int, int, int],
143    disease: Literal["AMD", "DME"] = "AMD",
144    resize_inputs: bool = False,
145    download: bool = False,
146    **kwargs
147) -> DataLoader:
148    """Get the AMD-DME-3D-OCT dataloader for PED and IRF segmentation in 3D OCT volumes.
149
150    Args:
151        path: Filepath to a folder where the data is downloaded for further processing.
152        batch_size: The batch size for training.
153        patch_shape: The patch shape to use for training.
154        disease: The choice of disease. Either 'AMD' or 'DME'.
155        resize_inputs: Whether to resize the inputs to the patch shape.
156        download: Whether to download the data if it is not present.
157        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
158
159    Returns:
160        The DataLoader.
161    """
162    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
163    dataset = get_amd_dme_3d_oct_dataset(path, patch_shape, disease, resize_inputs, download, **ds_kwargs)
164    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the AMD-DME-3D-OCT dataloader for PED and IRF segmentation in 3D OCT volumes.

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.
  • disease: The choice of disease. Either 'AMD' or 'DME'.
  • resize_inputs: Whether to resize the inputs to the 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.