Source code for stable_datasets.images.bee_dataset

"""BeeDataset: top-down photos of honey bees with multi-label annotations."""

import io
import json
import zipfile

from PIL import Image as PILImage

from stable_datasets.schema import (
    DatasetInfo,
    DatasetSource,
    DownloadInfo,
    Features,
    Value,
    Version,
)
from stable_datasets.schema import (
    Image as ImageFeature,
)
from stable_datasets.utils import BaseDatasetBuilder


_LABELS = ("varroa", "pollen", "wasps", "cooling")
_IMAGE_DIR = "images_300"


[docs] class BeeDataset(BaseDatasetBuilder): """BeeDataset contains approximately 7,500 images with four binary labels. Images show bees or wasps from above against a green background. The labels are independent, so multiple labels may be active for one image: - varroa: varroa-mite infection - pollen: pollen packets are present - wasps: the image shows a wasp - cooling: cooling behavior is present The dataset has no official train/test split, so all examples are exposed through a single ``train`` split. Images in ``images_300`` have a height of 300 and a width of 150. """ VERSION = Version("1.0.0") SOURCE = DatasetSource( homepage="https://github.com/BeeAlarmed/BeeDataset", assets={ "train": DownloadInfo( url=("https://github.com/BeeAlarmed/BeeDataset/raw/refs/heads/main/BeeDataset_20201121.zip"), ), }, citation="""@misc{hickert2021beedataset, title={Dataset for a camera based bee-hive monitoring}, author={Fabian Hickert}, year={2021}, url={https://github.com/BeeAlarmed/BeeDataset} }""", license="GPL-3.0", ) def _info(self): return DatasetInfo( description=( "BeeDataset contains images of bees and wasps photographed " "from above at a hive entrance. Each image has four " "independent binary labels: varroa-mite infection, pollen " "packets, wasps, and cooling behavior." ), features=Features( { "image": ImageFeature(), **{label: Value("int32") for label in _LABELS}, } ), supervised_keys=None, homepage=self.SOURCE["homepage"], citation=self.SOURCE["citation"], license=self.SOURCE["license"], ) def _generate_examples(self, data_path, split): """Yield images and their multi-label annotations from the ZIP archive.""" if split != "train": raise ValueError(f"Unknown BeeDataset split: {split!r}") with zipfile.ZipFile(data_path) as archive: json_members = [ name for name in archive.namelist() if name.rsplit("/", 1)[-1] == "data.json" and "__MACOSX" not in name.split("/") ] if len(json_members) != 1: raise ValueError( f"Expected exactly one data.json in the archive, found {len(json_members)}: {json_members}" ) json_member = json_members[0] root = json_member[: -len("data.json")] annotations = json.loads(archive.read(json_member)) # Sorting gives a reproducible example order. for name in sorted(annotations): entry = annotations[name] missing_labels = [label for label in _LABELS if label not in entry] if missing_labels: raise ValueError(f"Missing labels for image {name!r}: {missing_labels}") labels = {label: int(bool(entry[label])) for label in _LABELS} image_path = f"{root}{_IMAGE_DIR}/{name}" try: image_bytes = archive.read(image_path) except KeyError as exc: raise ValueError( f"Image {image_path!r} referenced by data.json was not found in the archive." ) from exc with PILImage.open(io.BytesIO(image_bytes)) as img: if img.mode == "RGB": image = image_bytes else: image = img.convert("RGB").copy() yield name, {"image": image, **labels}