torch_em.data.datasets.medical.periorbital_seg

The Periorbital Segmentation dataset contains annotations for periorbital anatomical structures (eyebrow, sclera, iris, caruncle, eyelid) in cropped eye images.

The dataset bundles both the cropped eye images and the segmentation masks (no need to source images separately from the Chicago Face Database or CelebAMask-HQ). It combines two subsets:

  • 'celeb': 2015 image-mask pairs cropped from CelebAMask-HQ.
  • 'cfd': 827 image-mask pairs cropped from the Chicago Face Database. (The archive also has a 'combined_final_data' folder, but it is inconsistent - it has 3670 images and only 2842 masks - so this module sources images and masks from the per-origin 'celeb_final_data' and 'cfd_final_data' folders instead, which are fully paired.)

The label legend (confirmed from the dataset's own 'coco2voc_aux.py' preprocessing script) is:

  • background: 0, eyebrow: 1, sclera: 2, iris (incl. pupil): 3, caruncle: 4, eyelid: 5

The dataset is located at https://doi.org/10.5281/zenodo.13916845 (Zenodo, CC BY 4.0). This dataset is from the publication https://doi.org/10.48550/arXiv.2409.20407. Please cite it if you use this dataset in your research.

  1"""The Periorbital Segmentation dataset contains annotations for periorbital anatomical
  2structures (eyebrow, sclera, iris, caruncle, eyelid) in cropped eye images.
  3
  4The dataset bundles both the cropped eye images and the segmentation masks (no need to
  5source images separately from the Chicago Face Database or CelebAMask-HQ). It combines two
  6subsets:
  7- 'celeb': 2015 image-mask pairs cropped from CelebAMask-HQ.
  8- 'cfd': 827 image-mask pairs cropped from the Chicago Face Database.
  9(The archive also has a 'combined_final_data' folder, but it is inconsistent - it has 3670
 10images and only 2842 masks - so this module sources images and masks from the per-origin
 11'celeb_final_data' and 'cfd_final_data' folders instead, which are fully paired.)
 12
 13The label legend (confirmed from the dataset's own 'coco2voc_aux.py' preprocessing script) is:
 14- background: 0, eyebrow: 1, sclera: 2, iris (incl. pupil): 3, caruncle: 4, eyelid: 5
 15
 16The dataset is located at https://doi.org/10.5281/zenodo.13916845 (Zenodo, CC BY 4.0).
 17This dataset is from the publication https://doi.org/10.48550/arXiv.2409.20407.
 18Please cite it if you use this dataset in your research.
 19"""
 20
 21import os
 22from glob import glob
 23from natsort import natsorted
 24from typing import Union, Tuple, Literal, List
 25
 26from torch.utils.data import Dataset, DataLoader
 27
 28import torch_em
 29
 30from .. import util
 31
 32
 33URL = "https://zenodo.org/records/13916845/files/periorbital_dataset.zip?download=1"
 34CHECKSUM = "7c1cd92e4bc58e5b288c6eeb1769a98fa119338bfb25a2d3bb7ccebed8d99011"
 35
 36SUBSETS = ["celeb", "cfd"]
 37
 38
 39def get_periorbital_seg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
 40    """Download the Periorbital Segmentation 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 stored.
 48    """
 49    data_dir = os.path.join(path, "periorbital_dataset")
 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, "periorbital_dataset.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 get_periorbital_seg_paths(
 63    path: Union[os.PathLike, str],
 64    subset: Union[Literal["celeb", "cfd"], List[str]] = SUBSETS,
 65    download: bool = False,
 66) -> Tuple[List[str], List[str]]:
 67    """Get paths to the Periorbital Segmentation data.
 68
 69    Args:
 70        path: Filepath to a folder where the data is downloaded for further processing.
 71        subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
 72        download: Whether to download the data if it is not present.
 73
 74    Returns:
 75        List of filepaths for the image data.
 76        List of filepaths for the label data.
 77    """
 78    data_dir = get_periorbital_seg_data(path, download)
 79
 80    subsets = [subset] if isinstance(subset, str) else subset
 81    for s in subsets:
 82        if s not in SUBSETS:
 83            raise ValueError(f"'{s}' is not a valid subset. Please choose from {SUBSETS}.")
 84
 85    image_paths, gt_paths = [], []
 86    for s in subsets:
 87        this_image_paths = natsorted(glob(os.path.join(data_dir, f"{s}_final_data", f"{s}_output_images", "*.jpg")))
 88        this_gt_dir = os.path.join(data_dir, f"{s}_final_data", f"{s}_output_masks")
 89        for image_path in this_image_paths:
 90            fname = os.path.splitext(os.path.basename(image_path))[0]
 91            gt_path = os.path.join(this_gt_dir, f"{fname}.png")
 92            if not os.path.exists(gt_path):
 93                continue
 94            image_paths.append(image_path)
 95            gt_paths.append(gt_path)
 96
 97    assert len(image_paths) == len(gt_paths) and len(image_paths) > 0, (
 98        "No image-mask pairs were found. The expected per-subset 'celeb_output_images' / 'celeb_output_masks' "
 99        f"(and 'cfd_output_images' / 'cfd_output_masks') layout may not match the actual structure of the "
100        f"downloaded data. Please inspect the data at '{data_dir}' and update the search pattern accordingly."
101    )
102
103    return image_paths, gt_paths
104
105
106def get_periorbital_seg_dataset(
107    path: Union[os.PathLike, str],
108    patch_shape: Tuple[int, int],
109    subset: Union[Literal["celeb", "cfd"], List[str]] = SUBSETS,
110    resize_inputs: bool = False,
111    download: bool = False,
112    **kwargs
113) -> Dataset:
114    """Get the Periorbital Segmentation dataset for periorbital anatomical structure segmentation.
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        subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
120        resize_inputs: Whether to resize inputs to the desired 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_periorbital_seg_paths(path, subset, download)
128
129    if resize_inputs:
130        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
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        is_seg_dataset=False,
141        patch_shape=patch_shape,
142        **kwargs
143    )
144
145
146def get_periorbital_seg_loader(
147    path: Union[os.PathLike, str],
148    batch_size: int,
149    patch_shape: Tuple[int, int],
150    subset: Union[Literal["celeb", "cfd"], List[str]] = SUBSETS,
151    resize_inputs: bool = False,
152    download: bool = False,
153    **kwargs
154) -> DataLoader:
155    """Get the Periorbital Segmentation dataloader for periorbital anatomical structure segmentation.
156
157    Args:
158        path: Filepath to a folder where the data is downloaded for further processing.
159        batch_size: The batch size for training.
160        patch_shape: The patch shape to use for training.
161        subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
162        resize_inputs: Whether to resize inputs to the desired patch shape.
163        download: Whether to download the data if it is not present.
164        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
165
166    Returns:
167        The DataLoader.
168    """
169    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
170    dataset = get_periorbital_seg_dataset(path, patch_shape, subset, resize_inputs, download, **ds_kwargs)
171    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)
URL = 'https://zenodo.org/records/13916845/files/periorbital_dataset.zip?download=1'
CHECKSUM = '7c1cd92e4bc58e5b288c6eeb1769a98fa119338bfb25a2d3bb7ccebed8d99011'
SUBSETS = ['celeb', 'cfd']
def get_periorbital_seg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
40def get_periorbital_seg_data(path: Union[os.PathLike, str], download: bool = False) -> str:
41    """Download the Periorbital Segmentation 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 stored.
49    """
50    data_dir = os.path.join(path, "periorbital_dataset")
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, "periorbital_dataset.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 Periorbital Segmentation 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 stored.

def get_periorbital_seg_paths( path: Union[os.PathLike, str], subset: Union[Literal['celeb', 'cfd'], List[str]] = ['celeb', 'cfd'], download: bool = False) -> Tuple[List[str], List[str]]:
 63def get_periorbital_seg_paths(
 64    path: Union[os.PathLike, str],
 65    subset: Union[Literal["celeb", "cfd"], List[str]] = SUBSETS,
 66    download: bool = False,
 67) -> Tuple[List[str], List[str]]:
 68    """Get paths to the Periorbital Segmentation data.
 69
 70    Args:
 71        path: Filepath to a folder where the data is downloaded for further processing.
 72        subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
 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_periorbital_seg_data(path, download)
 80
 81    subsets = [subset] if isinstance(subset, str) else subset
 82    for s in subsets:
 83        if s not in SUBSETS:
 84            raise ValueError(f"'{s}' is not a valid subset. Please choose from {SUBSETS}.")
 85
 86    image_paths, gt_paths = [], []
 87    for s in subsets:
 88        this_image_paths = natsorted(glob(os.path.join(data_dir, f"{s}_final_data", f"{s}_output_images", "*.jpg")))
 89        this_gt_dir = os.path.join(data_dir, f"{s}_final_data", f"{s}_output_masks")
 90        for image_path in this_image_paths:
 91            fname = os.path.splitext(os.path.basename(image_path))[0]
 92            gt_path = os.path.join(this_gt_dir, f"{fname}.png")
 93            if not os.path.exists(gt_path):
 94                continue
 95            image_paths.append(image_path)
 96            gt_paths.append(gt_path)
 97
 98    assert len(image_paths) == len(gt_paths) and len(image_paths) > 0, (
 99        "No image-mask pairs were found. The expected per-subset 'celeb_output_images' / 'celeb_output_masks' "
100        f"(and 'cfd_output_images' / 'cfd_output_masks') layout may not match the actual structure of the "
101        f"downloaded data. Please inspect the data at '{data_dir}' and update the search pattern accordingly."
102    )
103
104    return image_paths, gt_paths

Get paths to the Periorbital Segmentation data.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
  • 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_periorbital_seg_dataset( path: Union[os.PathLike, str], patch_shape: Tuple[int, int], subset: Union[Literal['celeb', 'cfd'], List[str]] = ['celeb', 'cfd'], resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataset.Dataset:
107def get_periorbital_seg_dataset(
108    path: Union[os.PathLike, str],
109    patch_shape: Tuple[int, int],
110    subset: Union[Literal["celeb", "cfd"], List[str]] = SUBSETS,
111    resize_inputs: bool = False,
112    download: bool = False,
113    **kwargs
114) -> Dataset:
115    """Get the Periorbital Segmentation dataset for periorbital anatomical structure segmentation.
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        subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
121        resize_inputs: Whether to resize inputs to the desired patch shape.
122        download: Whether to download the data if it is not present.
123        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset`.
124
125    Returns:
126        The segmentation dataset.
127    """
128    image_paths, gt_paths = get_periorbital_seg_paths(path, subset, download)
129
130    if resize_inputs:
131        resize_kwargs = {"patch_shape": patch_shape, "is_rgb": True}
132        kwargs, patch_shape = util.update_kwargs_for_resize_trafo(
133            kwargs=kwargs, patch_shape=patch_shape, resize_inputs=resize_inputs, resize_kwargs=resize_kwargs
134        )
135
136    return torch_em.default_segmentation_dataset(
137        raw_paths=image_paths,
138        raw_key=None,
139        label_paths=gt_paths,
140        label_key=None,
141        is_seg_dataset=False,
142        patch_shape=patch_shape,
143        **kwargs
144    )

Get the Periorbital Segmentation dataset for periorbital anatomical structure segmentation.

Arguments:
  • path: Filepath to a folder where the data is downloaded for further processing.
  • patch_shape: The patch shape to use for training.
  • subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
  • 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_periorbital_seg_loader( path: Union[os.PathLike, str], batch_size: int, patch_shape: Tuple[int, int], subset: Union[Literal['celeb', 'cfd'], List[str]] = ['celeb', 'cfd'], resize_inputs: bool = False, download: bool = False, **kwargs) -> torch.utils.data.dataloader.DataLoader:
147def get_periorbital_seg_loader(
148    path: Union[os.PathLike, str],
149    batch_size: int,
150    patch_shape: Tuple[int, int],
151    subset: Union[Literal["celeb", "cfd"], List[str]] = SUBSETS,
152    resize_inputs: bool = False,
153    download: bool = False,
154    **kwargs
155) -> DataLoader:
156    """Get the Periorbital Segmentation dataloader for periorbital anatomical structure segmentation.
157
158    Args:
159        path: Filepath to a folder where the data is downloaded for further processing.
160        batch_size: The batch size for training.
161        patch_shape: The patch shape to use for training.
162        subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
163        resize_inputs: Whether to resize inputs to the desired patch shape.
164        download: Whether to download the data if it is not present.
165        kwargs: Additional keyword arguments for `torch_em.default_segmentation_dataset` or for the PyTorch DataLoader.
166
167    Returns:
168        The DataLoader.
169    """
170    ds_kwargs, loader_kwargs = util.split_kwargs(torch_em.default_segmentation_dataset, **kwargs)
171    dataset = get_periorbital_seg_dataset(path, patch_shape, subset, resize_inputs, download, **ds_kwargs)
172    return torch_em.get_data_loader(dataset, batch_size, **loader_kwargs)

Get the Periorbital Segmentation dataloader for periorbital anatomical structure segmentation.

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.
  • subset: The choice of data subset(s). Either 'celeb', 'cfd', or a list of both. By default, loads both.
  • 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.