torch_em.data.datasets.light_microscopy.nucverse3d
The NucVerse3D dataset contains annotations for 3d nucleus segmentation in two-photon and confocal microscopy volumes.
The dataset holds three collections that the authors annotated by hand:
- 'liver': two-photon volumes of adult mouse liver, with mono- and binucleated hepatocytes,
- 'liver_hcc': two-photon volumes of mouse hepatocellular carcinoma,
- 'drosophila_glia': confocal volumes of Drosophila melanogaster brain, stained for glial nuclei.
Together they hold 26 volumes with 6226 nuclei. Every volume becomes one h5 file that stores the raw data, the instance labels and the voxel size.
NOTE: The three collections name their masks in three ways. The liver collection appends '_gt' or '_gt_uint16', the carcinoma collection appends '_labels', and the fly collection replaces a 'Denoised-' prefix with a '-label' suffix. The loader therefore pairs an image with a mask by position after sorting, and it checks that the shape of a pair agrees.
NOTE: The masks come as int32, uint32 and uint16, even inside one split. The loader writes them all as uint32.
NOTE: The readme of the repository says that the carcinoma collection serves for testing alone, but the archive splits it into 8 training volumes and 4 test volumes. This loader follows the archive.
NOTE: The tiff files carry no usable voxel size. The carcinoma files report a resolution of one with the unit 'none', and the fly files report no resolution at all, so the voxel size of this module comes from the readme of the repository.
The dataset is located at https://doi.org/10.5281/zenodo.18517324 under the CC BY 4.0 license. This dataset is from the publication https://doi.org/10.1038/s41598-026-51994-x. Please cite it if you use this dataset in your research.
1"""The NucVerse3D dataset contains annotations for 3d nucleus segmentation in 2two-photon and confocal microscopy volumes. 3 4The dataset holds three collections that the authors annotated by hand: 5- 'liver': two-photon volumes of adult mouse liver, with mono- and binucleated hepatocytes, 6- 'liver_hcc': two-photon volumes of mouse hepatocellular carcinoma, 7- 'drosophila_glia': confocal volumes of Drosophila melanogaster brain, stained for glial nuclei. 8 9Together they hold 26 volumes with 6226 nuclei. Every volume becomes one h5 file that stores the 10raw data, the instance labels and the voxel size. 11 12NOTE: The three collections name their masks in three ways. The liver collection appends '_gt' or 13'_gt_uint16', the carcinoma collection appends '_labels', and the fly collection replaces a 14'Denoised-' prefix with a '-label' suffix. The loader therefore pairs an image with a mask by 15position after sorting, and it checks that the shape of a pair agrees. 16 17NOTE: The masks come as int32, uint32 and uint16, even inside one split. The loader writes them all 18as uint32. 19 20NOTE: The readme of the repository says that the carcinoma collection serves for testing alone, but 21the archive splits it into 8 training volumes and 4 test volumes. This loader follows the archive. 22 23NOTE: The tiff files carry no usable voxel size. The carcinoma files report a resolution of one with 24the unit 'none', and the fly files report no resolution at all, so the voxel size of this module 25comes from the readme of the repository. 26 27The dataset is located at https://doi.org/10.5281/zenodo.18517324 under the CC BY 4.0 license. 28This dataset is from the publication https://doi.org/10.1038/s41598-026-51994-x. 29Please cite it if you use this dataset in your research. 30""" 31 32import os 33from glob import glob 34from natsort import natsorted 35from typing import List, Literal, Optional, Sequence, Tuple, Union 36 37from torch.utils.data import DataLoader, Dataset 38 39import torch_em 40 41from .. import util 42 43 44URL = "https://zenodo.org/records/18517324/files/raw.zip?download=1" 45CHECKSUM = "ba4be8b887fe839bb4b16f50e87b93292f95b959e9dc2d161e234521cc9a6d19" 46 47# The name of a collection in the archive, and what the readme says about it. 48DATASETS = { 49 "liver": { 50 "folder": "2_livernuclei", 51 "modality": "two-photon microscopy", 52 "tissue": "adult mouse liver", 53 # The readme gives the voxel size as x, y, z in micrometer. The arrays are z, y, x. 54 "resolution": (0.3, 0.3, 0.3), 55 }, 56 "liver_hcc": { 57 "folder": "7_liver_hcc_dataset", 58 "modality": "two-photon microscopy", 59 "tissue": "mouse liver hepatocellular carcinoma", 60 "resolution": (0.3, 0.3, 0.3), 61 }, 62 "drosophila_glia": { 63 "folder": "6_Drosophila_denoised", 64 "modality": "confocal microscopy", 65 "tissue": "Drosophila melanogaster brain glia", 66 "resolution": (0.3, 0.15, 0.15), 67 }, 68} 69 70SPLITS = ("train", "test") 71 72 73def _pair_split(data_dir: str, folder: str, split: str) -> List[Tuple[str, str]]: 74 """Pair every image of a split with its mask, by position after sorting.""" 75 image_paths = natsorted(glob(os.path.join(data_dir, folder, split, "images", "*.tif"))) 76 mask_paths = natsorted(glob(os.path.join(data_dir, folder, split, "masks", "*.tif"))) 77 if len(image_paths) != len(mask_paths): 78 raise RuntimeError( 79 f"The split '{folder}/{split}' holds {len(image_paths)} images but {len(mask_paths)} masks." 80 ) 81 return list(zip(image_paths, mask_paths)) 82 83 84def _create_h5(data_dir: str, name: str, split: str) -> str: 85 """Write one h5 file per volume, with the raw data, the labels and the voxel size.""" 86 import h5py 87 import tifffile 88 from tqdm import tqdm 89 90 info = DATASETS[name] 91 output_dir = os.path.join(data_dir, "preprocessed", name, split) 92 os.makedirs(output_dir, exist_ok=True) 93 94 pairs = _pair_split(data_dir, info["folder"], split) 95 for image_path, mask_path in tqdm(pairs, desc=f"Preprocess '{name}/{split}'"): 96 stem = os.path.splitext(os.path.basename(image_path))[0] 97 output_path = os.path.join(output_dir, f"{stem}.h5") 98 if os.path.exists(output_path): 99 continue 100 101 raw = tifffile.imread(image_path) 102 labels = tifffile.imread(mask_path) 103 if raw.shape != labels.shape: 104 raise RuntimeError( 105 f"The image {os.path.basename(image_path)} has the shape {raw.shape}, " 106 f"but its mask {os.path.basename(mask_path)} has the shape {labels.shape}." 107 ) 108 109 temporary_path = f"{output_path}.tmp" 110 with h5py.File(temporary_path, "w") as f: 111 f.attrs["dataset"] = name 112 f.attrs["modality"] = info["modality"] 113 f.attrs["tissue"] = info["tissue"] 114 f.attrs["split"] = split 115 # The voxel size in micrometer, in the order of the axes of the arrays. 116 f.attrs["resolution"] = info["resolution"] 117 f.attrs["axes"] = "zyx" 118 f.attrs["image_file"] = os.path.basename(image_path) 119 f.attrs["label_file"] = os.path.basename(mask_path) 120 121 raw_dataset = f.create_dataset("raw", data=raw, compression="gzip") 122 raw_dataset.attrs["resolution"] = info["resolution"] 123 # The masks come in three integer types, so they all become uint32 here. 124 label_dataset = f.create_dataset("labels", data=labels.astype("uint32"), compression="gzip") 125 label_dataset.attrs["resolution"] = info["resolution"] 126 os.replace(temporary_path, output_path) 127 128 return output_dir 129 130 131def get_nucverse3d_data(path: Union[os.PathLike, str], download: bool = False) -> str: 132 """Download the NucVerse3D dataset. 133 134 The repository also holds trained models and preprocessed patches, which take 31 GB together. 135 This loader reads the raw archive alone, which takes 0.68 GB. 136 137 Args: 138 path: Filepath to a folder where the downloaded data will be saved. 139 download: Whether to download the data if it is not present. 140 141 Returns: 142 The filepath to the extracted data. 143 """ 144 data_dir = os.path.join(path, "raw") 145 if os.path.exists(data_dir): 146 return data_dir 147 148 os.makedirs(path, exist_ok=True) 149 zip_path = os.path.join(path, "raw.zip") 150 util.download_source(zip_path, URL, download, CHECKSUM) 151 util.unzip(zip_path=zip_path, dst=path) 152 153 return data_dir 154 155 156def get_nucverse3d_paths( 157 path: Union[os.PathLike, str], 158 dataset: Optional[Union[str, Sequence[str]]] = None, 159 split: Literal["train", "test"] = "train", 160 download: bool = False, 161) -> List[str]: 162 """Get paths to the NucVerse3D data. 163 164 Args: 165 path: Filepath to a folder where the downloaded data will be saved. 166 dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 167 'drosophila_glia'. Defaults to all of them. 168 split: The data split. Either 'train' or 'test'. 169 download: Whether to download the data if it is not present. 170 171 Returns: 172 List of filepaths for the h5 data. 173 """ 174 if split not in SPLITS: 175 raise ValueError(f"'{split}' is not a valid split. Choose from {list(SPLITS)}.") 176 177 if dataset is None: 178 names = list(DATASETS) 179 else: 180 names = [dataset] if isinstance(dataset, str) else list(dataset) 181 for name in names: 182 if name not in DATASETS: 183 raise ValueError(f"'{name}' is not a valid dataset. Choose from {list(DATASETS)}.") 184 185 data_dir = get_nucverse3d_data(path, download) 186 187 volume_paths = [] 188 for name in names: 189 output_dir = _create_h5(data_dir, name, split) 190 volume_paths.extend(natsorted(glob(os.path.join(output_dir, "*.h5")))) 191 192 if not volume_paths: 193 raise RuntimeError(f"Could not find any NucVerse3D data in {data_dir}.") 194 195 return volume_paths 196 197 198def get_nucverse3d_dataset( 199 path: Union[os.PathLike, str], 200 patch_shape: Tuple[int, int, int], 201 dataset: Optional[Union[str, Sequence[str]]] = None, 202 split: Literal["train", "test"] = "train", 203 offsets: Optional[List[List[int]]] = None, 204 boundaries: bool = False, 205 binary: bool = False, 206 download: bool = False, 207 **kwargs, 208) -> Dataset: 209 """Get the NucVerse3D dataset for 3d nucleus segmentation. 210 211 Args: 212 path: Filepath to a folder where the downloaded data will be saved. 213 patch_shape: The 3D patch shape to use for training. 214 dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 215 'drosophila_glia'. Defaults to all of them. 216 split: The data split. Either 'train' or 'test'. 217 offsets: Offset values for affinity computation used as target. 218 boundaries: Whether to compute boundaries as the target. 219 binary: Whether to use a binary segmentation target. 220 download: Whether to download the data if it is not present. 221 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 222 223 Returns: 224 The segmentation dataset. 225 """ 226 if len(patch_shape) != 3: 227 raise ValueError(f"The NucVerse3D patch shape must be three-dimensional, got {patch_shape}.") 228 229 volume_paths = get_nucverse3d_paths(path, dataset, split, download) 230 231 kwargs, _ = util.add_instance_label_transform( 232 kwargs, add_binary_target=True, offsets=offsets, boundaries=boundaries, binary=binary, 233 ) 234 kwargs = util.ensure_transforms(ndim=3, **kwargs) 235 236 return torch_em.default_segmentation_dataset( 237 raw_paths=volume_paths, 238 raw_key="raw", 239 label_paths=volume_paths, 240 label_key="labels", 241 patch_shape=patch_shape, 242 ndim=3, 243 **kwargs, 244 ) 245 246 247def get_nucverse3d_loader( 248 path: Union[os.PathLike, str], 249 batch_size: int, 250 patch_shape: Tuple[int, int, int], 251 dataset: Optional[Union[str, Sequence[str]]] = None, 252 split: Literal["train", "test"] = "train", 253 offsets: Optional[List[List[int]]] = None, 254 boundaries: bool = False, 255 binary: bool = False, 256 download: bool = False, 257 **kwargs, 258) -> DataLoader: 259 """Get the NucVerse3D dataloader for 3d nucleus segmentation. 260 261 Args: 262 path: Filepath to a folder where the downloaded data will be saved. 263 batch_size: The batch size for training. 264 patch_shape: The 3D patch shape to use for training. 265 dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 266 'drosophila_glia'. Defaults to all of them. 267 split: The data split. Either 'train' or 'test'. 268 offsets: Offset values for affinity computation used as target. 269 boundaries: Whether to compute boundaries as the target. 270 binary: Whether to use a binary segmentation target. 271 download: Whether to download the data if it is not present. 272 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or the PyTorch DataLoader. 273 274 Returns: 275 The DataLoader. 276 """ 277 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 278 dataset_ = get_nucverse3d_dataset( 279 path=path, 280 patch_shape=patch_shape, 281 dataset=dataset, 282 split=split, 283 offsets=offsets, 284 boundaries=boundaries, 285 binary=binary, 286 download=download, 287 **ds_kwargs, 288 ) 289 return torch_em.get_data_loader(dataset_, batch_size=batch_size, **loader_kwargs)
132def get_nucverse3d_data(path: Union[os.PathLike, str], download: bool = False) -> str: 133 """Download the NucVerse3D dataset. 134 135 The repository also holds trained models and preprocessed patches, which take 31 GB together. 136 This loader reads the raw archive alone, which takes 0.68 GB. 137 138 Args: 139 path: Filepath to a folder where the downloaded data will be saved. 140 download: Whether to download the data if it is not present. 141 142 Returns: 143 The filepath to the extracted data. 144 """ 145 data_dir = os.path.join(path, "raw") 146 if os.path.exists(data_dir): 147 return data_dir 148 149 os.makedirs(path, exist_ok=True) 150 zip_path = os.path.join(path, "raw.zip") 151 util.download_source(zip_path, URL, download, CHECKSUM) 152 util.unzip(zip_path=zip_path, dst=path) 153 154 return data_dir
Download the NucVerse3D dataset.
The repository also holds trained models and preprocessed patches, which take 31 GB together. This loader reads the raw archive alone, which takes 0.68 GB.
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.
157def get_nucverse3d_paths( 158 path: Union[os.PathLike, str], 159 dataset: Optional[Union[str, Sequence[str]]] = None, 160 split: Literal["train", "test"] = "train", 161 download: bool = False, 162) -> List[str]: 163 """Get paths to the NucVerse3D data. 164 165 Args: 166 path: Filepath to a folder where the downloaded data will be saved. 167 dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 168 'drosophila_glia'. Defaults to all of them. 169 split: The data split. Either 'train' or 'test'. 170 download: Whether to download the data if it is not present. 171 172 Returns: 173 List of filepaths for the h5 data. 174 """ 175 if split not in SPLITS: 176 raise ValueError(f"'{split}' is not a valid split. Choose from {list(SPLITS)}.") 177 178 if dataset is None: 179 names = list(DATASETS) 180 else: 181 names = [dataset] if isinstance(dataset, str) else list(dataset) 182 for name in names: 183 if name not in DATASETS: 184 raise ValueError(f"'{name}' is not a valid dataset. Choose from {list(DATASETS)}.") 185 186 data_dir = get_nucverse3d_data(path, download) 187 188 volume_paths = [] 189 for name in names: 190 output_dir = _create_h5(data_dir, name, split) 191 volume_paths.extend(natsorted(glob(os.path.join(output_dir, "*.h5")))) 192 193 if not volume_paths: 194 raise RuntimeError(f"Could not find any NucVerse3D data in {data_dir}.") 195 196 return volume_paths
Get paths to the NucVerse3D data.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 'drosophila_glia'. Defaults to all of them.
- split: The data split. Either 'train' or 'test'.
- download: Whether to download the data if it is not present.
Returns:
List of filepaths for the h5 data.
199def get_nucverse3d_dataset( 200 path: Union[os.PathLike, str], 201 patch_shape: Tuple[int, int, int], 202 dataset: Optional[Union[str, Sequence[str]]] = None, 203 split: Literal["train", "test"] = "train", 204 offsets: Optional[List[List[int]]] = None, 205 boundaries: bool = False, 206 binary: bool = False, 207 download: bool = False, 208 **kwargs, 209) -> Dataset: 210 """Get the NucVerse3D dataset for 3d nucleus segmentation. 211 212 Args: 213 path: Filepath to a folder where the downloaded data will be saved. 214 patch_shape: The 3D patch shape to use for training. 215 dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 216 'drosophila_glia'. Defaults to all of them. 217 split: The data split. Either 'train' or 'test'. 218 offsets: Offset values for affinity computation used as target. 219 boundaries: Whether to compute boundaries as the target. 220 binary: Whether to use a binary segmentation target. 221 download: Whether to download the data if it is not present. 222 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 223 224 Returns: 225 The segmentation dataset. 226 """ 227 if len(patch_shape) != 3: 228 raise ValueError(f"The NucVerse3D patch shape must be three-dimensional, got {patch_shape}.") 229 230 volume_paths = get_nucverse3d_paths(path, dataset, split, download) 231 232 kwargs, _ = util.add_instance_label_transform( 233 kwargs, add_binary_target=True, offsets=offsets, boundaries=boundaries, binary=binary, 234 ) 235 kwargs = util.ensure_transforms(ndim=3, **kwargs) 236 237 return torch_em.default_segmentation_dataset( 238 raw_paths=volume_paths, 239 raw_key="raw", 240 label_paths=volume_paths, 241 label_key="labels", 242 patch_shape=patch_shape, 243 ndim=3, 244 **kwargs, 245 )
Get the NucVerse3D dataset for 3d nucleus segmentation.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- patch_shape: The 3D patch shape to use for training.
- dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 'drosophila_glia'. Defaults to all of them.
- split: The data split. Either 'train' 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.
248def get_nucverse3d_loader( 249 path: Union[os.PathLike, str], 250 batch_size: int, 251 patch_shape: Tuple[int, int, int], 252 dataset: Optional[Union[str, Sequence[str]]] = None, 253 split: Literal["train", "test"] = "train", 254 offsets: Optional[List[List[int]]] = None, 255 boundaries: bool = False, 256 binary: bool = False, 257 download: bool = False, 258 **kwargs, 259) -> DataLoader: 260 """Get the NucVerse3D dataloader for 3d nucleus segmentation. 261 262 Args: 263 path: Filepath to a folder where the downloaded data will be saved. 264 batch_size: The batch size for training. 265 patch_shape: The 3D patch shape to use for training. 266 dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 267 'drosophila_glia'. Defaults to all of them. 268 split: The data split. Either 'train' or 'test'. 269 offsets: Offset values for affinity computation used as target. 270 boundaries: Whether to compute boundaries as the target. 271 binary: Whether to use a binary segmentation target. 272 download: Whether to download the data if it is not present. 273 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or the PyTorch DataLoader. 274 275 Returns: 276 The DataLoader. 277 """ 278 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 279 dataset_ = get_nucverse3d_dataset( 280 path=path, 281 patch_shape=patch_shape, 282 dataset=dataset, 283 split=split, 284 offsets=offsets, 285 boundaries=boundaries, 286 binary=binary, 287 download=download, 288 **ds_kwargs, 289 ) 290 return torch_em.get_data_loader(dataset_, batch_size=batch_size, **loader_kwargs)
Get the NucVerse3D dataloader for 3d nucleus segmentation.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- batch_size: The batch size for training.
- patch_shape: The 3D patch shape to use for training.
- dataset: The collection or collections to use, out of 'liver', 'liver_hcc' and 'drosophila_glia'. Defaults to all of them.
- split: The data split. Either 'train' 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_datasetor the PyTorch DataLoader.
Returns:
The DataLoader.