Observed since 20 Oct, 18:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Production-ready, type-safe dataset management, YOLO parsing, and caching utilities for computer vision pipelines
Production-ready, type-safe dataset management, YOLO parsing, caching, and in-memory augmentation for computer vision pipelines
# Install dataset toolkit (pulls acmenra-cv, no heavy ML stack)
pip install acmenra-ds
# OR install with development extras (pytest, ddt, black, mypy)
pip install "acmenra-ds[dev]"
acmenra-ds is the data layer of the Acmenra stack. It turns a YOLO data.yaml plus a folder of images/labels into typed objects (Config, Dataset, Split, Sample, Instance) with strict validation, layout autodetection, RAM caching, visualization, and a composable augmentation pipeline.
It sits on top of acmenra-cv geometry (Box, Polygon, Obb, Instance) and rendering (Drawer, Style). The model itself stays out of this package.
| Module | Purpose | Key Features |
|---|---|---|
data | Config, Dataset, Split, Sample, LabelCache | DIRECT / REVERSE layouts, health(), mutation logging, O(1) label cache |
image | Atomic image ingestion | ImageParser.parse() → ndarray or None, strict vs lenient |
label | YOLO .txt parse / write | DETECT / SEGMENT / OBB, inverse LabelParser ↔ LabelWriter |
augmentation | In-memory (image, List[Instance]) pipeline | Transform + Compose, geometric + photometric, no source mutation |
All geometries stay in normalized coordinate space [0.0, 1.0]. Disk I/O is Split / LabelWriter. Augmentation never walks the filesystem.
Config.from_yaml() — Ultralytics-style YAML, autodetection of DIRECT (train/images) vs REVERSE (images/train)train_leaf / images_leaf / labels_leaf for non-standard folder names (trn, imgs, lbs).., unique class names, bool rejected as intDataset owns train / val / test as Split instances — not three separate loadershealth() — filesystem integrity across splits (missing images, missing labels)visualize() — Box / Polygon / OBB via acmenra-cv.DrawerSample.label_path is Optional; empty List[Instance] is valid(image, List[Instance]) → (image, List[Instance])p is rolled in __call__, not inside apply()Instance via map_instance (DETECT / SEGMENT / OBB independently)LabelCache — parsed List[Instance] keyed by stem, optional max_sizeis_strict — raise on the first bad file, or log and skipImageParser / LabelParser / LabelWriter across splitsSingle source of truth for paths, classes, and splits
Config — YOLO data.yaml containerfrom_yaml(): Loads YAML, resolves root to the YAML parent, autodetects layout.get_train_images() / get_train_labels() (and val/test): layout-aware absolute paths.names, nc, task, layout: class map, TaskType, DatasetLayout.*_leaf: rename split / images / labels folders without rewriting YAML.Dataset — Train + optional Val/Test__init__(config, category, is_cache, is_strict): builds all configured splits.train / val / test: Split accessors.health(): aggregated missing-file report.visualize(sample, style): draws the sample with the dataset task flags.from_yaml(): factory that parses YAML then constructs Dataset.Split — One of TRAIN / VAL / TESTfor sample in dataset.train, dataset.train[i]).get_instances(idx): cache hit or parse-on-read.visualize(idx, style): draw by index.health(): per-split filesystem check.Sample — Image + optional labelstem, image_path, label_path, is_labeled().to_dict() / from_dict() for manifests.LabelCache — RAM cache of List[Instance]store(), get(), __getitem__ (raises KeyError on miss), remove(), clear().DataSplit & DatasetLayoutDataSplit: TRAIN, VAL, TEST.DatasetLayout: DIRECT, REVERSE.Atomic read:
ndarrayorNone
ImageParserparse(path, strict): cv2.imread + min dimension checks.None.LabelParser — one return value, no status tuples.Inverse pair for YOLO
.txt
LabelParsercx cy w h), SEGMENT (flat polygon), OBB (cx cy w h angle_rad).[0, nc) and coordinates in [0.0, 1.0].acmenra_cv.Instance with Box / Polygon / Obb.LabelWriterList[Instance] to a .txt.In-memory only. Disk is
Split+LabelWriter.
Transform — ABC__call__(image, labels): validate → roll p → apply().apply(): subclasses implement the actual op; must not mutate inputs._as_image, _as_labels, _as_prob, _as_float, _as_int.ComposeList[Transform]. Each step rolls its own p.transforms getter returns a shallow copy.acmenra_ds.augmentation.geometric)HorizontalFlip — cv2.flip(..., 1), x' = 1 - x on Box / Polygon / OBB.VerticalFlip — cv2.flip(..., 0), y' = 1 - y.Resize — pixels to (H, W); normalized labels pass through.acmenra_ds.augmentation.photometric)Brightness, ChannelBrightness, Blur, Noise, Pixelate, Gray.Normalize — uint8 [0, 255] → float32 [0.0, 1.0]. Last step in a training loop. Do not imshow / JPEG it.acmenra_ds.augmentation.geometry)hflip_box, vflip_obb, map_instance, rebuild_instance.from enum import IntEnum
import cv2
import numpy as np
from acmenra_cv import Style, Stroke, Fill, Drawer, TaskType
from acmenra_ds import Config
from acmenra_ds.data import Dataset
from acmenra_ds.augmentation import (
Compose,
HorizontalFlip,
VerticalFlip,
Brightness,
Blur,
Noise,
)
class Defect(IntEnum):
inclusion = 0
scratch = 1
crack = 2
# 1. YAML → Config (DIRECT / REVERSE is detected)
config = Config.from_yaml("/path/to/dataset/data.yaml")
print(config) # DatasetConfig(root=..., nc=..., layout=direct, splits=[...])
# 2. Dataset owns train / val / test
dataset = Dataset(config=config, category=Defect, is_cache=True, is_strict=False)
print(dataset.health())
# 3. Iterate a split
style = Style(
palette=np.random.randint(0, 255, (80, 3)).tolist(),
stroke=Stroke(thickness=2, alpha=0.8),
fill=Fill(alpha=0.2),
show=True,
)
for sample in dataset.train:
frame = dataset.visualize(sample=sample, style=style)
cv2.imshow("sample", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# 4. Online augmentation (training loop)
pipeline = Compose([
HorizontalFlip(p=0.5),
VerticalFlip(p=0.5),
Brightness(min_factor=0.6, max_factor=1.4, p=0.8),
Blur(max_ksize=5, p=0.4),
Noise(max_ratio=0.03, p=0.4),
])
drawer = Drawer(style=style)
sample = dataset.train[0]
image = dataset.train.image_parser.parse(sample.image_path, is_strict=False)
labels = dataset.train.get_instances(0)
aug_image, aug_labels = pipeline(image, labels)
vis = drawer.draw_instances(
frame=aug_image.copy(),
instances=aug_labels,
is_box=dataset.task == TaskType.DETECT,
is_obb=dataset.task == TaskType.OBB,
is_polygon=dataset.task == TaskType.SEGMENT,
)
cv2.imshow("augmented", vis)
cv2.waitKey(0)
Offline export (new directory only — never overwrite the source dataset):
from pathlib import Path
from acmenra_ds.label import LabelWriter
out_img = Path("/data/aug/train/images")
out_lbl = Path("/data/aug/train/labels")
out_img.mkdir(parents=True, exist_ok=True)
out_lbl.mkdir(parents=True, exist_ok=True)
writer = dataset.train.label_writer
for idx, sample in enumerate(dataset.train):
image = dataset.train.image_parser.parse(sample.image_path, is_strict=False)
labels = dataset.train.get_instances(idx)
if image is None:
continue
aug_image, aug_labels = pipeline(image, labels)
cv2.imwrite(str(out_img / f"{sample.stem}_aug.jpg"), aug_image)
writer.write(out_lbl / f"{sample.stem}_aug.txt", aug_labels)
Installed with pip install acmenra-ds:
acmenra-cv>=0.3.2.0
PyYAML>=6.0
numpy>=1.21.0
opencv-python>=4.5.0
Development extras (pip install "acmenra-ds[dev]"):
pytest>=7.0.0
ddt>=1.6.0
black>=23.0.0
mypy>=1.0.0
Python >=3.9. No PyTorch in the core package — Split is a plain iterable; wrap it in torch.utils.data.Dataset yourself if you need a DataLoader.
# All tests
pytest tests/
# By module
pytest tests/data/
pytest tests/augmentation/
Coverage includes:
to_dict / from_dict round-tripsThis project is licensed under the GNU Affero General Public License v3 or later (AGPL-3.0-or-later). See the LICENSE file for details.
acmenra.studio — Building reliable vision systems for the edge. Every sample, every label, every frame.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.2.0.2 | 29 Sept 2026 | 9 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 18:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:e5b3ed897e2c6af608961b9ac5f733157164a4a5473821d1e88cc247babed7da