torch_em.data.datasets.medical.hc18
HC18 is a dataset for segmentation of the fetal head in 2d ultrasound images, together with annotations for measuring the head circumference (HC).
The dataset is located at https://doi.org/10.5281/zenodo.1327317, released under a CC BY 4.0 license. This dataset is from the publication https://doi.org/10.1371/journal.pone.0200412. Please cite it if you use this dataset in your research.
NOTE: The dataset ships pre-rendered annotations as the ellipse fit of the head circumference drawn as
a thin closed contour (not a filled mask). We rasterize a filled binary mask from this contour by
filling the enclosed region (analogous in spirit to polygon rasterization, see rasterize_rtstruct
in torch_em/data/datasets/util.py, although here the shape is defined by a closed contour rather
than by polygon vertices).
NOTE: Only the training split ships with ground truth annotations. The test split (available at the same Zenodo record) only provides the raw images and pixel size metadata, without annotations, and is therefore not supported by this loader.
1"""HC18 is a dataset for segmentation of the fetal head in 2d ultrasound images, together with 2annotations for measuring the head circumference (HC). 3 4The dataset is located at https://doi.org/10.5281/zenodo.1327317, released under a CC BY 4.0 license. 5This dataset is from the publication https://doi.org/10.1371/journal.pone.0200412. Please cite it if 6you use this dataset in your research. 7 8NOTE: The dataset ships pre-rendered annotations as the ellipse fit of the head circumference drawn as 9a thin closed contour (not a filled mask). We rasterize a filled binary mask from this contour by 10filling the enclosed region (analogous in spirit to polygon rasterization, see `rasterize_rtstruct` 11in `torch_em/data/datasets/util.py`, although here the shape is defined by a closed contour rather 12than by polygon vertices). 13 14NOTE: Only the training split ships with ground truth annotations. The test split (available at 15the same Zenodo record) only provides the raw images and pixel size metadata, without annotations, 16and is therefore not supported by this loader. 17""" 18 19import os 20from glob import glob 21from tqdm import tqdm 22from natsort import natsorted 23from typing import Union, Tuple, List 24 25import imageio.v3 as imageio 26from scipy.ndimage import binary_fill_holes 27 28from torch.utils.data import Dataset, DataLoader 29 30import torch_em 31 32from .. import util 33 34 35URL = "https://zenodo.org/records/1327317/files/training_set.zip" 36CHECKSUM = "fd20d7909df892cfbdc0850de18072dbdad4dc3bc0a57202d4cc818d4715de36" 37 38 39def get_hc18_data(path: Union[os.PathLike, str], download: bool = False) -> str: 40 """Download the HC18 dataset. 41 42 Args: 43 path: Filepath to a folder where the data is downloaded for further processing. 44 download: Whether to download the data if it is not present. 45 46 Returns: 47 Filepath where the data is downloaded. 48 """ 49 data_dir = os.path.join(path, "training_set") 50 if os.path.exists(data_dir): 51 return data_dir 52 53 os.makedirs(path, exist_ok=True) 54 55 zip_path = os.path.join(path, "training_set.zip") 56 util.download_source(path=zip_path, url=URL, download=download, checksum=CHECKSUM) 57 util.unzip(zip_path=zip_path, dst=path) 58 59 return data_dir 60 61 62def _create_mask(annotation_path, gt_path): 63 contour = imageio.imread(annotation_path) 64 mask = binary_fill_holes(contour > 0).astype("uint8") 65 imageio.imwrite(gt_path, mask) 66 67 68def get_hc18_paths(path: Union[os.PathLike, str], download: bool = False) -> Tuple[List[str], List[str]]: 69 """Get paths to the HC18 data. 70 71 Args: 72 path: Filepath to a folder where the data is downloaded for further processing. 73 download: Whether to download the data if it is not present. 74 75 Returns: 76 List of filepaths for the image data. 77 List of filepaths for the label data. 78 """ 79 data_dir = get_hc18_data(path=path, download=download) 80 81 # NOTE: Some patients have multiple annotated images (eg. '010_HC.png' and '010_2HC.png'), so we 82 # match on the 'HC.png' suffix rather than '_HC.png' and explicitly exclude the annotation images. 83 image_paths = natsorted( 84 p for p in glob(os.path.join(data_dir, "*HC.png")) if "Annotation" not in os.path.basename(p) 85 ) 86 87 gt_dir = os.path.join(path, "masks") 88 os.makedirs(gt_dir, exist_ok=True) 89 90 gt_paths = [] 91 for image_path in tqdm(image_paths, desc="Rasterizing head circumference masks"): 92 image_id = os.path.basename(image_path)[:-len(".png")] 93 annotation_path = os.path.join(data_dir, f"{image_id}_Annotation.png") 94 assert os.path.exists(annotation_path), f"The annotation for '{image_path}' is missing." 95 96 gt_path = os.path.join(gt_dir, f"{image_id}.tif") 97 if not os.path.exists(gt_path): 98 _create_mask(annotation_path, gt_path) 99 100 gt_paths.append(gt_path) 101 102 assert len(image_paths) == len(gt_paths) == 999, len(image_paths) 103 104 return image_paths, gt_paths 105 106 107def get_hc18_dataset( 108 path: Union[os.PathLike, str], 109 patch_shape: Tuple[int, int], 110 resize_inputs: bool = False, 111 download: bool = False, 112 **kwargs 113) -> Dataset: 114 """Get the HC18 dataset for segmentation of the fetal head in ultrasound images. 115 116 Args: 117 path: Filepath to a folder where the data is downloaded for further processing. 118 patch_shape: The patch shape to use for training. 119 resize_inputs: Whether to resize the inputs to the patch shape. 120 download: Whether to download the data if it is not present. 121 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 122 123 Returns: 124 The segmentation dataset. 125 """ 126 image_paths, gt_paths = get_hc18_paths(path, download) 127 128 if resize_inputs: 129 resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False} 130 kwargs, patch_shape = util.update_kwargs_for_resize_trafo( 131 kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs 132 ) 133 134 return torch_em.default_segmentation_dataset( 135 raw_paths=image_paths, 136 raw_key=None, 137 label_paths=gt_paths, 138 label_key=None, 139 patch_shape=patch_shape, 140 is_seg_dataset=False, 141 **kwargs 142 ) 143 144 145def get_hc18_loader( 146 path: Union[os.PathLike, str], 147 batch_size: int, 148 patch_shape: Tuple[int, int], 149 resize_inputs: bool = False, 150 download: bool = False, 151 **kwargs 152) -> DataLoader: 153 """Get the HC18 dataloader for segmentation of the fetal head in ultrasound images. 154 155 Args: 156 path: Filepath to a folder where the data is downloaded for further processing. 157 batch_size: The batch size for training. 158 patch_shape: The patch shape to use for training. 159 resize_inputs: Whether to resize the inputs to the patch shape. 160 download: Whether to download the data if it is not present. 161 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader. 162 163 Returns: 164 The DataLoader. 165 """ 166 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 167 dataset = get_hc18_dataset(path, patch_shape, resize_inputs, download, **ds_kwargs) 168 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
40def get_hc18_data(path: Union[os.PathLike, str], download: bool = False) -> str: 41 """Download the HC18 dataset. 42 43 Args: 44 path: Filepath to a folder where the data is downloaded for further processing. 45 download: Whether to download the data if it is not present. 46 47 Returns: 48 Filepath where the data is downloaded. 49 """ 50 data_dir = os.path.join(path, "training_set") 51 if os.path.exists(data_dir): 52 return data_dir 53 54 os.makedirs(path, exist_ok=True) 55 56 zip_path = os.path.join(path, "training_set.zip") 57 util.download_source(path=zip_path, url=URL, download=download, checksum=CHECKSUM) 58 util.unzip(zip_path=zip_path, dst=path) 59 60 return data_dir
Download the HC18 dataset.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- download: Whether to download the data if it is not present.
Returns:
Filepath where the data is downloaded.
69def get_hc18_paths(path: Union[os.PathLike, str], download: bool = False) -> Tuple[List[str], List[str]]: 70 """Get paths to the HC18 data. 71 72 Args: 73 path: Filepath to a folder where the data is downloaded for further processing. 74 download: Whether to download the data if it is not present. 75 76 Returns: 77 List of filepaths for the image data. 78 List of filepaths for the label data. 79 """ 80 data_dir = get_hc18_data(path=path, download=download) 81 82 # NOTE: Some patients have multiple annotated images (eg. '010_HC.png' and '010_2HC.png'), so we 83 # match on the 'HC.png' suffix rather than '_HC.png' and explicitly exclude the annotation images. 84 image_paths = natsorted( 85 p for p in glob(os.path.join(data_dir, "*HC.png")) if "Annotation" not in os.path.basename(p) 86 ) 87 88 gt_dir = os.path.join(path, "masks") 89 os.makedirs(gt_dir, exist_ok=True) 90 91 gt_paths = [] 92 for image_path in tqdm(image_paths, desc="Rasterizing head circumference masks"): 93 image_id = os.path.basename(image_path)[:-len(".png")] 94 annotation_path = os.path.join(data_dir, f"{image_id}_Annotation.png") 95 assert os.path.exists(annotation_path), f"The annotation for '{image_path}' is missing." 96 97 gt_path = os.path.join(gt_dir, f"{image_id}.tif") 98 if not os.path.exists(gt_path): 99 _create_mask(annotation_path, gt_path) 100 101 gt_paths.append(gt_path) 102 103 assert len(image_paths) == len(gt_paths) == 999, len(image_paths) 104 105 return image_paths, gt_paths
Get paths to the HC18 data.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- 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.
108def get_hc18_dataset( 109 path: Union[os.PathLike, str], 110 patch_shape: Tuple[int, int], 111 resize_inputs: bool = False, 112 download: bool = False, 113 **kwargs 114) -> Dataset: 115 """Get the HC18 dataset for segmentation of the fetal head in ultrasound images. 116 117 Args: 118 path: Filepath to a folder where the data is downloaded for further processing. 119 patch_shape: The patch shape to use for training. 120 resize_inputs: Whether to resize the inputs to the patch shape. 121 download: Whether to download the data if it is not present. 122 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`. 123 124 Returns: 125 The segmentation dataset. 126 """ 127 image_paths, gt_paths = get_hc18_paths(path, download) 128 129 if resize_inputs: 130 resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False} 131 kwargs, patch_shape = util.update_kwargs_for_resize_trafo( 132 kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs 133 ) 134 135 return torch_em.default_segmentation_dataset( 136 raw_paths=image_paths, 137 raw_key=None, 138 label_paths=gt_paths, 139 label_key=None, 140 patch_shape=patch_shape, 141 is_seg_dataset=False, 142 **kwargs 143 )
Get the HC18 dataset for segmentation of the fetal head in ultrasound images.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- patch_shape: The patch shape to use for training.
- resize_inputs: Whether to resize the inputs to the patch shape.
- 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.
146def get_hc18_loader( 147 path: Union[os.PathLike, str], 148 batch_size: int, 149 patch_shape: Tuple[int, int], 150 resize_inputs: bool = False, 151 download: bool = False, 152 **kwargs 153) -> DataLoader: 154 """Get the HC18 dataloader for segmentation of the fetal head in ultrasound images. 155 156 Args: 157 path: Filepath to a folder where the data is downloaded for further processing. 158 batch_size: The batch size for training. 159 patch_shape: The patch shape to use for training. 160 resize_inputs: Whether to resize the inputs to the patch shape. 161 download: Whether to download the data if it is not present. 162 kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader. 163 164 Returns: 165 The DataLoader. 166 """ 167 ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs) 168 dataset = get_hc18_dataset(path, patch_shape, resize_inputs, download, **ds_kwargs) 169 return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
Get the HC18 dataloader for segmentation of the fetal head in ultrasound images.
Arguments:
- path: Filepath to a folder where the data is downloaded for further processing.
- batch_size: The batch size for training.
- patch_shape: The patch shape to use for training.
- resize_inputs: Whether to resize the inputs to the patch shape.
- download: Whether to download the data if it is not present.
- kwargs: Additional keyword arguments for
torch_em.default_segmentation_datasetor for the PyTorch DataLoader.
Returns:
The DataLoader.