torch_em.data.datasets.light_microscopy.fluo_neuronal_cells

The Fluorescent Neuronal Cells v2 dataset contains annotations for cell segmentation in fluorescence microscopy images of rodent brain slices.

The dataset holds three image collections, named after the marker color: green, yellow and red. Each collection has a trainval and a test split. The archive ships a binary mask per image, and a COCO file that stores one polygon per cell. This loader rasterizes the polygons, so the target is an instance segmentation.

NOTE: The collections differ a lot. The green images show small punctate nuclei, the yellow images show sparse bright cells, and the red images show dense filamentous neurons at a larger size.

NOTE: The COCO files of this dataset do not follow the usual layout. They store one annotation per image, and its 'segmentation', 'bbox', 'dots' and 'area' fields are parallel lists over the cells.

NOTE: The green trainval split ships a mask for '128.png' but not the image, so this loader skips that sample. It yields 749 labelled images instead of the 750 that the publication reports.

The dataset is located at https://amsacta.unibo.it/id/eprint/7347 under the CC BY 4.0 license. This dataset is from the publication https://doi.org/10.1038/s41597-024-03005-9. Please cite it if you use this dataset in your research.

  1"""The Fluorescent Neuronal Cells v2 dataset contains annotations for cell segmentation
  2in fluorescence microscopy images of rodent brain slices.
  3
  4The dataset holds three image collections, named after the marker color: green, yellow and red.
  5Each collection has a trainval and a test split. The archive ships a binary mask per image, and a
  6COCO file that stores one polygon per cell. This loader rasterizes the polygons, so the target is an
  7instance segmentation.
  8
  9NOTE: The collections differ a lot. The green images show small punctate nuclei, the yellow images
 10show sparse bright cells, and the red images show dense filamentous neurons at a larger size.
 11
 12NOTE: The COCO files of this dataset do not follow the usual layout. They store one annotation per
 13image, and its 'segmentation', 'bbox', 'dots' and 'area' fields are parallel lists over the cells.
 14
 15NOTE: The green trainval split ships a mask for '128.png' but not the image, so this loader skips
 16that sample. It yields 749 labelled images instead of the 750 that the publication reports.
 17
 18The dataset is located at https://amsacta.unibo.it/id/eprint/7347 under the CC BY 4.0 license.
 19This dataset is from the publication https://doi.org/10.1038/s41597-024-03005-9.
 20Please cite it if you use this dataset in your research.
 21"""
 22
 23import os
 24import json
 25from glob import glob
 26from pathlib import Path
 27from natsort import natsorted
 28from typing import List, Literal, Optional, Sequence, Tuple, Union
 29
 30import numpy as np
 31import imageio.v3 as imageio
 32
 33from torch.utils.data import DataLoader, Dataset
 34
 35import torch_em
 36
 37from .. import util
 38
 39
 40URLS = {
 41    "green": "https://amsacta.unibo.it/id/eprint/7347/28/green.zip",
 42    "yellow": "https://amsacta.unibo.it/id/eprint/7347/27/yellow.zip",
 43    "red": "https://amsacta.unibo.it/id/eprint/7347/29/red.zip",
 44}
 45
 46CHECKSUMS = {
 47    "green": "7760c3c55d236c17f2225a0a63e8e61a86c93d0645c7188bbe9652f22f520517",
 48    "yellow": "08048f5c71d4afa726cc54fd887a06cc6894aff62f6704ff5a8c15aa2f9946ca",
 49    "red": "0a9a2ac9dbdd7222cadf44a7846f61f9d0adb08cf09b801efb917a76e8704533",
 50}
 51
 52COLLECTIONS = tuple(URLS)
 53SPLITS = ("trainval", "test")
 54
 55
 56def _rasterize(annotation, shape: Tuple[int, int]) -> np.ndarray:
 57    """Draw one label per cell polygon of an image."""
 58    from skimage.draw import polygon as draw_polygon
 59
 60    labels = np.zeros(shape, dtype="uint16")
 61    for instance_id, part in enumerate(annotation["segmentation"], start=1):
 62        polygon = np.array(part, dtype=float).reshape(-1, 2)
 63        rows, columns = draw_polygon(polygon[:, 1], polygon[:, 0], shape=shape)
 64        labels[rows, columns] = instance_id
 65    return labels
 66
 67
 68def _create_instance_labels(data_dir: str, collection: str, split: str) -> str:
 69    """Rasterize the COCO polygons of one collection split into instance label images."""
 70    from tqdm import tqdm
 71
 72    label_dir = os.path.join(data_dir, collection, split, "instance_labels")
 73    os.makedirs(label_dir, exist_ok=True)
 74
 75    coco_paths = glob(os.path.join(data_dir, collection, split, "ground_truths", "COCO", "*.json"))
 76    if not coco_paths:
 77        raise RuntimeError(f"Could not find the COCO file for '{collection}/{split}' in {data_dir}.")
 78
 79    with open(coco_paths[0]) as f:
 80        coco = json.load(f)
 81
 82    images = {image["id"]: image["file_name"] for image in coco["images"]}
 83    image_dir = os.path.join(data_dir, collection, split, "images")
 84
 85    for annotation in tqdm(coco["annotations"], desc=f"Preprocess '{collection}/{split}'"):
 86        file_name = images.get(annotation["image_id"])
 87        if file_name is None:
 88            continue
 89
 90        # The green trainval split lists an image that the archive does not contain.
 91        image_path = os.path.join(image_dir, file_name)
 92        if not os.path.exists(image_path):
 93            continue
 94
 95        output_path = os.path.join(label_dir, f"{Path(file_name).stem}.tif")
 96        if os.path.exists(output_path):
 97            continue
 98
 99        shape = imageio.imread(image_path).shape[:2]
100        imageio.imwrite(output_path, _rasterize(annotation, shape), compression="zlib")
101
102    return label_dir
103
104
105def get_fluo_neuronal_cells_data(
106    path: Union[os.PathLike, str],
107    collection: Literal["green", "yellow", "red"] = "green",
108    download: bool = False,
109) -> str:
110    """Download the Fluorescent Neuronal Cells dataset.
111
112    Args:
113        path: Filepath to a folder where the downloaded data will be saved.
114        collection: The image collection. Either 'green', 'yellow' or 'red'.
115        download: Whether to download the data if it is not present.
116
117    Returns:
118        The filepath to the folder that holds the collections.
119    """
120    if collection not in COLLECTIONS:
121        raise ValueError(f"'{collection}' is not a valid collection. Choose from {list(COLLECTIONS)}.")
122
123    collection_dir = os.path.join(path, collection)
124    if os.path.exists(collection_dir):
125        return path
126
127    os.makedirs(path, exist_ok=True)
128    zip_path = os.path.join(path, f"{collection}.zip")
129    util.download_source(zip_path, URLS[collection], download, CHECKSUMS[collection])
130    util.unzip(zip_path=zip_path, dst=path)
131
132    return path
133
134
135def get_fluo_neuronal_cells_paths(
136    path: Union[os.PathLike, str],
137    split: Literal["trainval", "test"] = "trainval",
138    collection: Optional[Union[str, Sequence[str]]] = None,
139    download: bool = False,
140) -> Tuple[List[str], List[str]]:
141    """Get paths to the Fluorescent Neuronal Cells data.
142
143    Args:
144        path: Filepath to a folder where the downloaded data will be saved.
145        split: The data split. Either 'trainval' or 'test'.
146        collection: The image collection or collections. Defaults to all of them.
147        download: Whether to download the data if it is not present.
148
149    Returns:
150        List of filepaths for the image data.
151        List of filepaths for the instance label data.
152    """
153    if split not in SPLITS:
154        raise ValueError(f"'{split}' is not a valid split. Choose from {list(SPLITS)}.")
155
156    if collection is None:
157        collections = list(COLLECTIONS)
158    else:
159        collections = [collection] if isinstance(collection, str) else list(collection)
160
161    image_paths, label_paths = [], []
162    for name in collections:
163        data_dir = get_fluo_neuronal_cells_data(path, name, download)
164        label_dir = _create_instance_labels(data_dir, name, split)
165
166        for label_path in natsorted(glob(os.path.join(label_dir, "*.tif"))):
167            image_path = os.path.join(data_dir, name, split, "images", f"{Path(label_path).stem}.png")
168            if not os.path.exists(image_path):
169                continue
170            image_paths.append(image_path)
171            label_paths.append(label_path)
172
173    if not image_paths:
174        raise RuntimeError(f"Could not find any Fluorescent Neuronal Cells data in {path}.")
175
176    return image_paths, label_paths
177
178
179def get_fluo_neuronal_cells_dataset(
180    path: Union[os.PathLike, str],
181    patch_shape: Tuple[int, int],
182    split: Literal["trainval", "test"] = "trainval",
183    collection: Optional[Union[str, Sequence[str]]] = None,
184    offsets: Optional[List[List[int]]] = None,
185    boundaries: bool = False,
186    binary: bool = False,
187    download: bool = False,
188    **kwargs,
189) -> Dataset:
190    """Get the Fluorescent Neuronal Cells dataset for cell segmentation.
191
192    Args:
193        path: Filepath to a folder where the downloaded data will be saved.
194        patch_shape: The 2D patch shape to use for training.
195        split: The data split. Either 'trainval' or 'test'.
196        collection: The image collection or collections. Defaults to all of them.
197        offsets: Offset values for affinity computation used as target.
198        boundaries: Whether to compute boundaries as the target.
199        binary: Whether to use a binary segmentation target.
200        download: Whether to download the data if it is not present.
201        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
202
203    Returns:
204        The segmentation dataset.
205    """
206    if len(patch_shape) != 2:
207        raise ValueError(f"The Fluorescent Neuronal Cells patch shape must be two-dimensional, got {patch_shape}.")
208
209    image_paths, label_paths = get_fluo_neuronal_cells_paths(path, split, collection, download)
210
211    kwargs, _ = util.add_instance_label_transform(
212        kwargs, add_binary_target=True, offsets=offsets, boundaries=boundaries, binary=binary,
213    )
214    kwargs = util.ensure_transforms(ndim=2, **kwargs)
215
216    return torch_em.default_segmentation_dataset(
217        raw_paths=image_paths,
218        raw_key=None,
219        label_paths=label_paths,
220        label_key=None,
221        patch_shape=patch_shape,
222        is_seg_dataset=False,
223        ndim=2,
224        **kwargs,
225    )
226
227
228def get_fluo_neuronal_cells_loader(
229    path: Union[os.PathLike, str],
230    batch_size: int,
231    patch_shape: Tuple[int, int],
232    split: Literal["trainval", "test"] = "trainval",
233    collection: Optional[Union[str, Sequence[str]]] = None,
234    offsets: Optional[List[List[int]]] = None,
235    boundaries: bool = False,
236    binary: bool = False,
237    download: bool = False,
238    **kwargs,
239) -> DataLoader:
240    """Get the Fluorescent Neuronal Cells dataloader for cell segmentation.
241
242    Args:
243        path: Filepath to a folder where the downloaded data will be saved.
244        batch_size: The batch size for training.
245        patch_shape: The 2D patch shape to use for training.
246        split: The data split. Either 'trainval' or 'test'.
247        collection: The image collection or collections. Defaults to all of them.
248        offsets: Offset values for affinity computation used as target.
249        boundaries: Whether to compute boundaries as the target.
250        binary: Whether to use a binary segmentation target.
251        download: Whether to download the data if it is not present.
252        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or the PyTorch DataLoader.
253
254    Returns:
255        The DataLoader.
256    """
257    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
258    dataset = get_fluo_neuronal_cells_dataset(
259        path=path,
260        patch_shape=patch_shape,
261        split=split,
262        collection=collection,
263        offsets=offsets,
264        boundaries=boundaries,
265        binary=binary,
266        download=download,
267        **ds_kwargs,
268    )
269    return torch_em.get_data_loader(dataset, batch_size=batch_size, **loader_kwargs)
URLS = {'green': 'https://amsacta.unibo.it/id/eprint/7347/28/green.zip', 'yellow': 'https://amsacta.unibo.it/id/eprint/7347/27/yellow.zip', 'red': 'https://amsacta.unibo.it/id/eprint/7347/29/red.zip'}
CHECKSUMS = {'green': '7760c3c55d236c17f2225a0a63e8e61a86c93d0645c7188bbe9652f22f520517', 'yellow': '08048f5c71d4afa726cc54fd887a06cc6894aff62f6704ff5a8c15aa2f9946ca', 'red': '0a9a2ac9dbdd7222cadf44a7846f61f9d0adb08cf09b801efb917a76e8704533'}
COLLECTIONS = ('green', 'yellow', 'red')
SPLITS = ('trainval', 'test')
def get_fluo_neuronal_cells_data( path: Union[os.PathLike, str], collection: Literal['green', 'yellow', 'red'] = 'green', download: bool = False) -> str:
106def get_fluo_neuronal_cells_data(
107    path: Union[os.PathLike, str],
108    collection: Literal["green", "yellow", "red"] = "green",
109    download: bool = False,
110) -> str:
111    """Download the Fluorescent Neuronal Cells dataset.
112
113    Args:
114        path: Filepath to a folder where the downloaded data will be saved.
115        collection: The image collection. Either 'green', 'yellow' or 'red'.
116        download: Whether to download the data if it is not present.
117
118    Returns:
119        The filepath to the folder that holds the collections.
120    """
121    if collection not in COLLECTIONS:
122        raise ValueError(f"'{collection}' is not a valid collection. Choose from {list(COLLECTIONS)}.")
123
124    collection_dir = os.path.join(path, collection)
125    if os.path.exists(collection_dir):
126        return path
127
128    os.makedirs(path, exist_ok=True)
129    zip_path = os.path.join(path, f"{collection}.zip")
130    util.download_source(zip_path, URLS[collection], download, CHECKSUMS[collection])
131    util.unzip(zip_path=zip_path, dst=path)
132
133    return path

Download the Fluorescent Neuronal Cells dataset.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • collection: The image collection. Either 'green', 'yellow' or 'red'.
  • download: Whether to download the data if it is not present.
Returns:

The filepath to the folder that holds the collections.

def get_fluo_neuronal_cells_paths( path: Union[os.PathLike, str], split: Literal['trainval', 'test'] = 'trainval', collection: Union[str, Sequence[str], NoneType] = None, download: bool = False) -> Tuple[List[str], List[str]]:
136def get_fluo_neuronal_cells_paths(
137    path: Union[os.PathLike, str],
138    split: Literal["trainval", "test"] = "trainval",
139    collection: Optional[Union[str, Sequence[str]]] = None,
140    download: bool = False,
141) -> Tuple[List[str], List[str]]:
142    """Get paths to the Fluorescent Neuronal Cells data.
143
144    Args:
145        path: Filepath to a folder where the downloaded data will be saved.
146        split: The data split. Either 'trainval' or 'test'.
147        collection: The image collection or collections. Defaults to all of them.
148        download: Whether to download the data if it is not present.
149
150    Returns:
151        List of filepaths for the image data.
152        List of filepaths for the instance label data.
153    """
154    if split not in SPLITS:
155        raise ValueError(f"'{split}' is not a valid split. Choose from {list(SPLITS)}.")
156
157    if collection is None:
158        collections = list(COLLECTIONS)
159    else:
160        collections = [collection] if isinstance(collection, str) else list(collection)
161
162    image_paths, label_paths = [], []
163    for name in collections:
164        data_dir = get_fluo_neuronal_cells_data(path, name, download)
165        label_dir = _create_instance_labels(data_dir, name, split)
166
167        for label_path in natsorted(glob(os.path.join(label_dir, "*.tif"))):
168            image_path = os.path.join(data_dir, name, split, "images", f"{Path(label_path).stem}.png")
169            if not os.path.exists(image_path):
170                continue
171            image_paths.append(image_path)
172            label_paths.append(label_path)
173
174    if not image_paths:
175        raise RuntimeError(f"Could not find any Fluorescent Neuronal Cells data in {path}.")
176
177    return image_paths, label_paths

Get paths to the Fluorescent Neuronal Cells data.

Arguments:
  • path: Filepath to a folder where the downloaded data will be saved.
  • split: The data split. Either 'trainval' or 'test'.
  • collection: The image collection or collections. Defaults to all of them.
  • download: Whether to download the data if it is not present.
Returns:

List of filepaths for the image data. List of filepaths for the instance label data.

def get_fluo_neuronal_cells_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], split: Literal['trainval', 'test'] = 'trainval', collection: Union[str, Sequence[str], NoneType] = None, offsets: Optional[List[List[int]]] = None, boundaries: bool = False, binary: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
180def get_fluo_neuronal_cells_dataset(
181    path: Union[os.PathLike, str],
182    patch_shape: Tuple[int, int],
183    split: Literal["trainval", "test"] = "trainval",
184    collection: Optional[Union[str, Sequence[str]]] = None,
185    offsets: Optional[List[List[int]]] = None,
186    boundaries: bool = False,
187    binary: bool = False,
188    download: bool = False,
189    **kwargs,
190) -> Dataset:
191    """Get the Fluorescent Neuronal Cells dataset for cell segmentation.
192
193    Args:
194        path: Filepath to a folder where the downloaded data will be saved.
195        patch_shape: The 2D patch shape to use for training.
196        split: The data split. Either 'trainval' or 'test'.
197        collection: The image collection or collections. Defaults to all of them.
198        offsets: Offset values for affinity computation used as target.
199        boundaries: Whether to compute boundaries as the target.
200        binary: Whether to use a binary segmentation target.
201        download: Whether to download the data if it is not present.
202        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
203
204    Returns:
205        The segmentation dataset.
206    """
207    if len(patch_shape) != 2:
208        raise ValueError(f"The Fluorescent Neuronal Cells patch shape must be two-dimensional, got {patch_shape}.")
209
210    image_paths, label_paths = get_fluo_neuronal_cells_paths(path, split, collection, download)
211
212    kwargs, _ = util.add_instance_label_transform(
213        kwargs, add_binary_target=True, offsets=offsets, boundaries=boundaries, binary=binary,
214    )
215    kwargs = util.ensure_transforms(ndim=2, **kwargs)
216
217    return torch_em.default_segmentation_dataset(
218        raw_paths=image_paths,
219        raw_key=None,
220        label_paths=label_paths,
221        label_key=None,
222        patch_shape=patch_shape,
223        is_seg_dataset=False,
224        ndim=2,
225        **kwargs,
226    )

Get the Fluorescent Neuronal Cells dataset for cell 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 'trainval' or 'test'.
  • collection: The image collection or collections. Defaults to all of them.
  • 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_fluo_neuronal_cells_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], split: Literal['trainval', 'test'] = 'trainval', collection: Union[str, Sequence[str], NoneType] = None, offsets: Optional[List[List[int]]] = None, boundaries: bool = False, binary: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
229def get_fluo_neuronal_cells_loader(
230    path: Union[os.PathLike, str],
231    batch_size: int,
232    patch_shape: Tuple[int, int],
233    split: Literal["trainval", "test"] = "trainval",
234    collection: Optional[Union[str, Sequence[str]]] = None,
235    offsets: Optional[List[List[int]]] = None,
236    boundaries: bool = False,
237    binary: bool = False,
238    download: bool = False,
239    **kwargs,
240) -> DataLoader:
241    """Get the Fluorescent Neuronal Cells dataloader for cell segmentation.
242
243    Args:
244        path: Filepath to a folder where the downloaded data will be saved.
245        batch_size: The batch size for training.
246        patch_shape: The 2D patch shape to use for training.
247        split: The data split. Either 'trainval' or 'test'.
248        collection: The image collection or collections. Defaults to all of them.
249        offsets: Offset values for affinity computation used as target.
250        boundaries: Whether to compute boundaries as the target.
251        binary: Whether to use a binary segmentation target.
252        download: Whether to download the data if it is not present.
253        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or the PyTorch DataLoader.
254
255    Returns:
256        The DataLoader.
257    """
258    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
259    dataset = get_fluo_neuronal_cells_dataset(
260        path=path,
261        patch_shape=patch_shape,
262        split=split,
263        collection=collection,
264        offsets=offsets,
265        boundaries=boundaries,
266        binary=binary,
267        download=download,
268        **ds_kwargs,
269    )
270    return torch_em.get_data_loader(dataset, batch_size=batch_size, **loader_kwargs)

Get the Fluorescent Neuronal Cells dataloader for cell 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 'trainval' or 'test'.
  • collection: The image collection or collections. Defaults to all of them.
  • 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.