torch_em.data.datasets.medical.platif

The PlaTiF dataset contains annotations for tibia bone segmentation in anteroposterior knee radiographs, together with Schatzker classification labels for tibial plateau fractures.

The dataset consists of 421 anteroposterior knee radiographs from 186 patients (normal and fractured knees), collected at Shariati Hospital, Tehran University of Medical Sciences. Each image comes with a manually produced (and MATLAB-refined) binary tibia segmentation mask, expert validated, plus a Schatzker fracture type label (1-6) or a "no fracture" label (7).

The dataset is located at https://doi.org/10.5281/zenodo.18007397 and is distributed under the CC BY 4.0 license.

This dataset is from the publication https://doi.org/10.1038/s41597-026-06560-5. Please cite it if you use this dataset in your research.

  1"""The PlaTiF dataset contains annotations for tibia bone segmentation in anteroposterior knee
  2radiographs, together with Schatzker classification labels for tibial plateau fractures.
  3
  4The dataset consists of 421 anteroposterior knee radiographs from 186 patients (normal and
  5fractured knees), collected at Shariati Hospital, Tehran University of Medical Sciences. Each
  6image comes with a manually produced (and MATLAB-refined) binary tibia segmentation mask, expert
  7validated, plus a Schatzker fracture type label (1-6) or a "no fracture" label (7).
  8
  9The dataset is located at https://doi.org/10.5281/zenodo.18007397 and is distributed under the
 10CC BY 4.0 license.
 11
 12This dataset is from the publication https://doi.org/10.1038/s41597-026-06560-5.
 13Please cite it if you use this dataset in your research.
 14"""
 15
 16import os
 17import shutil
 18from glob import glob
 19from tqdm import tqdm
 20from natsort import natsorted
 21from typing import Union, Tuple, List
 22
 23import imageio.v3 as imageio
 24
 25from torch.utils.data import Dataset, DataLoader
 26
 27import torch_em
 28
 29from .. import util
 30
 31
 32URLS = {
 33    "Patient Data_Part 1.zip": "https://zenodo.org/records/18007397/files/Patient%20Data_Part%201.zip",
 34    "Patient Data_Part 2.zip": "https://zenodo.org/records/18007397/files/Patient%20Data_Part%202.zip",
 35    "Patient Data_Part 3.zip": "https://zenodo.org/records/18007397/files/Patient%20Data_Part%203.zip",
 36    "Patient Data_Part 4.zip": "https://zenodo.org/records/18007397/files/Patient%20Data_Part%204.zip",
 37    "Patient Data_Part 5.zip": "https://zenodo.org/records/18007397/files/Patient%20Data_Part%205.zip",
 38}
 39
 40CHECKSUMS = {
 41    "Patient Data_Part 1.zip": "df72a6e0d988492eb87928105596001c6551db38d21dfb0a5d46942c45bd9d49",
 42    "Patient Data_Part 2.zip": "ef0f3315dbd9d47361dad23840cd4a8fbf36fbeb32955deddebc5fe29e14134b",
 43    "Patient Data_Part 3.zip": "63b77dc6e929df4d5c810a324d079905158d9196796ed9696ee5f1d81094ae09",
 44    "Patient Data_Part 4.zip": "d6135f67f5d7d76fab2b93ce059d56b6647e5bac87cf3b0d5ab0329121406756",
 45    "Patient Data_Part 5.zip": "dce5a29107a2e64eb7c25016e8cb65ba46d022f555983b144172602f2920416c",
 46}
 47
 48
 49def _preprocess_platif(mat_dir, preprocessed_dir):
 50    import scipy.io as sio
 51
 52    os.makedirs(os.path.join(preprocessed_dir, "images"), exist_ok=True)
 53    os.makedirs(os.path.join(preprocessed_dir, "masks"), exist_ok=True)
 54
 55    mat_paths = natsorted(glob(os.path.join(mat_dir, "**", "*.mat"), recursive=True))
 56    assert len(mat_paths) > 0, f"No '.mat' files were found at '{mat_dir}'."
 57
 58    for mat_path in tqdm(mat_paths, desc="Preprocessing inputs"):
 59        data = sio.loadmat(mat_path, simplify_cells=True)
 60        patient_keys = [k for k in data if not k.startswith("__")]
 61        assert len(patient_keys) == 1, f"Unexpected structure in '{mat_path}'."
 62        patient = data[patient_keys[0]]
 63
 64        view_keys = natsorted([k for k in patient if k.startswith("im")])
 65        for view_key in view_keys:
 66            view = patient[view_key]
 67
 68            image_path = os.path.join(preprocessed_dir, "images", f"{patient_keys[0]}_{view_key}.tif")
 69            mask_path = os.path.join(preprocessed_dir, "masks", f"{patient_keys[0]}_{view_key}.tif")
 70            if os.path.exists(image_path) and os.path.exists(mask_path):
 71                continue
 72
 73            image = (view["OriginalImage"] * 255).astype("uint8")
 74            mask = view["BW"].astype("uint8")
 75
 76            imageio.imwrite(image_path, image, compression="zlib")
 77            imageio.imwrite(mask_path, mask, compression="zlib")
 78
 79    shutil.rmtree(mat_dir)
 80
 81
 82def get_platif_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 83    """Download the PlaTiF data.
 84
 85    Args:
 86        path: Filepath to a folder where the data is downloaded for further processing.
 87        download: Whether to download the data if it is not present.
 88
 89    Returns:
 90        Filepath where the preprocessed data is stored.
 91    """
 92    preprocessed_dir = os.path.join(path, "preprocessed")
 93    if os.path.exists(preprocessed_dir) and glob(os.path.join(preprocessed_dir, "images", "*.tif")):
 94        return preprocessed_dir
 95
 96    os.makedirs(path, exist_ok=True)
 97
 98    mat_dir = os.path.join(path, "mat_files")
 99    os.makedirs(mat_dir, exist_ok=True)
100    for fname, url in URLS.items():
101        zip_path = os.path.join(path, fname)
102        util.download_source(path=zip_path, url=url, download=download, checksum=CHECKSUMS[fname])
103        util.unzip(zip_path=zip_path, dst=mat_dir, remove=False)
104
105    _preprocess_platif(mat_dir, preprocessed_dir)
106    return preprocessed_dir
107
108
109def get_platif_paths(path: Union[os.PathLike, str], download: bool = False) -> Tuple[List[str], List[str]]:
110    """Get paths to the PlaTiF data.
111
112    Args:
113        path: Filepath to a folder where the data is downloaded for further processing.
114        download: Whether to download the data if it is not present.
115
116    Returns:
117        List of filepaths for the image data.
118        List of filepaths for the label data.
119    """
120    preprocessed_dir = get_platif_data(path, download)
121
122    image_paths = natsorted(glob(os.path.join(preprocessed_dir, "images", "*.tif")))
123    mask_paths = natsorted(glob(os.path.join(preprocessed_dir, "masks", "*.tif")))
124
125    if len(image_paths) == 0 or len(image_paths) != len(mask_paths):
126        raise RuntimeError("Something went wrong with fetching the image and label paths.")
127
128    return image_paths, mask_paths
129
130
131def get_platif_dataset(
132    path: Union[os.PathLike, str],
133    patch_shape: Tuple[int, int],
134    resize_inputs: bool = False,
135    download: bool = False,
136    **kwargs
137) -> Dataset:
138    """Get the PlaTiF dataset for tibia segmentation in knee radiographs.
139
140    Args:
141        path: Filepath to a folder where the data is downloaded for further processing.
142        patch_shape: The patch shape to use for training.
143        resize_inputs: Whether to resize inputs to the desired patch shape.
144        download: Whether to download the data if it is not present.
145        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
146
147    Returns:
148        The segmentation dataset.
149    """
150    image_paths, mask_paths = get_platif_paths(path, download)
151
152    if resize_inputs:
153        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False}
154        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
155            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
156        )
157
158    return torch_em.default_segmentation_dataset(
159        raw_paths=image_paths,
160        raw_key=None,
161        label_paths=mask_paths,
162        label_key=None,
163        patch_shape=patch_shape,
164        is_seg_dataset=False,
165        **kwargs
166    )
167
168
169def get_platif_loader(
170    path: Union[os.PathLike, str],
171    batch_size: int,
172    patch_shape: Tuple[int, int],
173    resize_inputs: bool = False,
174    download: bool = False,
175    **kwargs
176) -> DataLoader:
177    """Get the PlaTiF dataloader for tibia segmentation in knee radiographs.
178
179    Args:
180        path: Filepath to a folder where the data is downloaded for further processing.
181        batch_size: The batch size for training.
182        patch_shape: The patch shape to use for training.
183        resize_inputs: Whether to resize inputs to the desired patch shape.
184        download: Whether to download the data if it is not present.
185        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
186
187    Returns:
188        The DataLoader.
189    """
190    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
191    dataset = get_platif_dataset(path, patch_shape, resize_inputs, download, **ds_kwargs)
192    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
URLS = {'Patient Data_Part 1.zip': 'https://zenodo.org/records/18007397/files/Patient%20Data_Part%201.zip', 'Patient Data_Part 2.zip': 'https://zenodo.org/records/18007397/files/Patient%20Data_Part%202.zip', 'Patient Data_Part 3.zip': 'https://zenodo.org/records/18007397/files/Patient%20Data_Part%203.zip', 'Patient Data_Part 4.zip': 'https://zenodo.org/records/18007397/files/Patient%20Data_Part%204.zip', 'Patient Data_Part 5.zip': 'https://zenodo.org/records/18007397/files/Patient%20Data_Part%205.zip'}
CHECKSUMS = {'Patient Data_Part 1.zip': 'df72a6e0d988492eb87928105596001c6551db38d21dfb0a5d46942c45bd9d49', 'Patient Data_Part 2.zip': 'ef0f3315dbd9d47361dad23840cd4a8fbf36fbeb32955deddebc5fe29e14134b', 'Patient Data_Part 3.zip': '63b77dc6e929df4d5c810a324d079905158d9196796ed9696ee5f1d81094ae09', 'Patient Data_Part 4.zip': 'd6135f67f5d7d76fab2b93ce059d56b6647e5bac87cf3b0d5ab0329121406756', 'Patient Data_Part 5.zip': 'dce5a29107a2e64eb7c25016e8cb65ba46d022f555983b144172602f2920416c'}
def get_platif_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 83def get_platif_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 84    """Download the PlaTiF data.
 85
 86    Args:
 87        path: Filepath to a folder where the data is downloaded for further processing.
 88        download: Whether to download the data if it is not present.
 89
 90    Returns:
 91        Filepath where the preprocessed data is stored.
 92    """
 93    preprocessed_dir = os.path.join(path, "preprocessed")
 94    if os.path.exists(preprocessed_dir) and glob(os.path.join(preprocessed_dir, "images", "*.tif")):
 95        return preprocessed_dir
 96
 97    os.makedirs(path, exist_ok=True)
 98
 99    mat_dir = os.path.join(path, "mat_files")
100    os.makedirs(mat_dir, exist_ok=True)
101    for fname, url in URLS.items():
102        zip_path = os.path.join(path, fname)
103        util.download_source(path=zip_path, url=url, download=download, checksum=CHECKSUMS[fname])
104        util.unzip(zip_path=zip_path, dst=mat_dir, remove=False)
105
106    _preprocess_platif(mat_dir, preprocessed_dir)
107    return preprocessed_dir

Download the PlaTiF 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:

Filepath where the preprocessed data is stored.

def get_platif_paths( path: Union[os.PathLike, str], download: bool = False) -> Tuple[List[str], List[str]]:
110def get_platif_paths(path: Union[os.PathLike, str], download: bool = False) -> Tuple[List[str], List[str]]:
111    """Get paths to the PlaTiF data.
112
113    Args:
114        path: Filepath to a folder where the data is downloaded for further processing.
115        download: Whether to download the data if it is not present.
116
117    Returns:
118        List of filepaths for the image data.
119        List of filepaths for the label data.
120    """
121    preprocessed_dir = get_platif_data(path, download)
122
123    image_paths = natsorted(glob(os.path.join(preprocessed_dir, "images", "*.tif")))
124    mask_paths = natsorted(glob(os.path.join(preprocessed_dir, "masks", "*.tif")))
125
126    if len(image_paths) == 0 or len(image_paths) != len(mask_paths):
127        raise RuntimeError("Something went wrong with fetching the image and label paths.")
128
129    return image_paths, mask_paths

Get paths to the PlaTiF 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.

def get_platif_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
132def get_platif_dataset(
133    path: Union[os.PathLike, str],
134    patch_shape: Tuple[int, int],
135    resize_inputs: bool = False,
136    download: bool = False,
137    **kwargs
138) -> Dataset:
139    """Get the PlaTiF dataset for tibia segmentation in knee radiographs.
140
141    Args:
142        path: Filepath to a folder where the data is downloaded for further processing.
143        patch_shape: The patch shape to use for training.
144        resize_inputs: Whether to resize inputs to the desired patch shape.
145        download: Whether to download the data if it is not present.
146        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
147
148    Returns:
149        The segmentation dataset.
150    """
151    image_paths, mask_paths = get_platif_paths(path, download)
152
153    if resize_inputs:
154        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": False}
155        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
156            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
157        )
158
159    return torch_em.default_segmentation_dataset(
160        raw_paths=image_paths,
161        raw_key=None,
162        label_paths=mask_paths,
163        label_key=None,
164        patch_shape=patch_shape,
165        is_seg_dataset=False,
166        **kwargs
167    )

Get the PlaTiF dataset for tibia segmentation in knee radiographs.

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 inputs to the desired 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_platif_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
170def get_platif_loader(
171    path: Union[os.PathLike, str],
172    batch_size: int,
173    patch_shape: Tuple[int, int],
174    resize_inputs: bool = False,
175    download: bool = False,
176    **kwargs
177) -> DataLoader:
178    """Get the PlaTiF dataloader for tibia segmentation in knee radiographs.
179
180    Args:
181        path: Filepath to a folder where the data is downloaded for further processing.
182        batch_size: The batch size for training.
183        patch_shape: The patch shape to use for training.
184        resize_inputs: Whether to resize inputs to the desired patch shape.
185        download: Whether to download the data if it is not present.
186        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
187
188    Returns:
189        The DataLoader.
190    """
191    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
192    dataset = get_platif_dataset(path, patch_shape, resize_inputs, download, **ds_kwargs)
193    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the PlaTiF dataloader for tibia segmentation in knee radiographs.

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 inputs to the desired 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.