Skip to content

datasets

datasets

Lightweight, generic dataset wrappers for radiograph collections.

CephalometricDataset

CephalometricDataset(root, image_size=None, transform=None, landmarks_file=None, normalize_landmarks=True)

Bases: RadiographDataset

Lateral cephalometric radiographs (e.g. ISBI2015).

Source code in deltaflow/datasets/radiograph.py
def __init__(
    self,
    root: Union[str, Path],
    image_size: Optional[int] = None,
    transform: Optional[Callable] = None,
    landmarks_file: Optional[Union[str, Path]] = None,
    normalize_landmarks: bool = True,
):
    if Image is None:
        raise ImportError("Pillow is required for RadiographDataset (pip install pillow)")

    self.root = Path(root)
    self.image_size = image_size
    self.transform = transform
    self.normalize_landmarks = normalize_landmarks
    self.image_paths = sorted(
        p for p in self.root.rglob("*") if p.suffix.lower() in _IMAGE_EXTENSIONS
    )
    self.landmarks = self._load_landmarks(landmarks_file) if landmarks_file else None
    if self.landmarks is not None:
        # Keep only images that actually carry an annotation. Real
        # benchmarks ship official train/test splits as separate
        # annotation files, so ``root`` typically holds more images than
        # any single split annotates; dropping the rest is what lets one
        # image directory be reused across splits.
        self.image_paths = [p for p in self.image_paths if p.stem in self.landmarks]
        if not self.image_paths:
            raise ValueError(
                f"None of the images under {self.root} matched an annotation "
                "entry (checked by file stem). Check that image filenames "
                "line up with the annotation keys."
            )

ChestXrayDataset

ChestXrayDataset(root, image_size=None, transform=None, landmarks_file=None, normalize_landmarks=True)

Bases: RadiographDataset

Frontal chest radiographs (e.g. Shenzhen, NIH ChestX-ray14).

Source code in deltaflow/datasets/radiograph.py
def __init__(
    self,
    root: Union[str, Path],
    image_size: Optional[int] = None,
    transform: Optional[Callable] = None,
    landmarks_file: Optional[Union[str, Path]] = None,
    normalize_landmarks: bool = True,
):
    if Image is None:
        raise ImportError("Pillow is required for RadiographDataset (pip install pillow)")

    self.root = Path(root)
    self.image_size = image_size
    self.transform = transform
    self.normalize_landmarks = normalize_landmarks
    self.image_paths = sorted(
        p for p in self.root.rglob("*") if p.suffix.lower() in _IMAGE_EXTENSIONS
    )
    self.landmarks = self._load_landmarks(landmarks_file) if landmarks_file else None
    if self.landmarks is not None:
        # Keep only images that actually carry an annotation. Real
        # benchmarks ship official train/test splits as separate
        # annotation files, so ``root`` typically holds more images than
        # any single split annotates; dropping the rest is what lets one
        # image directory be reused across splits.
        self.image_paths = [p for p in self.image_paths if p.stem in self.landmarks]
        if not self.image_paths:
            raise ValueError(
                f"None of the images under {self.root} matched an annotation "
                "entry (checked by file stem). Check that image filenames "
                "line up with the annotation keys."
            )

HandRadiographDataset

HandRadiographDataset(root, image_size=None, transform=None, landmarks_file=None, normalize_landmarks=True)

Bases: RadiographDataset

Hand/wrist radiographs (e.g. DHA).

Source code in deltaflow/datasets/radiograph.py
def __init__(
    self,
    root: Union[str, Path],
    image_size: Optional[int] = None,
    transform: Optional[Callable] = None,
    landmarks_file: Optional[Union[str, Path]] = None,
    normalize_landmarks: bool = True,
):
    if Image is None:
        raise ImportError("Pillow is required for RadiographDataset (pip install pillow)")

    self.root = Path(root)
    self.image_size = image_size
    self.transform = transform
    self.normalize_landmarks = normalize_landmarks
    self.image_paths = sorted(
        p for p in self.root.rglob("*") if p.suffix.lower() in _IMAGE_EXTENSIONS
    )
    self.landmarks = self._load_landmarks(landmarks_file) if landmarks_file else None
    if self.landmarks is not None:
        # Keep only images that actually carry an annotation. Real
        # benchmarks ship official train/test splits as separate
        # annotation files, so ``root`` typically holds more images than
        # any single split annotates; dropping the rest is what lets one
        # image directory be reused across splits.
        self.image_paths = [p for p in self.image_paths if p.stem in self.landmarks]
        if not self.image_paths:
            raise ValueError(
                f"None of the images under {self.root} matched an annotation "
                "entry (checked by file stem). Check that image filenames "
                "line up with the annotation keys."
            )

ISBI2015CephalometricDataset

ISBI2015CephalometricDataset(root, image_size=None, transform=None, landmarks_file=None, landmarks_file_2=None, normalize_landmarks=True, n_landmarks=19)

Bases: CephalometricDataset

ISBI2015 "Automatic Cephalometric X-Ray Landmark Detection" benchmark.

Wang et al., "A benchmark for comparison of dental radiography analysis algorithms", Medical Image Analysis (2016). 400 lateral cephalograms (1935x2400 px, 0.1 mm/px), each with 19 anatomical landmarks annotated independently by a senior and a junior rater.

Two annotation layouts are recognised, picked automatically from landmarks_file:

  • Per-image text files (the original figshare release). Point landmarks_file at a directory of .txt files named after each image stem (e.g. 001.txt), one x,y pixel pair per line in a fixed anatomical order. Some releases append extra classification lines after the 19th point, which are ignored. Pass landmarks_file_2 for a second rater directory to average the two raters into one ground truth.
  • Consolidated CSV (common on Kaggle mirrors, e.g. jiahongqian/cephalometric-landmarks). Point landmarks_file at a .csv whose header is image_path,1_x,1_y,2_x,2_y,... and whose rows give one image's filename followed by the landmark pixel coordinates. Only the images listed in the CSV are kept, which is how the dataset's official train/test splits (separate CSV files) are honoured while every image lives in one directory.

Parameters:

Name Type Description Default
root Union[str, Path]

directory of radiograph images (searched recursively).

required
image_size Optional[int]

images (and landmarks) are rescaled to this square size.

None
landmarks_file Optional[Union[str, Path]]

a directory of per-image .txt annotations, or a single .csv split file (see above).

None
landmarks_file_2 Optional[Union[str, Path]]

optional second rater's .txt directory (e.g. 400_junior). If given, the two raters' points are averaged per landmark. Only applies to the per-image text layout.

None
n_landmarks int

landmarks per image (19 for the ISBI2015 challenge).

19
Source code in deltaflow/datasets/radiograph.py
def __init__(
    self,
    root: Union[str, Path],
    image_size: Optional[int] = None,
    transform: Optional[Callable] = None,
    landmarks_file: Optional[Union[str, Path]] = None,
    landmarks_file_2: Optional[Union[str, Path]] = None,
    normalize_landmarks: bool = True,
    n_landmarks: int = 19,
):
    self.n_landmarks = n_landmarks
    self._landmarks_file_2 = Path(landmarks_file_2) if landmarks_file_2 else None
    super().__init__(
        root,
        image_size=image_size,
        transform=transform,
        landmarks_file=landmarks_file,
        normalize_landmarks=normalize_landmarks,
    )

RadiographDataset

RadiographDataset(root, image_size=None, transform=None, landmarks_file=None, normalize_landmarks=True)

Bases: Dataset

Base dataset over a flat directory of grayscale radiographs.

Parameters:

Name Type Description Default
root Union[str, Path]

directory containing image files.

required
image_size Optional[int]

if given, images are resized to (image_size, image_size).

None
transform Optional[Callable]

optional callable applied to the loaded PIL image before conversion to a tensor. Receives and must return a PIL image.

None
landmarks_file Optional[Union[str, Path]]

optional path to a landmark annotation file, parsed by _load_landmarks, which subclasses may override for a specific benchmark's file format. Landmarks must be returned in the original image's pixel coordinates (row/col or x/y as the subclass defines, consistently), the base class rescales them to match image_size and (optionally) normalises them.

None
normalize_landmarks bool

if True (default), landmarks returned by __getitem__ are mapped from resized-image pixel coordinates to [-1, 1], matching the convention used by every other DeltaFlow example (e.g. examples/90-showcase/07-landmark-detection). Set to False to keep them in resized-image pixel units.

True
Source code in deltaflow/datasets/radiograph.py
def __init__(
    self,
    root: Union[str, Path],
    image_size: Optional[int] = None,
    transform: Optional[Callable] = None,
    landmarks_file: Optional[Union[str, Path]] = None,
    normalize_landmarks: bool = True,
):
    if Image is None:
        raise ImportError("Pillow is required for RadiographDataset (pip install pillow)")

    self.root = Path(root)
    self.image_size = image_size
    self.transform = transform
    self.normalize_landmarks = normalize_landmarks
    self.image_paths = sorted(
        p for p in self.root.rglob("*") if p.suffix.lower() in _IMAGE_EXTENSIONS
    )
    self.landmarks = self._load_landmarks(landmarks_file) if landmarks_file else None
    if self.landmarks is not None:
        # Keep only images that actually carry an annotation. Real
        # benchmarks ship official train/test splits as separate
        # annotation files, so ``root`` typically holds more images than
        # any single split annotates; dropping the rest is what lets one
        # image directory be reused across splits.
        self.image_paths = [p for p in self.image_paths if p.stem in self.landmarks]
        if not self.image_paths:
            raise ValueError(
                f"None of the images under {self.root} matched an annotation "
                "entry (checked by file stem). Check that image filenames "
                "line up with the annotation keys."
            )