torch_em.data.datasets.light_microscopy.flywing

The FlyWing dataset contains annotated fluorescence microscopy images of Drosophila wing epithelia.

This loader uses the zero-noise segmentation release published with DenoiSeg. It contains 1428 training and 252 validation patches of shape 128 x 128, as well as 42 test images of shape 512 x 512. The data is derived from the epithelial cell tracking benchmark introduced in https://doi.org/10.1007/978-3-030-11024-6_33.

The dataset is located at https://doi.org/10.5281/zenodo.5156991 under the CC BY 4.0 license. This release does not contain the eight complete time-lapse movies used by the original tracking benchmark or its movie-level splits. It is from the publication https://doi.org/10.1007/978-3-030-66415-2_21. Please cite the dataset and publications if you use this dataset in your research.

  1"""The FlyWing dataset contains annotated fluorescence microscopy images of Drosophila wing epithelia.
  2
  3This loader uses the zero-noise segmentation release published with DenoiSeg. It contains 1428 training and
  4252 validation patches of shape 128 x 128, as well as 42 test images of shape 512 x 512. The data is derived from
  5the epithelial cell tracking benchmark introduced in https://doi.org/10.1007/978-3-030-11024-6_33.
  6
  7The dataset is located at https://doi.org/10.5281/zenodo.5156991 under the CC BY 4.0 license. This release does
  8not contain the eight complete time-lapse movies used by the original tracking benchmark or its movie-level splits.
  9It is from the publication https://doi.org/10.1007/978-3-030-66415-2_21. Please cite the dataset and publications
 10if you use this dataset in your research.
 11"""
 12
 13import os
 14from glob import glob
 15from typing import List, Literal, Optional, Tuple, Union
 16
 17import imageio.v3 as imageio
 18import numpy as np
 19from natsort import natsorted
 20from torch.utils.data import DataLoader, Dataset
 21from tqdm import tqdm
 22
 23import torch_em
 24
 25from .. import util
 26
 27
 28URL = "https://zenodo.org/api/records/5156991/files/Flywing_n0.zip/content"
 29CHECKSUM = "3fb49ba44e7e3e20b4fc3c77754f1bbff7184af7f343f23653f258d50e5d5aca"
 30
 31SPLIT_INFO = {
 32    "train": ("train/train_data.npz", "X_train", "Y_train", 1428),
 33    "val": ("train/train_data.npz", "X_val", "Y_val", 252),
 34    "test": ("test/test_data.npz", "X_test", "Y_test", 42),
 35}
 36
 37
 38def _get_split_paths(data_dir: str, split: str) -> Tuple[List[str], List[str]]:
 39    raw_paths = natsorted(glob(os.path.join(data_dir, split, "images", "*.tif")))
 40    label_paths = natsorted(glob(os.path.join(data_dir, split, "labels", "*.tif")))
 41    return raw_paths, label_paths
 42
 43
 44def _is_complete(data_dir: str, split: str) -> bool:
 45    raw_paths, label_paths = _get_split_paths(data_dir, split)
 46    expected_images = SPLIT_INFO[split][3]
 47    return (
 48        len(raw_paths) == expected_images
 49        and len(label_paths) == expected_images
 50        and [os.path.basename(path) for path in raw_paths] == [os.path.basename(path) for path in label_paths]
 51    )
 52
 53
 54def _preprocess_split(data_dir: str, split: str) -> None:
 55    npz_name, raw_key, label_key, expected_images = SPLIT_INFO[split]
 56    npz_path = os.path.join(data_dir, npz_name)
 57    if not os.path.exists(npz_path):
 58        raise RuntimeError(f"Could not find the FlyWing source data at '{npz_path}'.")
 59
 60    raw_dir = os.path.join(data_dir, split, "images")
 61    label_dir = os.path.join(data_dir, split, "labels")
 62    os.makedirs(raw_dir, exist_ok=True)
 63    os.makedirs(label_dir, exist_ok=True)
 64
 65    with np.load(npz_path) as data:
 66        raw = data[raw_key]
 67        labels = data[label_key]
 68        if raw.shape != labels.shape or len(raw) != expected_images:
 69            raise RuntimeError(
 70                f"Unexpected FlyWing data for split '{split}': raw={raw.shape}, labels={labels.shape}."
 71            )
 72
 73        for index, (image, instances) in tqdm(
 74            enumerate(zip(raw, labels)), total=expected_images, desc=f"Preprocessing FlyWing '{split}' split"
 75        ):
 76            filename = f"image_{index:04d}.tif"
 77            raw_path = os.path.join(raw_dir, filename)
 78            label_path = os.path.join(label_dir, filename)
 79            if not os.path.exists(raw_path):
 80                imageio.imwrite(raw_path, image, compression="zlib")
 81            if not os.path.exists(label_path):
 82                imageio.imwrite(label_path, instances, compression="zlib")
 83
 84
 85def get_flywing_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 86    """Download and preprocess the FlyWing segmentation dataset.
 87
 88    Args:
 89        path: Filepath to a folder where the downloaded data will be saved.
 90        download: Whether to download the data if it is not present.
 91
 92    Returns:
 93        The filepath to the preprocessed data.
 94    """
 95    data_dir = os.path.join(path, "Flywing_n0")
 96    if all(_is_complete(data_dir, split) for split in SPLIT_INFO):
 97        return data_dir
 98
 99    os.makedirs(path, exist_ok=True)
100    if not all(os.path.exists(os.path.join(data_dir, info[0])) for info in SPLIT_INFO.values()):
101        zip_path = os.path.join(path, "Flywing_n0.zip")
102        util.download_source(zip_path, URL, download, CHECKSUM)
103        util.unzip(zip_path, path)
104
105    for split in SPLIT_INFO:
106        if not _is_complete(data_dir, split):
107            _preprocess_split(data_dir, split)
108
109    incomplete_splits = [split for split in SPLIT_INFO if not _is_complete(data_dir, split)]
110    if incomplete_splits:
111        raise RuntimeError(f"FlyWing preprocessing failed for splits: {incomplete_splits}.")
112    return data_dir
113
114
115def get_flywing_paths(
116    path: Union[os.PathLike, str], split: Literal["train", "val", "test"], download: bool = False,
117) -> Tuple[List[str], List[str]]:
118    """Get paths to the FlyWing fluorescence images and cell instance labels.
119
120    Args:
121        path: Filepath to a folder where the downloaded data will be saved.
122        split: The data split. Either 'train', 'val' or 'test'.
123        download: Whether to download the data if it is not present.
124
125    Returns:
126        The image paths and corresponding label paths.
127    """
128    if split not in SPLIT_INFO:
129        raise ValueError(f"'{split}' is not a valid split. Choose from {list(SPLIT_INFO)}.")
130
131    data_dir = get_flywing_data(path, download)
132    raw_paths, label_paths = _get_split_paths(data_dir, split)
133    return raw_paths, label_paths
134
135
136def get_flywing_dataset(
137    path: Union[os.PathLike, str],
138    patch_shape: Tuple[int, int],
139    split: Literal["train", "val", "test"],
140    offsets: Optional[List[List[int]]] = None,
141    boundaries: bool = False,
142    binary: bool = False,
143    download: bool = False,
144    **kwargs,
145) -> Dataset:
146    """Get the FlyWing dataset for epithelial cell instance segmentation.
147
148    Args:
149        path: Filepath to a folder where the downloaded data will be saved.
150        patch_shape: The 2D patch shape to use for training.
151        split: The data split. Either 'train', 'val' or 'test'.
152        offsets: Offset values for affinity computation used as target.
153        boundaries: Whether to compute boundaries as the target.
154        binary: Whether to use a binary segmentation target.
155        download: Whether to download the data if it is not present.
156        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
157
158    Returns:
159        The segmentation dataset.
160    """
161    if len(patch_shape) != 2:
162        raise ValueError(f"The FlyWing patch shape must be two-dimensional, got {patch_shape}.")
163
164    raw_paths, label_paths = get_flywing_paths(path, split, download)
165    kwargs, _ = util.add_instance_label_transform(
166        kwargs, add_binary_target=True, offsets=offsets, boundaries=boundaries, binary=binary,
167    )
168    kwargs = util.ensure_transforms(ndim=2, **kwargs)
169
170    return torch_em.default_segmentation_dataset(
171        raw_paths=raw_paths,
172        raw_key=None,
173        label_paths=label_paths,
174        label_key=None,
175        patch_shape=patch_shape,
176        is_seg_dataset=False,
177        **kwargs,
178    )
179
180
181def get_flywing_loader(
182    path: Union[os.PathLike, str],
183    batch_size: int,
184    patch_shape: Tuple[int, int],
185    split: Literal["train", "val", "test"],
186    offsets: Optional[List[List[int]]] = None,
187    boundaries: bool = False,
188    binary: bool = False,
189    download: bool = False,
190    **kwargs,
191) -> DataLoader:
192    """Get the FlyWing dataloader for epithelial cell instance segmentation.
193
194    Args:
195        path: Filepath to a folder where the downloaded data will be saved.
196        batch_size: The batch size for training.
197        patch_shape: The 2D patch shape to use for training.
198        split: The data split. Either 'train', 'val' or 'test'.
199        offsets: Offset values for affinity computation used as target.
200        boundaries: Whether to compute boundaries as the target.
201        binary: Whether to use a binary segmentation target.
202        download: Whether to download the data if it is not present.
203        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or the PyTorch DataLoader.
204
205    Returns:
206        The DataLoader.
207    """
208    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
209    dataset = get_flywing_dataset(
210        path=path,
211        patch_shape=patch_shape,
212        split=split,
213        offsets=offsets,
214        boundaries=boundaries,
215        binary=binary,
216        download=download,
217        **ds_kwargs,
218    )
219    return torch_em.get_data_loader(dataset, batch_size=batch_size, **loader_kwargs)
URL = 'https://zenodo.org/api/records/5156991/files/Flywing_n0.zip/content'
CHECKSUM = '3fb49ba44e7e3e20b4fc3c77754f1bbff7184af7f343f23653f258d50e5d5aca'
SPLIT_INFO = {'train': ('train/train_data.npz', 'X_train', 'Y_train', 1428), 'val': ('train/train_data.npz', 'X_val', 'Y_val', 252), 'test': ('test/test_data.npz', 'X_test', 'Y_test', 42)}
def get_flywing_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 86def get_flywing_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 87    """Download and preprocess the FlyWing segmentation dataset.
 88
 89    Args:
 90        path: Filepath to a folder where the downloaded data will be saved.
 91        download: Whether to download the data if it is not present.
 92
 93    Returns:
 94        The filepath to the preprocessed data.
 95    """
 96    data_dir = os.path.join(path, "Flywing_n0")
 97    if all(_is_complete(data_dir, split) for split in SPLIT_INFO):
 98        return data_dir
 99
100    os.makedirs(path, exist_ok=True)
101    if not all(os.path.exists(os.path.join(data_dir, info[0])) for info in SPLIT_INFO.values()):
102        zip_path = os.path.join(path, "Flywing_n0.zip")
103        util.download_source(zip_path, URL, download, CHECKSUM)
104        util.unzip(zip_path, path)
105
106    for split in SPLIT_INFO:
107        if not _is_complete(data_dir, split):
108            _preprocess_split(data_dir, split)
109
110    incomplete_splits = [split for split in SPLIT_INFO if not _is_complete(data_dir, split)]
111    if incomplete_splits:
112        raise RuntimeError(f"FlyWing preprocessing failed for splits: {incomplete_splits}.")
113    return data_dir

Download and preprocess the FlyWing segmentation dataset.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • download: Whether to download the data if it is not present.
Returns:

The filepath to the preprocessed data.

def get_flywing_paths( path: Union[os.PathLike, str], split: Literal['train', 'val', 'test'], download: bool = False) -> Tuple[List[str], List[str]]:
116def get_flywing_paths(
117    path: Union[os.PathLike, str], split: Literal["train", "val", "test"], download: bool = False,
118) -> Tuple[List[str], List[str]]:
119    """Get paths to the FlyWing fluorescence images and cell instance labels.
120
121    Args:
122        path: Filepath to a folder where the downloaded data will be saved.
123        split: The data split. Either 'train', 'val' or 'test'.
124        download: Whether to download the data if it is not present.
125
126    Returns:
127        The image paths and corresponding label paths.
128    """
129    if split not in SPLIT_INFO:
130        raise ValueError(f"'{split}' is not a valid split. Choose from {list(SPLIT_INFO)}.")
131
132    data_dir = get_flywing_data(path, download)
133    raw_paths, label_paths = _get_split_paths(data_dir, split)
134    return raw_paths, label_paths

Get paths to the FlyWing fluorescence images and cell instance labels.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • split: The data split. Either 'train', 'val' or 'test'.
  • download: Whether to download the data if it is not present.
Returns:

The image paths and corresponding label paths.

def get_flywing_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], split: Literal['train', 'val', 'test'], offsets: Optional[List[List[int]]] = None, boundaries: bool = False, binary: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
137def get_flywing_dataset(
138    path: Union[os.PathLike, str],
139    patch_shape: Tuple[int, int],
140    split: Literal["train", "val", "test"],
141    offsets: Optional[List[List[int]]] = None,
142    boundaries: bool = False,
143    binary: bool = False,
144    download: bool = False,
145    **kwargs,
146) -> Dataset:
147    """Get the FlyWing dataset for epithelial cell instance segmentation.
148
149    Args:
150        path: Filepath to a folder where the downloaded data will be saved.
151        patch_shape: The 2D patch shape to use for training.
152        split: The data split. Either 'train', 'val' or 'test'.
153        offsets: Offset values for affinity computation used as target.
154        boundaries: Whether to compute boundaries as the target.
155        binary: Whether to use a binary segmentation target.
156        download: Whether to download the data if it is not present.
157        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
158
159    Returns:
160        The segmentation dataset.
161    """
162    if len(patch_shape) != 2:
163        raise ValueError(f"The FlyWing patch shape must be two-dimensional, got {patch_shape}.")
164
165    raw_paths, label_paths = get_flywing_paths(path, split, download)
166    kwargs, _ = util.add_instance_label_transform(
167        kwargs, add_binary_target=True, offsets=offsets, boundaries=boundaries, binary=binary,
168    )
169    kwargs = util.ensure_transforms(ndim=2, **kwargs)
170
171    return torch_em.default_segmentation_dataset(
172        raw_paths=raw_paths,
173        raw_key=None,
174        label_paths=label_paths,
175        label_key=None,
176        patch_shape=patch_shape,
177        is_seg_dataset=False,
178        **kwargs,
179    )

Get the FlyWing dataset for epithelial cell instance segmentation.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • patch_shape: The 2D patch shape to use for training.
  • split: The data split. Either 'train', 'val' or 'test'.
  • offsets: Offset values for affinity computation used as target.
  • boundaries: Whether to compute boundaries as the target.
  • binary: Whether to use a binary segmentation target.
  • 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_flywing_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], split: Literal['train', 'val', 'test'], offsets: Optional[List[List[int]]] = None, boundaries: bool = False, binary: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
182def get_flywing_loader(
183    path: Union[os.PathLike, str],
184    batch_size: int,
185    patch_shape: Tuple[int, int],
186    split: Literal["train", "val", "test"],
187    offsets: Optional[List[List[int]]] = None,
188    boundaries: bool = False,
189    binary: bool = False,
190    download: bool = False,
191    **kwargs,
192) -> DataLoader:
193    """Get the FlyWing dataloader for epithelial cell instance segmentation.
194
195    Args:
196        path: Filepath to a folder where the downloaded data will be saved.
197        batch_size: The batch size for training.
198        patch_shape: The 2D patch shape to use for training.
199        split: The data split. Either 'train', 'val' or 'test'.
200        offsets: Offset values for affinity computation used as target.
201        boundaries: Whether to compute boundaries as the target.
202        binary: Whether to use a binary segmentation target.
203        download: Whether to download the data if it is not present.
204        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or the PyTorch DataLoader.
205
206    Returns:
207        The DataLoader.
208    """
209    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
210    dataset = get_flywing_dataset(
211        path=path,
212        patch_shape=patch_shape,
213        split=split,
214        offsets=offsets,
215        boundaries=boundaries,
216        binary=binary,
217        download=download,
218        **ds_kwargs,
219    )
220    return torch_em.get_data_loader(dataset, batch_size=batch_size, **loader_kwargs)

Get the FlyWing dataloader for epithelial cell instance segmentation.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • batch_size: The batch size for training.
  • patch_shape: The 2D patch shape to use for training.
  • split: The data split. Either 'train', 'val' or 'test'.
  • offsets: Offset values for affinity computation used as target.
  • boundaries: Whether to compute boundaries as the target.
  • binary: Whether to use a binary segmentation target.
  • download: Whether to download the data if it is not present.
  • kwargs: Additional keyword arguments for torch_em.default_segmentation_dataset or the PyTorch DataLoader.
Returns:

The DataLoader.