Skip to content

simet.datasets.binary_folder_dataset

simet.datasets.binary_folder_dataset

BinaryFolderDataset

BinaryFolderDataset(root, transform=None, target_transform=None)

Bases: VisionDataset

Binary image dataset sourced from a folder structure.

Expects the root directory to contain two subdirectories (case-insensitive): GOOD/ and BAD/. All image files under these subtrees are discovered recursively and labeled as: - GOOD → label 1 - BAD → label 0

Supported extensions include: .jpg, .jpeg, .png, .bmp, .gif, .webp, .tif, .tiff.

Parameters:

Name Type Description Default
root Path | str

Root directory of the dataset. Must contain subfolders for the two classes (e.g., GOOD/ and BAD/; case-insensitive).

required
transform Callable | None

Optional transform applied to each PIL image before it is returned. Typical usage is a torchvision transform pipeline that produces a torch.Tensor. If omitted, the raw PIL image (converted to RGB) is returned.

None
target_transform Callable | None

Optional transform applied to the integer class label (0/1) after it is created. (Note: if not used in __getitem__, this parameter is accepted for API parity with VisionDataset.)

None

Attributes:

Name Type Description
root Path | str

The dataset root provided at construction.

samples list[tuple[Path, int]]

List of discovered samples as (filepath, label) tuples, where label is 1 for GOOD and 0 for BAD. The list is shuffled at initialization.

Raises:

Type Description
FileNotFoundError

If root does not exist.

RuntimeError

If no images are found under the expected class subdirectories.

Notes
  • Class folder names are matched case-insensitively via lower-casing.
  • Directory walking is recursive; all nested images under GOOD/BAD are included.
  • The sample list is shuffled once at initialization (not per epoch).
  • If transform is None, __getitem__ returns a PIL image (RGB) instead of a tensor; be consistent with your downstream code.
Example

ds = BinaryFolderDataset("data/my_dataset", transform=my_tfms) len(ds) 1280 x, y = ds[0] x.shape # doctest: +SKIP torch.Size([3, H, W]) int(y) 1

Initialize the dataset; see class docstring for parameter details.

Source code in simet/datasets/binary_folder_dataset.py
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
def __init__(
    self,
    root: Path,
    transform: Callable | None = None,
    target_transform: Callable | None = None,
) -> None:  # type: ignore
    """Initialize the dataset; see class docstring for parameter details."""
    super().__init__(root, transform=transform, target_transform=target_transform)  # type: ignore
    self.root = Path(root)
    if not self.root.exists():
        logger.error(f"Dataset root {self.root} does not exist.")
        raise FileNotFoundError(f"Dataset root {self.root} does not exist.")

    self.samples: list[tuple[Path, int]] = []
    for dirpath, dirnames, _ in os.walk(self.root):
        for dirname in dirnames:
            label_name = dirname.lower()
            if label_name not in ("good", "bad"):
                continue
            label = 1 if label_name == "good" else 0
            current = Path(dirpath) / dirname
            for candidate in current.rglob("*"):
                if (
                    candidate.is_file()
                    and candidate.suffix.lower() in IMG_EXTENSIONS
                ):
                    self.samples.append((candidate, label))

    if not self.samples:
        logger.error(
            f"No images found under {self.root}. Expected GOOD/ and BAD/ subdirectories."
        )
        raise RuntimeError(
            f"No images found under {self.root}. Expected GOOD/ and BAD/ subdirectories."
        )

    random.shuffle(self.samples)

__getitem__

__getitem__(index)

Load and return a (image, label) pair at the given index.

The image is opened with PIL and converted to RGB. If transform is set, it is applied to the image; otherwise the raw PIL image is returned. The label is returned as a torch.long tensor with values {0, 1}.

Parameters:

Name Type Description Default
index int

Index of the sample to retrieve.

required

Returns:

Type Description
tuple[Tensor, Tensor]

tuple[torch.Tensor | PIL.Image.Image, torch.Tensor]: The transformed image (or PIL image if no transform) and the label tensor.

Source code in simet/datasets/binary_folder_dataset.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
def __getitem__(self, index: int) -> tuple[torch.Tensor, torch.Tensor]:  # type: ignore[override]
    """Load and return a (image, label) pair at the given index.

    The image is opened with PIL and converted to RGB. If ``transform`` is set,
    it is applied to the image; otherwise the raw PIL image is returned.
    The label is returned as a ``torch.long`` tensor with values {0, 1}.

    Args:
        index (int): Index of the sample to retrieve.

    Returns:
        tuple[torch.Tensor | PIL.Image.Image, torch.Tensor]:
            The transformed image (or PIL image if no transform) and the label tensor.

    """
    path, label = self.samples[index]
    with Image.open(path) as img:
        image = img.convert("RGB")
    tensor = self.transform(image) if self.transform else image
    target = torch.tensor(label, dtype=torch.long)
    return tensor, target  # type: ignore

__len__

__len__()

Return the number of samples discovered under GOOD/BAD.

Source code in simet/datasets/binary_folder_dataset.py
108
109
110
def __len__(self) -> int:  # type: ignore[override]
    """Return the number of samples discovered under GOOD/BAD."""
    return len(self.samples)