torch_em.data.datasets.medical.fuseg

The FUSeg dataset contains annotations for wound segmentation in clinical foot ulcer photographs.

The dataset consists of 1,210 foot ulcer images collected over two years from 889 patients for the 2021 MICCAI Foot Ulcer Segmentation (FUSeg) Challenge. Only the 'train' and 'validation' splits are used here, as they are the only splits with publicly released ground-truth masks; the 'test' split ground truth is kept private by the challenge organizers for the leaderboard.

The dataset is located at https://github.com/uwm-bigdata/wound-segmentation. The dataset is from the publication https://doi.org/10.3390/info15030140. Please cite it if you use this dataset for your research.

  1"""The FUSeg dataset contains annotations for wound segmentation in clinical foot ulcer photographs.
  2
  3The dataset consists of 1,210 foot ulcer images collected over two years from 889 patients for the
  42021 MICCAI Foot Ulcer Segmentation (FUSeg) Challenge. Only the 'train' and 'validation' splits are
  5used here, as they are the only splits with publicly released ground-truth masks; the 'test' split
  6ground truth is kept private by the challenge organizers for the leaderboard.
  7
  8The dataset is located at https://github.com/uwm-bigdata/wound-segmentation.
  9The dataset is from the publication https://doi.org/10.3390/info15030140.
 10Please cite it if you use this dataset for your research.
 11"""
 12
 13import os
 14import subprocess
 15from glob import glob
 16from natsort import natsorted
 17from typing import Union, Tuple, Literal, List
 18
 19import imageio.v3 as imageio
 20
 21from torch.utils.data import Dataset, DataLoader
 22
 23import torch_em
 24
 25from .. import util
 26from ..light_microscopy.neurips_cell_seg import to_rgb
 27
 28
 29URL = "https://github.com/uwm-bigdata/wound-segmentation.git"
 30
 31CHALLENGE_DIR = "Foot Ulcer Segmentation Challenge"
 32
 33
 34def get_fuseg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 35    """Download the FUSeg dataset.
 36
 37    Args:
 38        path: Filepath to a folder where the data is downloaded for further processing.
 39        download: Whether to download the data if it is not present.
 40
 41    Returns:
 42        Filepath where the data is downloaded.
 43    """
 44    data_dir = os.path.join(path, "wound-segmentation", "data", CHALLENGE_DIR)
 45    if os.path.exists(data_dir):
 46        return data_dir
 47
 48    if not download:
 49        raise RuntimeError(f"Cannot find the data at {path}, but download was set to False")
 50
 51    os.makedirs(path, exist_ok=True)
 52    repo_dir = os.path.join(path, "wound-segmentation")
 53    subprocess.run(
 54        ["git", "clone", "--filter=blob:none", "--sparse", "--depth", "1", "--quiet", URL, repo_dir], check=True
 55    )
 56    subprocess.run(["git", "sparse-checkout", "set", os.path.join("data", CHALLENGE_DIR)], cwd=repo_dir, check=True)
 57
 58    return data_dir
 59
 60
 61def _binarize_mask(mask_path, out_path):
 62    if os.path.exists(out_path):
 63        return
 64    mask = imageio.imread(mask_path)
 65    if mask.ndim == 3:
 66        mask = mask[..., 0]
 67    mask = (mask > 127).astype("uint8")
 68    imageio.imwrite(out_path, mask)
 69
 70
 71def get_fuseg_paths(
 72    path: Union[os.PathLike, str], split: Literal["train", "validation"] = "train", download: bool = False
 73) -> Tuple[List[str], List[str]]:
 74    """Get paths to the FUSeg data.
 75
 76    Args:
 77        path: Filepath to a folder where the data is downloaded for further processing.
 78        split: The choice of data split. Either 'train' or 'validation'.
 79        download: Whether to download the data if it is not present.
 80
 81    Returns:
 82        List of filepaths for the image data.
 83        List of filepaths for the label data.
 84    """
 85    if split not in ["train", "validation"]:
 86        raise ValueError(f"'{split}' is not a valid split. Choose 'train' or 'validation'.")
 87
 88    data_dir = get_fuseg_data(path, download)
 89
 90    image_dir = os.path.join(data_dir, split, "images")
 91    label_dir = os.path.join(data_dir, split, "labels")
 92    preprocessed_dir = os.path.join(data_dir, split, "preprocessed_labels")
 93    os.makedirs(preprocessed_dir, exist_ok=True)
 94
 95    image_paths = natsorted(glob(os.path.join(image_dir, "*.png")))
 96
 97    label_paths = []
 98    for image_path in image_paths:
 99        fname = os.path.basename(image_path)
100        mask_path = os.path.join(label_dir, fname)
101        out_path = os.path.join(preprocessed_dir, fname)
102        _binarize_mask(mask_path, out_path)
103        label_paths.append(out_path)
104
105    return image_paths, label_paths
106
107
108def get_fuseg_dataset(
109    path: Union[os.PathLike, str],
110    patch_shape: Tuple[int, int],
111    split: Literal["train", "validation"] = "train",
112    resize_inputs: bool = False,
113    download: bool = False,
114    **kwargs
115) -> Dataset:
116    """Get the FUSeg dataset for wound segmentation in foot ulcer photographs.
117
118    Args:
119        path: Filepath to a folder where the data is downloaded for further processing.
120        patch_shape: The patch shape to use for training.
121        split: The choice of data split. Either 'train' or 'validation'.
122        resize_inputs: Whether to resize the inputs to the expected patch shape.
123        download: Whether to download the data if it is not present.
124        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
125
126    Returns:
127        The segmentation dataset.
128    """
129    image_paths, label_paths = get_fuseg_paths(path, split, download)
130
131    if resize_inputs:
132        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
133        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
134            kwargs=kwargs,
135            patch_shape=patch_shape,
136            resize_inputs=resize_inputs,
137            resize_kwargs=resize_kwargs,
138            ensure_rgb=to_rgb,
139        )
140
141    return torch_em.default_segmentation_dataset(
142        raw_paths=image_paths,
143        raw_key=None,
144        label_paths=label_paths,
145        label_key=None,
146        patch_shape=patch_shape,
147        is_seg_dataset=False,
148        **kwargs
149    )
150
151
152def get_fuseg_loader(
153    path: Union[os.PathLike, str],
154    batch_size: int,
155    patch_shape: Tuple[int, int],
156    split: Literal["train", "validation"] = "train",
157    resize_inputs: bool = False,
158    download: bool = False,
159    **kwargs
160) -> DataLoader:
161    """Get the FUSeg dataloader for wound segmentation in foot ulcer photographs.
162
163    Args:
164        path: Filepath to a folder where the data is downloaded for further processing.
165        batch_size: The batch size for training.
166        patch_shape: The patch shape to use for training.
167        split: The choice of data split. Either 'train' or 'validation'.
168        resize_inputs: Whether to resize the inputs to the expected patch shape.
169        download: Whether to download the data if it is not present.
170        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
171
172    Returns:
173        The DataLoader.
174    """
175    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
176    dataset = get_fuseg_dataset(path, patch_shape, split, resize_inputs, download, **ds_kwargs)
177    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
URL = 'https://github.com/uwm-bigdata/wound-segmentation.git'
CHALLENGE_DIR = 'Foot Ulcer Segmentation Challenge'
def get_fuseg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
35def get_fuseg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
36    """Download the FUSeg dataset.
37
38    Args:
39        path: Filepath to a folder where the data is downloaded for further processing.
40        download: Whether to download the data if it is not present.
41
42    Returns:
43        Filepath where the data is downloaded.
44    """
45    data_dir = os.path.join(path, "wound-segmentation", "data", CHALLENGE_DIR)
46    if os.path.exists(data_dir):
47        return data_dir
48
49    if not download:
50        raise RuntimeError(f"Cannot find the data at {path}, but download was set to False")
51
52    os.makedirs(path, exist_ok=True)
53    repo_dir = os.path.join(path, "wound-segmentation")
54    subprocess.run(
55        ["git", "clone", "--filter=blob:none", "--sparse", "--depth", "1", "--quiet", URL, repo_dir], check=True
56    )
57    subprocess.run(["git", "sparse-checkout", "set", os.path.join("data", CHALLENGE_DIR)], cwd=repo_dir, check=True)
58
59    return data_dir

Download the FUSeg 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.

def get_fuseg_paths( path: Union[os.PathLike, str], split: Literal['train', 'validation'] = 'train', download: bool = False) -> Tuple[List[str], List[str]]:
 72def get_fuseg_paths(
 73    path: Union[os.PathLike, str], split: Literal["train", "validation"] = "train", download: bool = False
 74) -> Tuple[List[str], List[str]]:
 75    """Get paths to the FUSeg data.
 76
 77    Args:
 78        path: Filepath to a folder where the data is downloaded for further processing.
 79        split: The choice of data split. Either 'train' or 'validation'.
 80        download: Whether to download the data if it is not present.
 81
 82    Returns:
 83        List of filepaths for the image data.
 84        List of filepaths for the label data.
 85    """
 86    if split not in ["train", "validation"]:
 87        raise ValueError(f"'{split}' is not a valid split. Choose 'train' or 'validation'.")
 88
 89    data_dir = get_fuseg_data(path, download)
 90
 91    image_dir = os.path.join(data_dir, split, "images")
 92    label_dir = os.path.join(data_dir, split, "labels")
 93    preprocessed_dir = os.path.join(data_dir, split, "preprocessed_labels")
 94    os.makedirs(preprocessed_dir, exist_ok=True)
 95
 96    image_paths = natsorted(glob(os.path.join(image_dir, "*.png")))
 97
 98    label_paths = []
 99    for image_path in image_paths:
100        fname = os.path.basename(image_path)
101        mask_path = os.path.join(label_dir, fname)
102        out_path = os.path.join(preprocessed_dir, fname)
103        _binarize_mask(mask_path, out_path)
104        label_paths.append(out_path)
105
106    return image_paths, label_paths

Get paths to the FUSeg data.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • split: The choice of data split. Either 'train' or 'validation'.
  • 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_fuseg_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], split: Literal['train', 'validation'] = 'train', resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
109def get_fuseg_dataset(
110    path: Union[os.PathLike, str],
111    patch_shape: Tuple[int, int],
112    split: Literal["train", "validation"] = "train",
113    resize_inputs: bool = False,
114    download: bool = False,
115    **kwargs
116) -> Dataset:
117    """Get the FUSeg dataset for wound segmentation in foot ulcer photographs.
118
119    Args:
120        path: Filepath to a folder where the data is downloaded for further processing.
121        patch_shape: The patch shape to use for training.
122        split: The choice of data split. Either 'train' or 'validation'.
123        resize_inputs: Whether to resize the inputs to the expected patch shape.
124        download: Whether to download the data if it is not present.
125        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
126
127    Returns:
128        The segmentation dataset.
129    """
130    image_paths, label_paths = get_fuseg_paths(path, split, download)
131
132    if resize_inputs:
133        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
134        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
135            kwargs=kwargs,
136            patch_shape=patch_shape,
137            resize_inputs=resize_inputs,
138            resize_kwargs=resize_kwargs,
139            ensure_rgb=to_rgb,
140        )
141
142    return torch_em.default_segmentation_dataset(
143        raw_paths=image_paths,
144        raw_key=None,
145        label_paths=label_paths,
146        label_key=None,
147        patch_shape=patch_shape,
148        is_seg_dataset=False,
149        **kwargs
150    )

Get the FUSeg dataset for wound segmentation in foot ulcer photographs.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • patch_shape: The patch shape to use for training.
  • split: The choice of data split. Either 'train' or 'validation'.
  • resize_inputs: Whether to resize the inputs to the expected 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.

def get_fuseg_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], split: Literal['train', 'validation'] = 'train', resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
153def get_fuseg_loader(
154    path: Union[os.PathLike, str],
155    batch_size: int,
156    patch_shape: Tuple[int, int],
157    split: Literal["train", "validation"] = "train",
158    resize_inputs: bool = False,
159    download: bool = False,
160    **kwargs
161) -> DataLoader:
162    """Get the FUSeg dataloader for wound segmentation in foot ulcer photographs.
163
164    Args:
165        path: Filepath to a folder where the data is downloaded for further processing.
166        batch_size: The batch size for training.
167        patch_shape: The patch shape to use for training.
168        split: The choice of data split. Either 'train' or 'validation'.
169        resize_inputs: Whether to resize the inputs to the expected patch shape.
170        download: Whether to download the data if it is not present.
171        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
172
173    Returns:
174        The DataLoader.
175    """
176    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
177    dataset = get_fuseg_dataset(path, patch_shape, split, resize_inputs, download, **ds_kwargs)
178    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the FUSeg dataloader for wound segmentation in foot ulcer photographs.

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.
  • split: The choice of data split. Either 'train' or 'validation'.
  • resize_inputs: Whether to resize the inputs to the expected patch shape.
  • 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.