torch_em.data.datasets.light_microscopy.cellbindb

CellBinDB contains annotations for cell segmentation in multi-modal images.

  • Consists of DAPI, ssDNA, H&E, and mIF staining.
  • Covers more than 30 normal and diseased tissue types from human and mouse samples.

The dataset is located at https://db.cngb.org/search/project/CNP0006370/. This dataset is from the publication https://doi.org/10.1101/2024.11.20.619750. Please cite it if you use this dataset for your research.

  1"""CellBinDB contains annotations for cell segmentation in multi-modal images.
  2- Consists of DAPI, ssDNA, H&E, and mIF staining.
  3- Covers more than 30 normal and diseased tissue types from human and mouse samples.
  4
  5The dataset is located at https://db.cngb.org/search/project/CNP0006370/.
  6This dataset is from the publication https://doi.org/10.1101/2024.11.20.619750.
  7Please cite it if you use this dataset for your research.
  8"""
  9
 10import os
 11import warnings
 12import subprocess
 13from glob import glob
 14from natsort import natsorted
 15from typing import Union, Tuple, List, Optional
 16
 17import torch_em
 18
 19from torch.utils.data import Dataset, DataLoader
 20
 21from .. import util
 22from .neurips_cell_seg import to_rgb
 23
 24
 25DOWNLOAD_SCRIPT = 'wget -c -nH -np -r -R "index.html*" --cut-dirs 4 ftp://ftp.cngb.org/pub/CNSA/data5/CNP0006370/Other/'
 26
 27# Files that are corrupted in the source archive (5 of 1044 pairs): one truncated ssDNA image and four
 28# instance masks that are not TIFF files. Their image-label pairs are skipped.
 29CORRUPTED_FILES = {
 30    "HH799999864GO_W8_36_62-img.tif",
 31    "X98668W8-x10151_y9176_w256_h256-instancemask.tif",
 32    "Z98801V5-x15153_y13890_w256_h256-instancemask.tif",
 33    "HH799999356_M1-x1536_y9216_w512_h512-instancemask.tif",
 34    "X97754Z3-x17024_y19696_w512_h512-instancemask.tif",
 35}
 36
 37CHOICES = ["10×Genomics_DAPI", "10×Genomics_HE", "DAPI", "HE", "mIF", "ssDNA"]
 38
 39
 40def get_cellbindb_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 41    """Download the CellBinDB dataset.
 42
 43    Args:
 44        path: Filepath to a folder where the data is downloaded.
 45        download: Whether to download the data if it is not present.
 46
 47    Returns:
 48        The filepath to the data.
 49    """
 50    data_dir = os.path.join(path, "Other")
 51    if os.path.exists(data_dir):
 52        return data_dir
 53
 54    os.makedirs(path, exist_ok=True)
 55
 56    if not download:
 57        raise AssertionError("The dataset is not found and download is set to 'False'.")
 58
 59    print(
 60        "Downloading the dataset takes several hours and is extremely (like very very) slow. "
 61        "Make sure you have consistent internet connection or run it in background over a cluster."
 62    )
 63    splits = DOWNLOAD_SCRIPT.split(" ")
 64    subprocess.run([*splits[:-1], "-P", os.path.abspath(path), splits[-1]])
 65    return data_dir
 66
 67
 68def get_cellbindb_paths(
 69    path: Union[os.PathLike, str], data_choice: Optional[Union[str, List[str]]] = None, download: bool = False
 70) -> Tuple[List[str], List[str]]:
 71    """Get paths to the CellBinDB data.
 72
 73    Args:
 74        path: Filepath to a folder where the data is downloaded.
 75        data_choice: The choice of datasets.
 76        download: Whether to download the data if it is not present.
 77
 78    Returns:
 79        List of filepaths for the image data.
 80        List of filepaths for the label data.
 81    """
 82    data_dir = get_cellbindb_data(path, download)
 83
 84    if data_choice is None:
 85        data_choice = CHOICES
 86    else:
 87        if isinstance(data_choice, str):
 88            data_choice = [data_choice]
 89
 90    raw_paths, label_paths = [], []
 91    for dchoice in data_choice:
 92        assert dchoice in CHOICES, f"'{dchoice}' is not a valid data choice."
 93        raw_paths.extend(natsorted(glob(os.path.join(data_dir, dchoice, "*", "*-img.tif"))))
 94        label_paths.extend(natsorted(glob(os.path.join(data_dir, dchoice, "*", "*-instancemask.tif"))))
 95
 96    # NOTE: Some files are corrupted from source. Since it's just a few of them, let's bump them out.
 97    valid_paired_images = [
 98        (rp, lp) for rp, lp in zip(raw_paths, label_paths)
 99        if not {os.path.basename(rp), os.path.basename(lp)} & CORRUPTED_FILES
100        and _is_valid_image(rp) and _is_valid_image(lp)
101    ]
102    raw_paths, label_paths = zip(*valid_paired_images)
103    raw_paths, label_paths = list(raw_paths), list(label_paths)
104
105    assert len(raw_paths) == len(label_paths) and len(raw_paths) > 0
106
107    return raw_paths, label_paths
108
109
110def _is_valid_image(im_path):
111    import tifffile
112
113    try:
114        _ = tifffile.imread(im_path)
115        return True
116    except Exception as e:
117        warnings.warn(f"Skipping the corrupted CellBinDB file '{im_path}': {type(e).__name__}: {e}")
118        return False
119
120
121def get_cellbindb_dataset(
122    path: Union[os.PathLike, str],
123    patch_shape: Tuple[int, int],
124    data_choice: Optional[Union[str, List[str]]] = None,
125    download: bool = False,
126    **kwargs
127) -> Dataset:
128    """Get the CellBinDB dataset for cell segmentation.
129
130    Args:
131        path: Filepath to a folder where the data is downloaded.
132        patch_shape: The patch shape to use for training.
133        data_choice: The choice of datasets.
134        download: Whether to download the data if it is not present.
135        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
136
137    Returns:
138        The segmentation dataset.
139    """
140    raw_paths, label_paths = get_cellbindb_paths(path, data_choice, download)
141
142    if "raw_transform" not in kwargs:
143        kwargs["raw_transform"] = torch_em.transform.get_raw_transform(augmentation2=to_rgb)
144
145    return torch_em.default_segmentation_dataset(
146        raw_paths=raw_paths,
147        raw_key=None,
148        label_paths=label_paths,
149        label_key=None,
150        is_seg_dataset=False,
151        ndim=2,
152        patch_shape=patch_shape,
153        **kwargs
154    )
155
156
157def get_cellbindb_loader(
158    path: Union[os.PathLike, str],
159    batch_size: int,
160    patch_shape: Tuple[int, int],
161    data_choice: Optional[Union[str, List[str]]] = None,
162    download: bool = False,
163    **kwargs
164) -> DataLoader:
165    """Get the CellBinDB dataloader for cell segmentation.
166
167    Args:
168        path: Filepath to a folder where the data is downloaded.
169        patch_shape: The patch shape to use for training.
170        data_choice: The choice of datasets.
171        download: Whether to download the data if it is not present.
172        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
173
174    Returns:
175        The DataLoader.
176    """
177    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
178    dataset = get_cellbindb_dataset(path, patch_shape, data_choice, download, **ds_kwargs)
179    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
DOWNLOAD_SCRIPT = 'wget -c -nH -np -r -R "index.html*" --cut-dirs 4 ftp://ftp.cngb.org/pub/CNSA/data5/CNP0006370/Other/'
CORRUPTED_FILES = {'Z98801V5-x15153_y13890_w256_h256-instancemask.tif', 'HH799999864GO_W8_36_62-img.tif', 'X97754Z3-x17024_y19696_w512_h512-instancemask.tif', 'HH799999356_M1-x1536_y9216_w512_h512-instancemask.tif', 'X98668W8-x10151_y9176_w256_h256-instancemask.tif'}
CHOICES = ['10×Genomics_DAPI', '10×Genomics_HE', 'DAPI', 'HE', 'mIF', 'ssDNA']
def get_cellbindb_data(path: Union[os.PathLike, str], download: bool = False) -> str:
41def get_cellbindb_data(path: Union[os.PathLike, str], download: bool = False) -> str:
42    """Download the CellBinDB dataset.
43
44    Args:
45        path: Filepath to a folder where the data is downloaded.
46        download: Whether to download the data if it is not present.
47
48    Returns:
49        The filepath to the data.
50    """
51    data_dir = os.path.join(path, "Other")
52    if os.path.exists(data_dir):
53        return data_dir
54
55    os.makedirs(path, exist_ok=True)
56
57    if not download:
58        raise AssertionError("The dataset is not found and download is set to 'False'.")
59
60    print(
61        "Downloading the dataset takes several hours and is extremely (like very very) slow. "
62        "Make sure you have consistent internet connection or run it in background over a cluster."
63    )
64    splits = DOWNLOAD_SCRIPT.split(" ")
65    subprocess.run([*splits[:-1], "-P", os.path.abspath(path), splits[-1]])
66    return data_dir

Download the CellBinDB dataset.

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

The filepath to the data.

def get_cellbindb_paths( path: Union[os.PathLike, str], data_choice: Union[List[str], str, NoneType] = None, download: bool = False) -> Tuple[List[str], List[str]]:
 69def get_cellbindb_paths(
 70    path: Union[os.PathLike, str], data_choice: Optional[Union[str, List[str]]] = None, download: bool = False
 71) -> Tuple[List[str], List[str]]:
 72    """Get paths to the CellBinDB data.
 73
 74    Args:
 75        path: Filepath to a folder where the data is downloaded.
 76        data_choice: The choice of datasets.
 77        download: Whether to download the data if it is not present.
 78
 79    Returns:
 80        List of filepaths for the image data.
 81        List of filepaths for the label data.
 82    """
 83    data_dir = get_cellbindb_data(path, download)
 84
 85    if data_choice is None:
 86        data_choice = CHOICES
 87    else:
 88        if isinstance(data_choice, str):
 89            data_choice = [data_choice]
 90
 91    raw_paths, label_paths = [], []
 92    for dchoice in data_choice:
 93        assert dchoice in CHOICES, f"'{dchoice}' is not a valid data choice."
 94        raw_paths.extend(natsorted(glob(os.path.join(data_dir, dchoice, "*", "*-img.tif"))))
 95        label_paths.extend(natsorted(glob(os.path.join(data_dir, dchoice, "*", "*-instancemask.tif"))))
 96
 97    # NOTE: Some files are corrupted from source. Since it's just a few of them, let's bump them out.
 98    valid_paired_images = [
 99        (rp, lp) for rp, lp in zip(raw_paths, label_paths)
100        if not {os.path.basename(rp), os.path.basename(lp)} & CORRUPTED_FILES
101        and _is_valid_image(rp) and _is_valid_image(lp)
102    ]
103    raw_paths, label_paths = zip(*valid_paired_images)
104    raw_paths, label_paths = list(raw_paths), list(label_paths)
105
106    assert len(raw_paths) == len(label_paths) and len(raw_paths) > 0
107
108    return raw_paths, label_paths

Get paths to the CellBinDB data.

Arguments:
  • path: Filepath to a folder where the data is downloaded.
  • data_choice: The choice of datasets.
  • 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_cellbindb_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], data_choice: Union[List[str], str, NoneType] = None, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
122def get_cellbindb_dataset(
123    path: Union[os.PathLike, str],
124    patch_shape: Tuple[int, int],
125    data_choice: Optional[Union[str, List[str]]] = None,
126    download: bool = False,
127    **kwargs
128) -> Dataset:
129    """Get the CellBinDB dataset for cell segmentation.
130
131    Args:
132        path: Filepath to a folder where the data is downloaded.
133        patch_shape: The patch shape to use for training.
134        data_choice: The choice of datasets.
135        download: Whether to download the data if it is not present.
136        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
137
138    Returns:
139        The segmentation dataset.
140    """
141    raw_paths, label_paths = get_cellbindb_paths(path, data_choice, download)
142
143    if "raw_transform" not in kwargs:
144        kwargs["raw_transform"] = torch_em.transform.get_raw_transform(augmentation2=to_rgb)
145
146    return torch_em.default_segmentation_dataset(
147        raw_paths=raw_paths,
148        raw_key=None,
149        label_paths=label_paths,
150        label_key=None,
151        is_seg_dataset=False,
152        ndim=2,
153        patch_shape=patch_shape,
154        **kwargs
155    )

Get the CellBinDB dataset for cell segmentation.

Arguments:
  • path: Filepath to a folder where the data is downloaded.
  • patch_shape: The patch shape to use for training.
  • data_choice: The choice of datasets.
  • 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_cellbindb_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], data_choice: Union[List[str], str, NoneType] = None, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
158def get_cellbindb_loader(
159    path: Union[os.PathLike, str],
160    batch_size: int,
161    patch_shape: Tuple[int, int],
162    data_choice: Optional[Union[str, List[str]]] = None,
163    download: bool = False,
164    **kwargs
165) -> DataLoader:
166    """Get the CellBinDB dataloader for cell segmentation.
167
168    Args:
169        path: Filepath to a folder where the data is downloaded.
170        patch_shape: The patch shape to use for training.
171        data_choice: The choice of datasets.
172        download: Whether to download the data if it is not present.
173        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
174
175    Returns:
176        The DataLoader.
177    """
178    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
179    dataset = get_cellbindb_dataset(path, patch_shape, data_choice, download, **ds_kwargs)
180    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the CellBinDB dataloader for cell segmentation.

Arguments:
  • path: Filepath to a folder where the data is downloaded.
  • patch_shape: The patch shape to use for training.
  • data_choice: The choice of datasets.
  • 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.