torch_em.data.datasets.light_microscopy.micro_bench
Micro-Bench contains microscopy images for vision-language understanding.
This loader exposes polygon annotations from Burgess et al., CellCognition, OpenCell and Wu et al. The dataset is located at https://huggingface.co/datasets/jnirschl/uBench and is from the publication https://doi.org/10.52202/079017-0965. Please cite it if you use this dataset in your research.
1"""Micro-Bench contains microscopy images for vision-language understanding. 2 3This loader exposes polygon annotations from Burgess et al., CellCognition, OpenCell and Wu et al. 4The dataset is located at https://huggingface.co/datasets/jnirschl/uBench and is from the publication 5https://doi.org/10.52202/079017-0965. Please cite it if you use this dataset in your research. 6""" 7 8import os 9from glob import glob 10from io import BytesIO 11from pathlib import Path 12from typing import List, Literal, Optional, Tuple, Union 13 14import numpy as np 15 16from torch.utils.data import DataLoader, Dataset 17 18import torch_em 19 20from .. import util 21 22 23REVISION = "3f2c5b590bc7a208d5b60f3527ce4c76a331aa2b" 24URL = ( 25 "https://huggingface.co/datasets/jnirschl/uBench/resolve/" 26 f"{REVISION}/perception/0.1.0/{{filename}}?download=true" 27) 28 29FILES = { 30 "ubench-test-00000-of-00007.arrow": "3d346134e6dffed41f74da64c1c173f5efd3a10200805796a030357297b630f1", 31 "ubench-test-00001-of-00007.arrow": "790591636ae679afa1161664d207c2bb2e3d583690d03967e38364ba0f31ccac", 32 "ubench-test-00002-of-00007.arrow": "c370cd84e6ed9b00483ef3d20f5c06d5ff2264733ea87f2df98cf9a22820bf74", 33 "ubench-test-00003-of-00007.arrow": "832cdd6f73a132028584b4e47ec1afe643e0490dd8ec9686eabbb9de3eb7f814", 34 "ubench-test-00004-of-00007.arrow": "e2741415cef1327ba243f21000ac43aab2d36b61a9c2c862a1d0e21f200f4a69", 35 "ubench-test-00005-of-00007.arrow": "89deae84ed2dab1bb1fc40be0aefe81b8d94590cec548d1950ff5ff853143d34", 36 "ubench-test-00006-of-00007.arrow": "534beca2084a250d4436340c78accc9fe7cc2d6063d4884302e7e7f141edad6c", 37} 38 39SOURCES = { 40 "synthetic_cells": ("burgess", "cell"), 41 "synthetic_nuclei": ("burgess", "nucleus"), 42 "fluo_nuclei": ("cellcognition", "instances"), 43 "protein_localization_nuclei": ("opencell", "instances"), 44 "em_mitochondria": ("wu", "instances"), 45} 46 47 48def _get_source(row) -> Optional[str]: 49 dataset = row["dataset"] 50 if dataset is not None and dataset.startswith("burgess_et_al_2024_"): 51 return "burgess" 52 if dataset == "opencell": 53 return "opencell" 54 if dataset == "wu_et_al_2023": 55 return "wu" 56 57 classes = {annotation["className"] for annotation in row["polygon"] or []} 58 if dataset is None and "H2B-mCherry" in classes: 59 return "cellcognition" 60 return None 61 62 63def _get_sample_id(row, source: str) -> str: 64 dataset = source if row["dataset"] is None else row["dataset"] 65 return f"{dataset}_{row['image_id']}" 66 67 68def _rasterize(polygons, shape: Tuple[int, int], label_choice: Optional[str] = None) -> np.ndarray: 69 from skimage.draw import polygon as draw_polygon 70 71 labels = np.zeros(shape, dtype="uint16") 72 instance_id = 0 73 for annotation in polygons: 74 if label_choice is not None and annotation["className"] != label_choice: 75 continue 76 77 points = np.asarray(annotation["points"], dtype=float).reshape(-1, 2) 78 rows, columns = draw_polygon(points[:, 1], points[:, 0], shape=shape) 79 instance_id += 1 80 labels[rows, columns] = instance_id 81 return labels 82 83 84def _process_shard(path: Union[os.PathLike, str], arrow_path: Union[os.PathLike, str]) -> None: 85 import imageio.v3 as imageio 86 import pyarrow.ipc as ipc 87 from PIL import Image 88 from tqdm import tqdm 89 90 with open(arrow_path, "rb") as file: 91 reader = ipc.open_stream(file) 92 for batch in tqdm(reader, desc=f"Process {Path(arrow_path).name}"): 93 columns = batch.select(["image_id", "image", "dataset", "polygon"]) 94 for row in columns.to_pylist(): 95 source = _get_source(row) 96 if source is None: 97 continue 98 99 image = np.asarray(Image.open(BytesIO(row["image"]["bytes"])).convert("RGB")) 100 sample_id = _get_sample_id(row, source) 101 image_path = os.path.join(path, "images", source, f"{sample_id}.tif") 102 os.makedirs(os.path.dirname(image_path), exist_ok=True) 103 if not os.path.exists(image_path): 104 imageio.imwrite(image_path, image, compression="zlib") 105 106 choices = ("cell", "nucleus") if source == "burgess" else ("instances",) 107 for choice in choices: 108 label_path = os.path.join(path, "labels", source, choice, f"{sample_id}.tif") 109 if os.path.exists(label_path): 110 continue 111 112 os.makedirs(os.path.dirname(label_path), exist_ok=True) 113 label_choice = choice if source == "burgess" else None 114 labels = _rasterize(row["polygon"], image.shape[:2], label_choice) 115 if labels.max() == 0: 116 raise RuntimeError(f"No '{choice}' polygons found for Micro-Bench sample {sample_id}.") 117 imageio.imwrite(label_path, labels, compression="zlib") 118 119 120def get_micro_bench_data(path: Union[os.PathLike, str], download: bool = False) -> str: 121 """Download and prepare the segmentation subset of Micro-Bench. 122 123 The seven official test shards contain 3.57 GB in total. Each shard is removed after its 124 segmentation samples have been extracted, so at most one source shard is stored alongside 125 the prepared data. 126 127 Args: 128 path: Filepath to a folder where the downloaded data will be saved. 129 download: Whether to download the data if it is not present. 130 131 Returns: 132 The filepath to the folder with the prepared data. 133 """ 134 marker_dir = os.path.join(path, ".processed") 135 os.makedirs(marker_dir, exist_ok=True) 136 137 for filename, checksum in FILES.items(): 138 marker_path = os.path.join(marker_dir, filename) 139 if os.path.exists(marker_path): 140 continue 141 142 arrow_path = os.path.join(path, filename) 143 util.download_source(arrow_path, URL.format(filename=filename), download, checksum) 144 _process_shard(path, arrow_path) 145 Path(marker_path).touch() 146 os.remove(arrow_path) 147 148 return str(path) 149 150 151def _validate_source(source: str) -> Tuple[str, str]: 152 if source not in SOURCES: 153 raise ValueError(f"'{source}' is not a valid source. Choose from {list(SOURCES)}.") 154 return SOURCES[source] 155 156 157def get_micro_bench_paths( 158 path: Union[os.PathLike, str], 159 source: Literal[ 160 "synthetic_cells", 161 "synthetic_nuclei", 162 "fluo_nuclei", 163 "protein_localization_nuclei", 164 "em_mitochondria", 165 ] = "synthetic_cells", 166 download: bool = False, 167) -> Tuple[List[str], List[str]]: 168 """Get paths to one segmentation source in Micro-Bench. 169 170 Args: 171 path: Filepath to a folder where the downloaded data will be saved. 172 source: The source named by imaging modality and segmentation task. Choose from 173 'synthetic_cells', 'synthetic_nuclei', 'fluo_nuclei', 'protein_localization_nuclei', or 174 'em_mitochondria'. These correspond to Burgess et al., Burgess et al., CellCognition, 175 OpenCell, and Wu et al., respectively. 176 download: Whether to download the data if it is not present. 177 178 Returns: 179 List of filepaths for the image data. 180 List of filepaths for the instance label data. 181 """ 182 from natsort import natsorted 183 184 dataset_source, label_choice = _validate_source(source) 185 get_micro_bench_data(path, download) 186 187 image_paths = natsorted(glob(os.path.join(path, "images", dataset_source, "*.tif"))) 188 label_paths = natsorted(glob(os.path.join(path, "labels", dataset_source, label_choice, "*.tif"))) 189 if not image_paths or len(image_paths) != len(label_paths): 190 raise RuntimeError(f"Could not find matching Micro-Bench images and labels for source '{source}' in {path}.") 191 return image_paths, label_paths 192 193 194def get_micro_bench_dataset( 195 path: Union[os.PathLike, str], 196 patch_shape: Tuple[int, int], 197 source: Literal[ 198 "synthetic_cells", 199 "synthetic_nuclei", 200 "fluo_nuclei", 201 "protein_localization_nuclei", 202 "em_mitochondria", 203 ] = "synthetic_cells", 204 download: bool = False, 205 **kwargs, 206) -> Dataset: 207 """Get a Micro-Bench instance segmentation dataset. 208 209 Args: 210 path: Filepath to a folder where the downloaded data will be saved. 211 patch_shape: The patch shape to use for training. 212 source: The source named by imaging modality and segmentation task. See ``get_micro_bench_paths``. 213 download: Whether to download the data if it is not present. 214 kwargs: Additional keyword arguments for ``torch_em.default_segmentation_dataset``. 215 216 Returns: 217 The segmentation dataset. 218 """ 219 image_paths, label_paths = get_micro_bench_paths(path, source, download) 220 kwargs, _ = util.add_instance_label_transform(kwargs, add_binary_target=True) 221 kwargs = util.update_kwargs(kwargs, "ndim", 2) 222 223 return torch_em.default_segmentation_dataset( 224 raw_paths=image_paths, 225 raw_key=None, 226 label_paths=label_paths, 227 label_key=None, 228 patch_shape=patch_shape, 229 is_seg_dataset=False, 230 **kwargs, 231 ) 232 233 234def get_micro_bench_loader( 235 path: Union[os.PathLike, str], 236 batch_size: int, 237 patch_shape: Tuple[int, int], 238 source: Literal[ 239 "synthetic_cells", 240 "synthetic_nuclei", 241 "fluo_nuclei", 242 "protein_localization_nuclei", 243 "em_mitochondria", 244 ] = "synthetic_cells", 245 download: bool = False, 246 **kwargs, 247) -> DataLoader: 248 """Get a Micro-Bench instance segmentation data loader. 249 250 Args: 251 path: Filepath to a folder where the downloaded data will be saved. 252 batch_size: The batch size for training. 253 patch_shape: The patch shape to use for training. 254 source: The source named by imaging modality and segmentation task. See ``get_micro_bench_paths``. 255 download: Whether to download the data if it is not present. 256 kwargs: Additional keyword arguments for the dataset or PyTorch DataLoader. 257 258 Returns: 259 The DataLoader. 260 """ 261 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 262 dataset = get_micro_bench_dataset( 263 path, patch_shape, source, download, **ds_kwargs, 264 ) 265 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
121def get_micro_bench_data(path: Union[os.PathLike, str], download: bool = False) -> str: 122 """Download and prepare the segmentation subset of Micro-Bench. 123 124 The seven official test shards contain 3.57 GB in total. Each shard is removed after its 125 segmentation samples have been extracted, so at most one source shard is stored alongside 126 the prepared data. 127 128 Args: 129 path: Filepath to a folder where the downloaded data will be saved. 130 download: Whether to download the data if it is not present. 131 132 Returns: 133 The filepath to the folder with the prepared data. 134 """ 135 marker_dir = os.path.join(path, ".processed") 136 os.makedirs(marker_dir, exist_ok=True) 137 138 for filename, checksum in FILES.items(): 139 marker_path = os.path.join(marker_dir, filename) 140 if os.path.exists(marker_path): 141 continue 142 143 arrow_path = os.path.join(path, filename) 144 util.download_source(arrow_path, URL.format(filename=filename), download, checksum) 145 _process_shard(path, arrow_path) 146 Path(marker_path).touch() 147 os.remove(arrow_path) 148 149 return str(path)
Download and prepare the segmentation subset of Micro-Bench.
The seven official test shards contain 3.57 GB in total. Each shard is removed after its segmentation samples have been extracted, so at most one source shard is stored alongside the prepared data.
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 folder with the prepared data.
158def get_micro_bench_paths( 159 path: Union[os.PathLike, str], 160 source: Literal[ 161 "synthetic_cells", 162 "synthetic_nuclei", 163 "fluo_nuclei", 164 "protein_localization_nuclei", 165 "em_mitochondria", 166 ] = "synthetic_cells", 167 download: bool = False, 168) -> Tuple[List[str], List[str]]: 169 """Get paths to one segmentation source in Micro-Bench. 170 171 Args: 172 path: Filepath to a folder where the downloaded data will be saved. 173 source: The source named by imaging modality and segmentation task. Choose from 174 'synthetic_cells', 'synthetic_nuclei', 'fluo_nuclei', 'protein_localization_nuclei', or 175 'em_mitochondria'. These correspond to Burgess et al., Burgess et al., CellCognition, 176 OpenCell, and Wu et al., respectively. 177 download: Whether to download the data if it is not present. 178 179 Returns: 180 List of filepaths for the image data. 181 List of filepaths for the instance label data. 182 """ 183 from natsort import natsorted 184 185 dataset_source, label_choice = _validate_source(source) 186 get_micro_bench_data(path, download) 187 188 image_paths = natsorted(glob(os.path.join(path, "images", dataset_source, "*.tif"))) 189 label_paths = natsorted(glob(os.path.join(path, "labels", dataset_source, label_choice, "*.tif"))) 190 if not image_paths or len(image_paths) != len(label_paths): 191 raise RuntimeError(f"Could not find matching Micro-Bench images and labels for source '{source}' in {path}.") 192 return image_paths, label_paths
Get paths to one segmentation source in Micro-Bench.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- source: The source named by imaging modality and segmentation task. Choose from 'synthetic_cells', 'synthetic_nuclei', 'fluo_nuclei', 'protein_localization_nuclei', or 'em_mitochondria'. These correspond to Burgess et al., Burgess et al., CellCognition, OpenCell, and Wu et al., respectively.
- 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.
195def get_micro_bench_dataset( 196 path: Union[os.PathLike, str], 197 patch_shape: Tuple[int, int], 198 source: Literal[ 199 "synthetic_cells", 200 "synthetic_nuclei", 201 "fluo_nuclei", 202 "protein_localization_nuclei", 203 "em_mitochondria", 204 ] = "synthetic_cells", 205 download: bool = False, 206 **kwargs, 207) -> Dataset: 208 """Get a Micro-Bench instance segmentation dataset. 209 210 Args: 211 path: Filepath to a folder where the downloaded data will be saved. 212 patch_shape: The patch shape to use for training. 213 source: The source named by imaging modality and segmentation task. See ``get_micro_bench_paths``. 214 download: Whether to download the data if it is not present. 215 kwargs: Additional keyword arguments for ``torch_em.default_segmentation_dataset``. 216 217 Returns: 218 The segmentation dataset. 219 """ 220 image_paths, label_paths = get_micro_bench_paths(path, source, download) 221 kwargs, _ = util.add_instance_label_transform(kwargs, add_binary_target=True) 222 kwargs = util.update_kwargs(kwargs, "ndim", 2) 223 224 return torch_em.default_segmentation_dataset( 225 raw_paths=image_paths, 226 raw_key=None, 227 label_paths=label_paths, 228 label_key=None, 229 patch_shape=patch_shape, 230 is_seg_dataset=False, 231 **kwargs, 232 )
Get a Micro-Bench instance segmentation dataset.
Arguments:
- path: Filepath to a folder where the downloaded data will be saved.
- patch_shape: The patch shape to use for training.
- source: The source named by imaging modality and segmentation task. See
get_micro_bench_paths. - 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.
235def get_micro_bench_loader( 236 path: Union[os.PathLike, str], 237 batch_size: int, 238 patch_shape: Tuple[int, int], 239 source: Literal[ 240 "synthetic_cells", 241 "synthetic_nuclei", 242 "fluo_nuclei", 243 "protein_localization_nuclei", 244 "em_mitochondria", 245 ] = "synthetic_cells", 246 download: bool = False, 247 **kwargs, 248) -> DataLoader: 249 """Get a Micro-Bench instance segmentation data loader. 250 251 Args: 252 path: Filepath to a folder where the downloaded data will be saved. 253 batch_size: The batch size for training. 254 patch_shape: The patch shape to use for training. 255 source: The source named by imaging modality and segmentation task. See ``get_micro_bench_paths``. 256 download: Whether to download the data if it is not present. 257 kwargs: Additional keyword arguments for the dataset or PyTorch DataLoader. 258 259 Returns: 260 The DataLoader. 261 """ 262 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 263 dataset = get_micro_bench_dataset( 264 path, patch_shape, source, download, **ds_kwargs, 265 ) 266 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
Get a Micro-Bench instance segmentation data loader.
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.
- source: The source named by imaging modality and segmentation task. See
get_micro_bench_paths. - download: Whether to download the data if it is not present.
- kwargs: Additional keyword arguments for the dataset or PyTorch DataLoader.
Returns:
The DataLoader.