torch_em.data.datasets.light_microscopy.oocyteseg

The OocyteSeg dataset contains annotations for binary membrane segmentation in transmitted light microscopy images of oocytes from multiple species.

NOTE: The dataset only has semantic (binary) segmentation.

The dataset is from the publication https://doi.org/10.1242/jcs.260281. Please cite it if you use this dataset in your research.

  1"""The OocyteSeg dataset contains annotations for binary membrane segmentation
  2in transmitted light microscopy images of oocytes from multiple species.
  3
  4NOTE: The dataset only has semantic (binary) segmentation.
  5
  6The dataset is from the publication https://doi.org/10.1242/jcs.260281.
  7Please cite it if you use this dataset in your research.
  8"""
  9
 10import os
 11from glob import glob
 12from typing import Union, Literal, Optional, Tuple, List
 13
 14import numpy as np
 15import imageio.v3 as imageio
 16
 17from torch.utils.data import Dataset, DataLoader
 18
 19import torch_em
 20
 21from .. import util
 22
 23
 24URL = "https://zenodo.org/records/6502830/files/SegmentationCortex.tar.gz"
 25# NOTE: This is the sha256 of the archive, which is what `util.download_source` verifies.
 26# Zenodo publishes an md5 (1da5d4fd102d8e903744db424f6114c6), which was stored here previously
 27# and always failed the check, leaving the completed download as a rejected .incomplete file.
 28CHECKSUM = "46852468b41c4e19c28f079de9e7f6ae565e45c8dc89273adb6f3bd7e9b50613"
 29
 30SPECIES = ["mouse", "human", "sea_urchin"]
 31
 32_SUBDIRS = {
 33    "mouse": {
 34        "train": ["exp1", "exp2"],
 35        "test": ["exp1_test", "exp2_test"],
 36    },
 37    "human": {
 38        "train": ["clin1", "clin2"],
 39        "test": ["clin1_test", "clin2_test"],
 40    },
 41    "sea_urchin": {
 42        "train": ["train"],
 43        "test": ["test"],
 44    },
 45}
 46
 47
 48def _preprocess_data(data_dir, processed_dir, species, split):
 49    """Preprocess images and masks to ensure consistent format.
 50
 51    Some sea urchin images are stored as RGB instead of grayscale.
 52    Masks are stored as 0/255 and need to be normalized to 0/1.
 53    This function converts all data to a consistent single-channel uint8 format.
 54    """
 55    img_out_dir = os.path.join(processed_dir, "images")
 56    mask_out_dir = os.path.join(processed_dir, "masks")
 57    os.makedirs(img_out_dir, exist_ok=True)
 58    os.makedirs(mask_out_dir, exist_ok=True)
 59
 60    subdirs = _SUBDIRS[species][split]
 61
 62    for subdir in subdirs:
 63        input_dir = os.path.join(data_dir, species, subdir, "input")
 64        mask_dir = os.path.join(data_dir, species, subdir, "mask")
 65
 66        input_names = {os.path.splitext(f)[0] for f in os.listdir(input_dir) if f.endswith(".png")}
 67        mask_names = {os.path.splitext(f)[0] for f in os.listdir(mask_dir) if f.endswith(".png")}
 68        matched = sorted(input_names & mask_names)
 69
 70        for name in matched:
 71            img_out = os.path.join(img_out_dir, f"{subdir}_{name}.tif")
 72            mask_out = os.path.join(mask_out_dir, f"{subdir}_{name}.tif")
 73
 74            if os.path.exists(img_out) and os.path.exists(mask_out):
 75                continue
 76
 77            img = imageio.imread(os.path.join(input_dir, f"{name}.png"))
 78            if img.ndim == 3:
 79                img = np.mean(img[..., :3], axis=-1).astype("uint8")
 80            imageio.imwrite(img_out, img, compression="zlib")
 81
 82            mask = imageio.imread(os.path.join(mask_dir, f"{name}.png"))
 83            if mask.ndim == 3:
 84                mask = mask[..., 0]
 85            mask = (mask > 0).astype("uint8")
 86            imageio.imwrite(mask_out, mask, compression="zlib")
 87
 88
 89def get_oocyteseg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 90    """Download the OocyteSeg dataset.
 91
 92    Args:
 93        path: Filepath to a folder where the downloaded data will be saved.
 94        download: Whether to download the data if it is not present.
 95
 96    Returns:
 97        The filepath to the extracted data directory.
 98    """
 99    data_dir = os.path.join(path, "SegmentationCortex")
100    if os.path.exists(data_dir):
101        return data_dir
102
103    os.makedirs(path, exist_ok=True)
104    tar_path = os.path.join(path, "SegmentationCortex.tar.gz")
105    util.download_source(path=tar_path, url=URL, download=download, checksum=CHECKSUM)
106    util.unzip_tarfile(tar_path=tar_path, dst=path)
107
108    return data_dir
109
110
111def get_oocyteseg_paths(
112    path: Union[os.PathLike, str],
113    split: Literal["train", "test"] = "train",
114    species: Optional[str] = None,
115    download: bool = False,
116) -> Tuple[List[str], List[str]]:
117    """Get paths to the OocyteSeg data.
118
119    Args:
120        path: Filepath to a folder where the downloaded data will be saved.
121        split: The data split to use. One of 'train' or 'test'.
122        species: The species to select. One of 'mouse', 'human' or 'sea_urchin'.
123            If None, data from all species is returned.
124        download: Whether to download the data if it is not present.
125
126    Returns:
127        List of filepaths for the image data.
128        List of filepaths for the label data.
129    """
130    assert split in ("train", "test"), f"'{split}' is not a valid split. Choose from 'train' or 'test'."
131
132    if species is None:
133        species_list = SPECIES
134    else:
135        assert species in SPECIES, f"'{species}' is not a valid species. Choose from {SPECIES}."
136        species_list = [species]
137
138    data_dir = get_oocyteseg_data(path, download)
139
140    all_image_paths = []
141    all_seg_paths = []
142
143    from natsort import natsorted
144
145    for sp in species_list:
146        processed_dir = os.path.join(path, "processed", sp, split)
147        img_out_dir = os.path.join(processed_dir, "images")
148        mask_out_dir = os.path.join(processed_dir, "masks")
149
150        if not os.path.exists(img_out_dir) or len(glob(os.path.join(img_out_dir, "*.tif"))) == 0:
151            _preprocess_data(data_dir, processed_dir, sp, split)
152
153        image_paths = natsorted(glob(os.path.join(img_out_dir, "*.tif")))
154        seg_paths = natsorted(glob(os.path.join(mask_out_dir, "*.tif")))
155
156        assert len(image_paths) == len(seg_paths), \
157            f"Mismatch: {len(image_paths)} images vs {len(seg_paths)} masks for {sp}/{split}"
158        assert len(image_paths) > 0, f"No images found for {sp}/{split}"
159
160        all_image_paths.extend(image_paths)
161        all_seg_paths.extend(seg_paths)
162
163    return all_image_paths, all_seg_paths
164
165
166def get_oocyteseg_dataset(
167    path: Union[os.PathLike, str],
168    patch_shape: Tuple[int, int],
169    split: Literal["train", "test"] = "train",
170    species: Optional[str] = None,
171    download: bool = False,
172    **kwargs
173) -> Dataset:
174    """Get the OocyteSeg dataset for binary membrane segmentation.
175
176    Args:
177        path: Filepath to a folder where the downloaded data will be saved.
178        patch_shape: The patch shape to use for training.
179        split: The data split to use. One of 'train' or 'test'.
180        species: The species to select. One of 'mouse', 'human' or 'sea_urchin'.
181            If None, data from all species is returned.
182        download: Whether to download the data if it is not present.
183        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
184
185    Returns:
186        The segmentation dataset.
187    """
188    image_paths, seg_paths = get_oocyteseg_paths(path, split, species, download)
189
190    kwargs = util.ensure_transforms(ndim=2, **kwargs)
191
192    return torch_em.default_segmentation_dataset(
193        raw_paths=image_paths,
194        raw_key=None,
195        label_paths=seg_paths,
196        label_key=None,
197        patch_shape=patch_shape,
198        is_seg_dataset=False,
199        ndim=2,
200        **kwargs
201    )
202
203
204def get_oocyteseg_loader(
205    path: Union[os.PathLike, str],
206    batch_size: int,
207    patch_shape: Tuple[int, int],
208    split: Literal["train", "test"] = "train",
209    species: Optional[str] = None,
210    download: bool = False,
211    **kwargs
212) -> DataLoader:
213    """Get the OocyteSeg dataloader for binary membrane segmentation.
214
215    Args:
216        path: Filepath to a folder where the downloaded data will be saved.
217        batch_size: The batch size for training.
218        patch_shape: The patch shape to use for training.
219        split: The data split to use. One of 'train' or 'test'.
220        species: The species to select. One of 'mouse', 'human' or 'sea_urchin'.
221            If None, data from all species is returned.
222        download: Whether to download the data if it is not present.
223        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
224
225    Returns:
226        The DataLoader.
227    """
228    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
229    dataset = get_oocyteseg_dataset(
230        path=path,
231        patch_shape=patch_shape,
232        split=split,
233        species=species,
234        download=download,
235        **ds_kwargs,
236    )
237    return torch_em.get_data_loader(dataset=dataset, batch_size=batch_size, **loader_kwargs)
URL = 'https://zenodo.org/records/6502830/files/SegmentationCortex.tar.gz'
CHECKSUM = '46852468b41c4e19c28f079de9e7f6ae565e45c8dc89273adb6f3bd7e9b50613'
SPECIES = ['mouse', 'human', 'sea_urchin']
def get_oocyteseg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 90def get_oocyteseg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 91    """Download the OocyteSeg dataset.
 92
 93    Args:
 94        path: Filepath to a folder where the downloaded data will be saved.
 95        download: Whether to download the data if it is not present.
 96
 97    Returns:
 98        The filepath to the extracted data directory.
 99    """
100    data_dir = os.path.join(path, "SegmentationCortex")
101    if os.path.exists(data_dir):
102        return data_dir
103
104    os.makedirs(path, exist_ok=True)
105    tar_path = os.path.join(path, "SegmentationCortex.tar.gz")
106    util.download_source(path=tar_path, url=URL, download=download, checksum=CHECKSUM)
107    util.unzip_tarfile(tar_path=tar_path, dst=path)
108
109    return data_dir

Download the OocyteSeg 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 extracted data directory.

def get_oocyteseg_paths( path: Union[os.PathLike, str], split: Literal['train', 'test'] = 'train', species: Optional[str] = None, download: bool = False) -> Tuple[List[str], List[str]]:
112def get_oocyteseg_paths(
113    path: Union[os.PathLike, str],
114    split: Literal["train", "test"] = "train",
115    species: Optional[str] = None,
116    download: bool = False,
117) -> Tuple[List[str], List[str]]:
118    """Get paths to the OocyteSeg data.
119
120    Args:
121        path: Filepath to a folder where the downloaded data will be saved.
122        split: The data split to use. One of 'train' or 'test'.
123        species: The species to select. One of 'mouse', 'human' or 'sea_urchin'.
124            If None, data from all species is returned.
125        download: Whether to download the data if it is not present.
126
127    Returns:
128        List of filepaths for the image data.
129        List of filepaths for the label data.
130    """
131    assert split in ("train", "test"), f"'{split}' is not a valid split. Choose from 'train' or 'test'."
132
133    if species is None:
134        species_list = SPECIES
135    else:
136        assert species in SPECIES, f"'{species}' is not a valid species. Choose from {SPECIES}."
137        species_list = [species]
138
139    data_dir = get_oocyteseg_data(path, download)
140
141    all_image_paths = []
142    all_seg_paths = []
143
144    from natsort import natsorted
145
146    for sp in species_list:
147        processed_dir = os.path.join(path, "processed", sp, split)
148        img_out_dir = os.path.join(processed_dir, "images")
149        mask_out_dir = os.path.join(processed_dir, "masks")
150
151        if not os.path.exists(img_out_dir) or len(glob(os.path.join(img_out_dir, "*.tif"))) == 0:
152            _preprocess_data(data_dir, processed_dir, sp, split)
153
154        image_paths = natsorted(glob(os.path.join(img_out_dir, "*.tif")))
155        seg_paths = natsorted(glob(os.path.join(mask_out_dir, "*.tif")))
156
157        assert len(image_paths) == len(seg_paths), \
158            f"Mismatch: {len(image_paths)} images vs {len(seg_paths)} masks for {sp}/{split}"
159        assert len(image_paths) > 0, f"No images found for {sp}/{split}"
160
161        all_image_paths.extend(image_paths)
162        all_seg_paths.extend(seg_paths)
163
164    return all_image_paths, all_seg_paths

Get paths to the OocyteSeg data.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • split: The data split to use. One of 'train' or 'test'.
  • species: The species to select. One of 'mouse', 'human' or 'sea_urchin'. If None, data from all species is returned.
  • 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_oocyteseg_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], split: Literal['train', 'test'] = 'train', species: Optional[str] = None, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
167def get_oocyteseg_dataset(
168    path: Union[os.PathLike, str],
169    patch_shape: Tuple[int, int],
170    split: Literal["train", "test"] = "train",
171    species: Optional[str] = None,
172    download: bool = False,
173    **kwargs
174) -> Dataset:
175    """Get the OocyteSeg dataset for binary membrane segmentation.
176
177    Args:
178        path: Filepath to a folder where the downloaded data will be saved.
179        patch_shape: The patch shape to use for training.
180        split: The data split to use. One of 'train' or 'test'.
181        species: The species to select. One of 'mouse', 'human' or 'sea_urchin'.
182            If None, data from all species is returned.
183        download: Whether to download the data if it is not present.
184        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
185
186    Returns:
187        The segmentation dataset.
188    """
189    image_paths, seg_paths = get_oocyteseg_paths(path, split, species, download)
190
191    kwargs = util.ensure_transforms(ndim=2, **kwargs)
192
193    return torch_em.default_segmentation_dataset(
194        raw_paths=image_paths,
195        raw_key=None,
196        label_paths=seg_paths,
197        label_key=None,
198        patch_shape=patch_shape,
199        is_seg_dataset=False,
200        ndim=2,
201        **kwargs
202    )

Get the OocyteSeg dataset for binary membrane segmentation.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • patch_shape: The patch shape to use for training.
  • split: The data split to use. One of 'train' or 'test'.
  • species: The species to select. One of 'mouse', 'human' or 'sea_urchin'. If None, data from all species is returned.
  • 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_oocyteseg_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], split: Literal['train', 'test'] = 'train', species: Optional[str] = None, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
205def get_oocyteseg_loader(
206    path: Union[os.PathLike, str],
207    batch_size: int,
208    patch_shape: Tuple[int, int],
209    split: Literal["train", "test"] = "train",
210    species: Optional[str] = None,
211    download: bool = False,
212    **kwargs
213) -> DataLoader:
214    """Get the OocyteSeg dataloader for binary membrane segmentation.
215
216    Args:
217        path: Filepath to a folder where the downloaded data will be saved.
218        batch_size: The batch size for training.
219        patch_shape: The patch shape to use for training.
220        split: The data split to use. One of 'train' or 'test'.
221        species: The species to select. One of 'mouse', 'human' or 'sea_urchin'.
222            If None, data from all species is returned.
223        download: Whether to download the data if it is not present.
224        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
225
226    Returns:
227        The DataLoader.
228    """
229    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
230    dataset = get_oocyteseg_dataset(
231        path=path,
232        patch_shape=patch_shape,
233        split=split,
234        species=species,
235        download=download,
236        **ds_kwargs,
237    )
238    return torch_em.get_data_loader(dataset=dataset, batch_size=batch_size, **loader_kwargs)

Get the OocyteSeg dataloader for binary membrane segmentation.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • batch_size: The batch size for training.
  • patch_shape: The patch shape to use for training.
  • split: The data split to use. One of 'train' or 'test'.
  • species: The species to select. One of 'mouse', 'human' or 'sea_urchin'. If None, data from all species is returned.
  • 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.