torch_em.data.datasets.medical.cetus

The CETUS dataset contains annotations for left ventricle segmentation in 3D echocardiography of the heart.

The data was curated for the CETUS challenge (Challenge on Endocardial Three-dimensional Ultrasound Segmentation, https://www.creatis.insa-lyon.fr/Challenge/CETUS/), which was held at MICCAI 2014. The public release consists of the 3D echocardiographic sequences of 45 patients. For each patient the end-diastolic (ED) and the end-systolic (ES) frame are extracted and annotated, which gives 90 annotated volumes. The annotation is a binary mask of the left ventricle lumen (the endocardial surface), see LABEL_IDS. The volumes of a single phase can be selected with the 'phase' argument.

The volumes are stored as nifti files with the slice axis last and the masks use the foreground value 255, so they are converted to hdf5 volumes with the slice axis first (the keys are 'raw' and 'labels') and the masks are binarized by this module. The image intensities are 8 bit and the voxels are isotropic.

The data is located at https://humanheart-project.creatis.insa-lyon.fr/database/#collection/62eb991b73e9f0048c3a6c45 and is distributed under the CC BY-NC-SA 4.0 license.

This dataset is from the publication https://doi.org/10.1109/TMI.2015.2503890. Please cite it if you use this dataset in your research.

  1"""The CETUS dataset contains annotations for left ventricle segmentation in
  23D echocardiography of the heart.
  3
  4The data was curated for the CETUS challenge (Challenge on Endocardial Three-dimensional Ultrasound
  5Segmentation, https://www.creatis.insa-lyon.fr/Challenge/CETUS/), which was held at MICCAI 2014. The public
  6release consists of the 3D echocardiographic sequences of 45 patients. For each patient the end-diastolic (ED)
  7and the end-systolic (ES) frame are extracted and annotated, which gives 90 annotated volumes. The annotation
  8is a binary mask of the left ventricle lumen (the endocardial surface), see `LABEL_IDS`. The volumes of a
  9single phase can be selected with the 'phase' argument.
 10
 11The volumes are stored as nifti files with the slice axis last and the masks use the foreground value 255,
 12so they are converted to hdf5 volumes with the slice axis first (the keys are 'raw' and 'labels') and the
 13masks are binarized by this module. The image intensities are 8 bit and the voxels are isotropic.
 14
 15The data is located at https://humanheart-project.creatis.insa-lyon.fr/database/#collection/62eb991b73e9f0048c3a6c45
 16and is distributed under the CC BY-NC-SA 4.0 license.
 17
 18This dataset is from the publication https://doi.org/10.1109/TMI.2015.2503890.
 19Please cite it if you use this dataset in your research.
 20"""
 21
 22import os
 23from glob import glob
 24from tqdm import tqdm
 25from natsort import natsorted
 26from typing import Union, Tuple, List, Literal, Optional
 27
 28import numpy as np
 29
 30from torch.utils.data import Dataset, DataLoader
 31
 32import torch_em
 33
 34from .. import util
 35
 36
 37URL = "https://humanheart-project.creatis.insa-lyon.fr/database/api/v1/folder/62eb9a3e73e9f0048c3a6c46/download"
 38
 39# NOTE: The archive is created on the fly by the girder server, so its checksum changes with every download.
 40CHECKSUM = None
 41
 42LABEL_IDS = {"background": 0, "left_ventricle": 1}
 43
 44PHASES = ["ED", "ES"]
 45
 46N_VOLUMES = 90
 47
 48
 49def _preprocess_inputs(data_dir, preprocessed_dir):
 50    import h5py
 51    import nibabel as nib
 52
 53    case_dirs = natsorted(glob(os.path.join(data_dir, "patient*")))
 54    os.makedirs(preprocessed_dir, exist_ok=True)
 55
 56    for case_dir in tqdm(case_dirs, desc="Preprocessing the CETUS volumes"):
 57        case_id = os.path.basename(case_dir)
 58        for phase in PHASES:
 59            volume_path = os.path.join(preprocessed_dir, f"{case_id}_{phase}.h5")
 60            if os.path.exists(volume_path):
 61                continue
 62
 63            # The transpose maps the nifti axis order (X, Y, Z) to the (Z, Y, X) order used for the volumes.
 64            raw = np.asarray(nib.load(os.path.join(case_dir, f"{case_id}_{phase}.nii.gz")).dataobj).T
 65            mask = np.asarray(nib.load(os.path.join(case_dir, f"{case_id}_{phase}_gt.nii.gz")).dataobj).T
 66
 67            # The intensities are 8 bit values stored as floats and the mask uses the foreground value 255.
 68            raw = np.round(raw).astype("uint8")
 69            labels = (mask > 0).astype("uint8") * LABEL_IDS["left_ventricle"]
 70
 71            # The file is written to a temporary path first, so that an interrupted run leaves no corrupt file.
 72            with h5py.File(f"{volume_path}.tmp", "w") as f:
 73                f.create_dataset("raw", data=raw, compression="gzip")
 74                f.create_dataset("labels", data=labels, compression="gzip")
 75
 76            os.rename(f"{volume_path}.tmp", volume_path)
 77
 78
 79def get_cetus_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 80    """Download the CETUS dataset.
 81
 82    Args:
 83        path: Filepath to a folder where the data is downloaded for further processing.
 84        download: Whether to download the data if it is not present.
 85
 86    Returns:
 87        Filepath where the preprocessed data is stored.
 88    """
 89    preprocessed_dir = os.path.join(path, "preprocessed")
 90    if len(glob(os.path.join(preprocessed_dir, "*.h5"))) == N_VOLUMES:
 91        return preprocessed_dir
 92
 93    os.makedirs(path, exist_ok=True)
 94
 95    data_dir = os.path.join(path, "dataset")
 96    if not os.path.exists(data_dir):
 97        zip_path = os.path.join(path, "CETUS.zip")
 98        util.download_source(path=zip_path, url=URL, download=download, checksum=CHECKSUM)
 99        util.unzip(zip_path=zip_path, dst=path)
100
101    _preprocess_inputs(data_dir, preprocessed_dir)
102    return preprocessed_dir
103
104
105def get_cetus_paths(
106    path: Union[os.PathLike, str], phase: Optional[Literal["ED", "ES"]] = None, download: bool = False
107) -> List[str]:
108    """Get paths to the CETUS data.
109
110    Args:
111        path: Filepath to a folder where the data is downloaded for further processing.
112        phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases are used.
113        download: Whether to download the data if it is not present.
114
115    Returns:
116        List of filepaths for the hdf5 files, which contain the image data ('raw') and the label data ('labels').
117    """
118    if phase is not None and phase not in PHASES:
119        raise ValueError(f"'{phase}' is not a valid cardiac phase. Please choose one of {PHASES}.")
120
121    data_dir = get_cetus_data(path, download)
122    volume_paths = natsorted(glob(os.path.join(data_dir, f"patient*_{'*' if phase is None else phase}.h5")))
123    assert len(volume_paths) > 0
124
125    return volume_paths
126
127
128def get_cetus_dataset(
129    path: Union[os.PathLike, str],
130    patch_shape: Tuple[int, ...],
131    phase: Optional[Literal["ED", "ES"]] = None,
132    resize_inputs: bool = False,
133    download: bool = False,
134    **kwargs
135) -> Dataset:
136    """Get the CETUS dataset for left ventricle segmentation.
137
138    Args:
139        path: Filepath to a folder where the data is downloaded for further processing.
140        patch_shape: The patch shape to use for training.
141        phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases are used.
142        resize_inputs: Whether to resize inputs to the desired patch shape.
143        download: Whether to download the data if it is not present.
144        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
145
146    Returns:
147        The segmentation dataset.
148    """
149    volume_paths = get_cetus_paths(path, phase, download)
150
151    if resize_inputs:
152        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False}
153        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
154            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
155        )
156
157    return torch_em.default_segmentation_dataset(
158        raw_paths=volume_paths,
159        raw_key="raw",
160        label_paths=volume_paths,
161        label_key="labels",
162        patch_shape=patch_shape,
163        is_seg_dataset=True,
164        **kwargs
165    )
166
167
168def get_cetus_loader(
169    path: Union[os.PathLike, str],
170    batch_size: int,
171    patch_shape: Tuple[int, ...],
172    phase: Optional[Literal["ED", "ES"]] = None,
173    resize_inputs: bool = False,
174    download: bool = False,
175    **kwargs
176) -> DataLoader:
177    """Get the CETUS dataloader for left ventricle segmentation.
178
179    Args:
180        path: Filepath to a folder where the data is downloaded for further processing.
181        batch_size: The batch size for training.
182        patch_shape: The patch shape to use for training.
183        phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases are used.
184        resize_inputs: Whether to resize inputs to the desired patch shape.
185        download: Whether to download the data if it is not present.
186        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
187
188    Returns:
189        The DataLoader.
190    """
191    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
192    dataset = get_cetus_dataset(path, patch_shape, phase, resize_inputs, download, **ds_kwargs)
193    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
URL = 'https://humanheart-project.creatis.insa-lyon.fr/database/api/v1/folder/62eb9a3e73e9f0048c3a6c46/download'
CHECKSUM = None
LABEL_IDS = {'background': 0, 'left_ventricle': 1}
PHASES = ['ED', 'ES']
N_VOLUMES = 90
def get_cetus_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 80def get_cetus_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 81    """Download the CETUS dataset.
 82
 83    Args:
 84        path: Filepath to a folder where the data is downloaded for further processing.
 85        download: Whether to download the data if it is not present.
 86
 87    Returns:
 88        Filepath where the preprocessed data is stored.
 89    """
 90    preprocessed_dir = os.path.join(path, "preprocessed")
 91    if len(glob(os.path.join(preprocessed_dir, "*.h5"))) == N_VOLUMES:
 92        return preprocessed_dir
 93
 94    os.makedirs(path, exist_ok=True)
 95
 96    data_dir = os.path.join(path, "dataset")
 97    if not os.path.exists(data_dir):
 98        zip_path = os.path.join(path, "CETUS.zip")
 99        util.download_source(path=zip_path, url=URL, download=download, checksum=CHECKSUM)
100        util.unzip(zip_path=zip_path, dst=path)
101
102    _preprocess_inputs(data_dir, preprocessed_dir)
103    return preprocessed_dir

Download the CETUS 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 preprocessed data is stored.

def get_cetus_paths( path: Union[os.PathLike, str], phase: Optional[Literal['ED', 'ES']] = None, download: bool = False) -> List[str]:
106def get_cetus_paths(
107    path: Union[os.PathLike, str], phase: Optional[Literal["ED", "ES"]] = None, download: bool = False
108) -> List[str]:
109    """Get paths to the CETUS data.
110
111    Args:
112        path: Filepath to a folder where the data is downloaded for further processing.
113        phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases are used.
114        download: Whether to download the data if it is not present.
115
116    Returns:
117        List of filepaths for the hdf5 files, which contain the image data ('raw') and the label data ('labels').
118    """
119    if phase is not None and phase not in PHASES:
120        raise ValueError(f"'{phase}' is not a valid cardiac phase. Please choose one of {PHASES}.")
121
122    data_dir = get_cetus_data(path, download)
123    volume_paths = natsorted(glob(os.path.join(data_dir, f"patient*_{'*' if phase is None else phase}.h5")))
124    assert len(volume_paths) > 0
125
126    return volume_paths

Get paths to the CETUS data.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases are used.
  • download: Whether to download the data if it is not present.
Returns:

List of filepaths for the hdf5 files, which contain the image data ('raw') and the label data ('labels').

def get_cetus_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, ...], phase: Optional[Literal['ED', 'ES']] = None, resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
129def get_cetus_dataset(
130    path: Union[os.PathLike, str],
131    patch_shape: Tuple[int, ...],
132    phase: Optional[Literal["ED", "ES"]] = None,
133    resize_inputs: bool = False,
134    download: bool = False,
135    **kwargs
136) -> Dataset:
137    """Get the CETUS dataset for left ventricle segmentation.
138
139    Args:
140        path: Filepath to a folder where the data is downloaded for further processing.
141        patch_shape: The patch shape to use for training.
142        phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases are used.
143        resize_inputs: Whether to resize inputs to the desired patch shape.
144        download: Whether to download the data if it is not present.
145        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
146
147    Returns:
148        The segmentation dataset.
149    """
150    volume_paths = get_cetus_paths(path, phase, download)
151
152    if resize_inputs:
153        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False}
154        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
155            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
156        )
157
158    return torch_em.default_segmentation_dataset(
159        raw_paths=volume_paths,
160        raw_key="raw",
161        label_paths=volume_paths,
162        label_key="labels",
163        patch_shape=patch_shape,
164        is_seg_dataset=True,
165        **kwargs
166    )

Get the CETUS dataset for left ventricle segmentation.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • patch_shape: The patch shape to use for training.
  • phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases 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.

def get_cetus_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, ...], phase: Optional[Literal['ED', 'ES']] = None, resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
169def get_cetus_loader(
170    path: Union[os.PathLike, str],
171    batch_size: int,
172    patch_shape: Tuple[int, ...],
173    phase: Optional[Literal["ED", "ES"]] = None,
174    resize_inputs: bool = False,
175    download: bool = False,
176    **kwargs
177) -> DataLoader:
178    """Get the CETUS dataloader for left ventricle segmentation.
179
180    Args:
181        path: Filepath to a folder where the data is downloaded for further processing.
182        batch_size: The batch size for training.
183        patch_shape: The patch shape to use for training.
184        phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases are used.
185        resize_inputs: Whether to resize inputs to the desired patch shape.
186        download: Whether to download the data if it is not present.
187        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
188
189    Returns:
190        The DataLoader.
191    """
192    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
193    dataset = get_cetus_dataset(path, patch_shape, phase, resize_inputs, download, **ds_kwargs)
194    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the CETUS dataloader for left ventricle 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.
  • phase: The choice of cardiac phase. Either 'ED' or 'ES'. By default both phases 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 or for the PyTorch DataLoader.
Returns:

The DataLoader.