euler-loading 2.21.0__tar.gz → 2.26.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- euler_loading-2.26.0/.gitignore +44 -0
- euler_loading-2.26.0/CHANGELOG.md +43 -0
- euler_loading-2.26.0/LICENSE +21 -0
- euler_loading-2.26.0/PKG-INFO +238 -0
- euler_loading-2.26.0/README.md +199 -0
- euler_loading-2.26.0/docs/README.md +34 -0
- euler_loading-2.26.0/docs/dataset.md +328 -0
- euler_loading-2.26.0/docs/loaders.md +354 -0
- euler_loading-2.26.0/docs/materialization.md +90 -0
- euler_loading-2.26.0/docs/preprocessing.md +141 -0
- euler_loading-2.26.0/docs/transform-descriptors.md +116 -0
- euler_loading-2.26.0/docs/writing.md +125 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/__init__.py +31 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/_dataset_contract.py +2 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/_ds_crawler_utils.py +0 -6
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/_resolution.py +22 -4
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/_writing.py +36 -3
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/dataset.py +136 -23
- euler_loading-2.26.0/euler_loading/geometry.py +34 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/__init__.py +14 -12
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/cpu/__init__.py +4 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/cpu/generic_dense_depth.py +0 -1
- euler_loading-2.26.0/euler_loading/loaders/cpu/synscapes.py +769 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/generate/loaders.json +152 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/gpu/__init__.py +4 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/gpu/generic_dense_depth.py +0 -1
- euler_loading-2.26.0/euler_loading/loaders/gpu/synscapes.py +204 -0
- euler_loading-2.26.0/euler_loading/loaders/materialized.py +32 -0
- euler_loading-2.26.0/euler_loading/loaders/synscapes.py +7 -0
- euler_loading-2.26.0/euler_loading/materialization.py +288 -0
- euler_loading-2.26.0/euler_loading/output_encoding.py +138 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/preprocessing.py +19 -46
- euler_loading-2.26.0/euler_loading/receipts.py +462 -0
- euler_loading-2.26.0/euler_loading/transform_descriptors.py +733 -0
- euler_loading-2.26.0/examples/README.md +28 -0
- euler_loading-2.26.0/examples/real_drive_sim_preview.py +67 -0
- euler_loading-2.26.0/examples/vkitti2_sample.py +104 -0
- euler_loading-2.26.0/pyproject.toml +65 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_indexing.py +0 -1
- euler_loading-2.26.0/tests/test_materialization.py +577 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_preprocessing.py +0 -1
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_real_dataset.py +37 -16
- euler_loading-2.26.0/tests/test_synscapes.py +949 -0
- euler_loading-2.26.0/tests/test_transform_descriptors.py +724 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_writing.py +23 -0
- euler_loading-2.21.0/.github/workflows/workflow.yml +0 -30
- euler_loading-2.21.0/.gitignore +0 -2
- euler_loading-2.21.0/PKG-INFO +0 -13
- euler_loading-2.21.0/README.md +0 -601
- euler_loading-2.21.0/docs/loader-attributes.md +0 -183
- euler_loading-2.21.0/example.py +0 -82
- euler_loading-2.21.0/gen_loaders.sh +0 -7
- euler_loading-2.21.0/package-lock.json +0 -6
- euler_loading-2.21.0/pyproject.toml +0 -29
- euler_loading-2.21.0/sample_rds.py +0 -30
- euler_loading-2.21.0/vkitti_cpu_example_output.json +0 -30
- euler_loading-2.21.0/vkitti_gpu_example_output.json +0 -30
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/_metadata.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/indexing.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/_annotations.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/_princeton_dense.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/_writer_utils.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/contracts.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/cpu/generic.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/cpu/muses.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/cpu/princeton_dense.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/cpu/real_drive_sim.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/cpu/vkitti2.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/generate/__init__.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/generate/__main__.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/generic.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/gpu/generic.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/gpu/muses.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/gpu/princeton_dense.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/gpu/real_drive_sim.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/gpu/vkitti2.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/muses.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/princeton_dense.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/real_drive_sim.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/euler_loading/loaders/vkitti2.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/__init__.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/conftest.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/example_rds_calib.json +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_dataset.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_id_schema.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_loaders.py +0 -0
- {euler_loading-2.21.0 → euler_loading-2.26.0}/tests/test_python_compat.py +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Byte-compiled / optimized
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# Test / coverage artifacts
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
.coverage.*
|
|
21
|
+
htmlcov/
|
|
22
|
+
coverage.xml
|
|
23
|
+
.tox/
|
|
24
|
+
.nox/
|
|
25
|
+
|
|
26
|
+
# Type checkers / linters
|
|
27
|
+
.mypy_cache/
|
|
28
|
+
.ruff_cache/
|
|
29
|
+
.pytype/
|
|
30
|
+
|
|
31
|
+
# Editors and OS cruft
|
|
32
|
+
.vscode/
|
|
33
|
+
.idea/
|
|
34
|
+
.DS_Store
|
|
35
|
+
|
|
36
|
+
# Local agent / assistant scratch (never part of a release)
|
|
37
|
+
.claude/
|
|
38
|
+
.ao-mcp/
|
|
39
|
+
.ao-provider-auth/
|
|
40
|
+
CLAUDE.md
|
|
41
|
+
TASK.md
|
|
42
|
+
|
|
43
|
+
# uv
|
|
44
|
+
uv.lock
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- Add `read_extrinsics` to the Synscapes loaders, building a 4x4 rigid
|
|
6
|
+
transform from the six `camera.extrinsic` scalars. `transform_direction`
|
|
7
|
+
and `camera_axes` select the pose, its inverse, and vehicle or optical
|
|
8
|
+
camera axes; the assumed `Rz(yaw) @ Ry(pitch) @ Rx(roll)` order is recorded
|
|
9
|
+
in the modality metadata because the dataset does not document it.
|
|
10
|
+
- Add Synscapes writers for every modality, making the loader a
|
|
11
|
+
`DenseDepthCodec`. Depth writes a float32 EXR `Z` channel and needs a
|
|
12
|
+
filesystem path; the intrinsics and extrinsics writers merge into a single
|
|
13
|
+
`meta/<id>.json`, replacing it in one step and keeping its permissions,
|
|
14
|
+
symlink and unmodelled fields rather than truncating it in place.
|
|
15
|
+
- `sky_mask` now honours `meta['sky_class_id']`, or the same key in per-file
|
|
16
|
+
attributes, instead of hardcoding Cityscapes ID 23, so a dataset that
|
|
17
|
+
relabels sky round-trips through `write_sky_mask`.
|
|
18
|
+
- Accept the plural `camera.intrinsics` / `camera.extrinsics` spellings and
|
|
19
|
+
report missing camera fields by name instead of raising `KeyError`.
|
|
20
|
+
|
|
21
|
+
## 2.24.0 (unreleased)
|
|
22
|
+
|
|
23
|
+
Add source-backed capture, strict per-output writers, explicit NPY/PNG encoding, typed calibration views and replay. Consolidate pinhole geometry and correct legacy skew scaling.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## 2.23.0 (source changes; not published)
|
|
27
|
+
|
|
28
|
+
- Reject wrapped decoders during dataset export by checking actual built-in
|
|
29
|
+
function identity. Ordinary callable loading remains supported.
|
|
30
|
+
- Apply boolean thresholds before Pillow dtype conversion, and permit exact
|
|
31
|
+
int32/int64 crop and identity-resize plans while refusing float32 resampling.
|
|
32
|
+
- Add `SamplePreprocessor.export_descriptor`, `MultiModalDataset.export_transform_plan`,
|
|
33
|
+
`SerializableTransform`, and `resolve_transform_descriptor`, paired with contract 0.4.0.
|
|
34
|
+
- Freeze profiles, qualified source/calibration bindings, field policies, operation
|
|
35
|
+
order, and installed CPU backend versions. Infer output profiles and virtual
|
|
36
|
+
calibration geometry without materialization claims.
|
|
37
|
+
- Add explicit Torch/Pillow execution, corrected pinhole skew in the opt-in path,
|
|
38
|
+
validity-aware depth policy, source immutability, and worker validator registration.
|
|
39
|
+
- Cover five-field round trips, projected geometry, ambiguous bindings, unsupported
|
|
40
|
+
semantics, backend choices, schemas, and spawned workers in synthetic tests.
|
|
41
|
+
|
|
42
|
+
Legacy preprocessing and writer behavior remain unchanged. Execution receipts,
|
|
43
|
+
materialized metadata propagation, producer wiring, and GT replay are later work.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daniel Rothenpieler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: euler-loading
|
|
3
|
+
Version: 2.26.0
|
|
4
|
+
Summary: Multi-modal PyTorch dataloader using ds-crawler indices
|
|
5
|
+
Project-URL: Homepage, https://github.com/d-rothen/euler-loading
|
|
6
|
+
Project-URL: Repository, https://github.com/d-rothen/euler-loading
|
|
7
|
+
Project-URL: Issues, https://github.com/d-rothen/euler-loading/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/d-rothen/euler-loading/tree/main/docs
|
|
9
|
+
Author-email: Daniel Rothenpieler <rothenpielerdaniel@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: computer-vision,dataloader,dataset,depth-estimation,multi-modal,pytorch
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Requires-Dist: ds-crawler>=2.11.0
|
|
27
|
+
Requires-Dist: euler-dataset-contract>=0.5.0
|
|
28
|
+
Requires-Dist: numpy
|
|
29
|
+
Requires-Dist: pillow
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: jsonschema>=4.18; extra == 'dev'
|
|
32
|
+
Requires-Dist: openexr>=3.2; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
34
|
+
Provides-Extra: gpu
|
|
35
|
+
Requires-Dist: torch; extra == 'gpu'
|
|
36
|
+
Provides-Extra: synscapes
|
|
37
|
+
Requires-Dist: openexr>=3.2; extra == 'synscapes'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
<!-- euler header — shared across the euler packages.
|
|
41
|
+
Per package, change only: the <h1>, the tagline, and the badge URLs. -->
|
|
42
|
+
<p align="center">
|
|
43
|
+
<img src="https://files.chronodle.com/icons/euler.svg" alt="euler" width="96" height="96">
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<h1 align="center">euler-loading</h1>
|
|
47
|
+
|
|
48
|
+
<p align="center">
|
|
49
|
+
<em>One PyTorch <code>Dataset</code> across arbitrarily many data modalities — matched by ID, not by filename luck.</em>
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<a href="https://pypi.org/project/euler-loading/"><img alt="PyPI" src="https://img.shields.io/pypi/v/euler-loading.svg"></a>
|
|
54
|
+
<a href="https://pypi.org/project/euler-loading/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/euler-loading.svg"></a>
|
|
55
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
56
|
+
<a href="https://github.com/d-rothen/euler-loading/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/d-rothen/euler-loading/actions/workflows/ci.yml/badge.svg"></a>
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
Multi-modal datasets arrive as separate directory trees — RGB here, depth there,
|
|
62
|
+
segmentation in a zip, calibration somewhere above it all. Keeping them in step
|
|
63
|
+
usually means a pile of fragile path arithmetic.
|
|
64
|
+
|
|
65
|
+
euler-loading replaces that. Each modality is indexed by
|
|
66
|
+
[ds-crawler](https://github.com/d-rothen/ds-crawler), and euler-loading
|
|
67
|
+
**intersects the file IDs** across modalities so every sample holds exactly one
|
|
68
|
+
file per modality. Hierarchical files such as per-scene calibration are matched
|
|
69
|
+
by their position in the tree and shared across the samples below them.
|
|
70
|
+
|
|
71
|
+
```mermaid
|
|
72
|
+
flowchart LR
|
|
73
|
+
A["rgb/"] --> X
|
|
74
|
+
B["depth/"] --> X
|
|
75
|
+
C["segmentation.zip"] --> X
|
|
76
|
+
X(["intersect file IDs"]) --> S["sample dict<br/>rgb · depth · segmentation<br/>id · full_id · meta · attributes"]
|
|
77
|
+
D["calib.json<br/><i>hierarchical</i>"] -.->|"matched by tree position"| S
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
It never interprets file contents. It resolves *which* file to load and hands
|
|
81
|
+
the path — or an in-memory buffer, for zip-backed modalities — to a loader
|
|
82
|
+
function, which you supply or let euler-loading resolve from the dataset's
|
|
83
|
+
`dataset-head.json` contract.
|
|
84
|
+
|
|
85
|
+
## Install
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install "euler-loading[gpu]"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Requires Python 3.9+. The `[gpu]` extra pulls in PyTorch for the tensor loaders;
|
|
92
|
+
without it the package still works using the CPU (NumPy) loaders.
|
|
93
|
+
|
|
94
|
+
For Synscapes EXR depth files, install `euler-loading[synscapes]` (NumPy) or
|
|
95
|
+
`euler-loading[gpu,synscapes]` (tensors). See the
|
|
96
|
+
[Synscapes loaders](docs/loaders.md#synscapes--synscapes) for formats and usage.
|
|
97
|
+
|
|
98
|
+
## Quick start
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from euler_loading import Modality, MultiModalDataset
|
|
102
|
+
from euler_loading.loaders.gpu import vkitti2
|
|
103
|
+
|
|
104
|
+
dataset = MultiModalDataset(
|
|
105
|
+
modalities={
|
|
106
|
+
"rgb": Modality("/data/vkitti2/rgb", loader=vkitti2.rgb, split="train"),
|
|
107
|
+
"depth": Modality("/data/vkitti2/depth", loader=vkitti2.depth, split="train"),
|
|
108
|
+
},
|
|
109
|
+
hierarchical_modalities={
|
|
110
|
+
"intrinsics": Modality("/data/vkitti2/textgt", loader=vkitti2.read_intrinsics),
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
sample = dataset[0]
|
|
115
|
+
sample["rgb"] # torch.Tensor (3, H, W) float32 in [0, 1]
|
|
116
|
+
sample["depth"] # torch.Tensor (1, H, W) float32, metres
|
|
117
|
+
sample["intrinsics"] # {file_id: (3, 3) tensor} for every calib file above this sample
|
|
118
|
+
sample["id"] # leaf file ID, shared across modalities
|
|
119
|
+
sample["full_id"] # full hierarchical path, e.g. "/Scene01/Camera_0/00000"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Drop it straight into a `DataLoader` — it is a standard `torch.utils.data.Dataset`:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
loader = DataLoader(dataset, batch_size=16, num_workers=4, pin_memory=True)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Automatic loader resolution
|
|
129
|
+
|
|
130
|
+
Omit `loader=` and euler-loading resolves the loader declared by that
|
|
131
|
+
modality's ds-crawler dataset contract:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
dataset = MultiModalDataset(
|
|
135
|
+
modalities={
|
|
136
|
+
"rgb": Modality("/data/vkitti2/rgb", split="train"),
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The modality root must contain `.ds_crawler/dataset-head.json` (or the scoped
|
|
142
|
+
equivalent) with a named `euler_loading` entry in its `addons` object. A minimal
|
|
143
|
+
RGB contract looks like this:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"contract": {
|
|
148
|
+
"kind": "dataset_head",
|
|
149
|
+
"version": "1.0"
|
|
150
|
+
},
|
|
151
|
+
"dataset": {
|
|
152
|
+
"id": "vkitti2_rgb",
|
|
153
|
+
"name": "Virtual KITTI 2 RGB"
|
|
154
|
+
},
|
|
155
|
+
"modality": {
|
|
156
|
+
"key": "rgb",
|
|
157
|
+
"meta": {
|
|
158
|
+
"range": [0, 255]
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"addons": {
|
|
162
|
+
"euler_loading": {
|
|
163
|
+
"version": "1.0",
|
|
164
|
+
"loader": "vkitti2",
|
|
165
|
+
"function": "rgb"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`loader` selects a built-in loader module and `function` selects the callable
|
|
172
|
+
inside it. Automatic resolution uses the GPU variant; pass a loader explicitly
|
|
173
|
+
when you want the CPU variant or a custom callable. See
|
|
174
|
+
[Automatic loader resolution](docs/loaders.md#automatic-loader-resolution) for
|
|
175
|
+
the full contract and writer rules.
|
|
176
|
+
|
|
177
|
+
## What you get
|
|
178
|
+
|
|
179
|
+
| | |
|
|
180
|
+
|---|---|
|
|
181
|
+
| **ID intersection** | Every sample has exactly one file per modality. Unmatched files are reported, not silently dropped. |
|
|
182
|
+
| **Hierarchical modalities** | Per-scene or per-sequence calibration is matched by tree position and cached, with deepest-file-wins inheritance. |
|
|
183
|
+
| **Zip-native** | Point a modality at a `.zip` and files are read from the archive without extraction. One handle per worker. |
|
|
184
|
+
| **Splits** | `Modality(path, split="train")` overlays a ds-crawler inline split on the canonical index. |
|
|
185
|
+
| **Scoped metadata** | Several logical modalities can share one physical root or archive via `metadata_scope`. |
|
|
186
|
+
| **Loader resolution** | Loaders and writers resolve from the `dataset-head.json` `addons.euler_loading` contract, so datasets describe how to read themselves. |
|
|
187
|
+
| **Writing back** | Resolved writers put inference outputs back in dataset-native formats, re-indexable with matching IDs. |
|
|
188
|
+
| **Spatial preprocessing** | `SamplePreprocessor` resizes and crops consistently across images, depth, masks, ray maps *and* intrinsics. |
|
|
189
|
+
|
|
190
|
+
## Built-in loaders
|
|
191
|
+
|
|
192
|
+
Every dataset module exists in two variants: `loaders.gpu.*` returns
|
|
193
|
+
`torch.Tensor` in CHW layout, `loaders.cpu.*` returns `numpy.ndarray` in HWC.
|
|
194
|
+
All of them accept both filesystem paths and in-memory buffers.
|
|
195
|
+
|
|
196
|
+
| Module | Dataset | Modalities |
|
|
197
|
+
|---|---|---|
|
|
198
|
+
| `vkitti2` | Virtual KITTI 2 | rgb, depth, class/instance segmentation, scene flow, sky mask, intrinsics, extrinsics |
|
|
199
|
+
| `muses` | MUSES | rgb, reference rgb, semantic & panoptic segmentation, sky mask, lidar point cloud, sparse depth, calibration |
|
|
200
|
+
| `real_drive_sim` | Real Drive Sim | rgb, depth, class segmentation, sky mask, calibration, intrinsics, extrinsics |
|
|
201
|
+
| `princeton_dense` | Princeton DENSE / SeeingThroughFog | rgb, rccb, sparse depth, intrinsics, extrinsics |
|
|
202
|
+
| `generic_dense_depth` | *any* — inferred from file extension | rgb, depth, sky mask, intrinsics |
|
|
203
|
+
| `generic` | *any* — `.npy` / `.npz` modalities | points 3d, maps, segmentation, spherical maps, SH coefficients, … |
|
|
204
|
+
|
|
205
|
+
Full inventory with shapes, dtypes and units: [docs/loaders.md](docs/loaders.md).
|
|
206
|
+
The machine-readable version is
|
|
207
|
+
[`loaders.json`](euler_loading/loaders/generate/loaders.json).
|
|
208
|
+
|
|
209
|
+
## Documentation
|
|
210
|
+
|
|
211
|
+
- [Serializable resize/crop plans](docs/transform-descriptors.md): Phase 1 export,
|
|
212
|
+
explicit backend and calibration bindings, resolution, and output profiles.
|
|
213
|
+
|
|
214
|
+
| Guide | Covers |
|
|
215
|
+
|---|---|
|
|
216
|
+
| [Dataset & modalities](docs/dataset.md) | `Modality` and `MultiModalDataset` reference, the sample dict, splits, scoped metadata, zip archives, layout-aware loading |
|
|
217
|
+
| [Loaders & writers](docs/loaders.md) | The loader contract, automatic resolution, per-file attributes, the full built-in inventory |
|
|
218
|
+
| [Preprocessing & transforms](docs/preprocessing.md) | Cross-modal transforms, `SamplePreprocessor`, calibration-aware resize and crop |
|
|
219
|
+
| [Writing outputs](docs/writing.md) | Writing predictions back in dataset-native formats and re-indexing them |
|
|
220
|
+
| [Examples](examples/) | Runnable scripts against real datasets |
|
|
221
|
+
|
|
222
|
+
## Development
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
git clone https://github.com/d-rothen/euler-loading.git
|
|
226
|
+
cd euler-loading
|
|
227
|
+
pip install -e ".[gpu,dev]"
|
|
228
|
+
pytest
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the loader-authoring workflow and
|
|
232
|
+
release process.
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
[MIT](LICENSE) © Daniel Rothenpieler
|
|
237
|
+
|
|
238
|
+
See [Phase 2 materialization](docs/materialization.md) for the opt-in captured spatial workflow (2.24.0, unreleased).
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
<!-- euler header — shared across the euler packages.
|
|
2
|
+
Per package, change only: the <h1>, the tagline, and the badge URLs. -->
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://files.chronodle.com/icons/euler.svg" alt="euler" width="96" height="96">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">euler-loading</h1>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<em>One PyTorch <code>Dataset</code> across arbitrarily many data modalities — matched by ID, not by filename luck.</em>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://pypi.org/project/euler-loading/"><img alt="PyPI" src="https://img.shields.io/pypi/v/euler-loading.svg"></a>
|
|
15
|
+
<a href="https://pypi.org/project/euler-loading/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/euler-loading.svg"></a>
|
|
16
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
17
|
+
<a href="https://github.com/d-rothen/euler-loading/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/d-rothen/euler-loading/actions/workflows/ci.yml/badge.svg"></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
Multi-modal datasets arrive as separate directory trees — RGB here, depth there,
|
|
23
|
+
segmentation in a zip, calibration somewhere above it all. Keeping them in step
|
|
24
|
+
usually means a pile of fragile path arithmetic.
|
|
25
|
+
|
|
26
|
+
euler-loading replaces that. Each modality is indexed by
|
|
27
|
+
[ds-crawler](https://github.com/d-rothen/ds-crawler), and euler-loading
|
|
28
|
+
**intersects the file IDs** across modalities so every sample holds exactly one
|
|
29
|
+
file per modality. Hierarchical files such as per-scene calibration are matched
|
|
30
|
+
by their position in the tree and shared across the samples below them.
|
|
31
|
+
|
|
32
|
+
```mermaid
|
|
33
|
+
flowchart LR
|
|
34
|
+
A["rgb/"] --> X
|
|
35
|
+
B["depth/"] --> X
|
|
36
|
+
C["segmentation.zip"] --> X
|
|
37
|
+
X(["intersect file IDs"]) --> S["sample dict<br/>rgb · depth · segmentation<br/>id · full_id · meta · attributes"]
|
|
38
|
+
D["calib.json<br/><i>hierarchical</i>"] -.->|"matched by tree position"| S
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
It never interprets file contents. It resolves *which* file to load and hands
|
|
42
|
+
the path — or an in-memory buffer, for zip-backed modalities — to a loader
|
|
43
|
+
function, which you supply or let euler-loading resolve from the dataset's
|
|
44
|
+
`dataset-head.json` contract.
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install "euler-loading[gpu]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Requires Python 3.9+. The `[gpu]` extra pulls in PyTorch for the tensor loaders;
|
|
53
|
+
without it the package still works using the CPU (NumPy) loaders.
|
|
54
|
+
|
|
55
|
+
For Synscapes EXR depth files, install `euler-loading[synscapes]` (NumPy) or
|
|
56
|
+
`euler-loading[gpu,synscapes]` (tensors). See the
|
|
57
|
+
[Synscapes loaders](docs/loaders.md#synscapes--synscapes) for formats and usage.
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from euler_loading import Modality, MultiModalDataset
|
|
63
|
+
from euler_loading.loaders.gpu import vkitti2
|
|
64
|
+
|
|
65
|
+
dataset = MultiModalDataset(
|
|
66
|
+
modalities={
|
|
67
|
+
"rgb": Modality("/data/vkitti2/rgb", loader=vkitti2.rgb, split="train"),
|
|
68
|
+
"depth": Modality("/data/vkitti2/depth", loader=vkitti2.depth, split="train"),
|
|
69
|
+
},
|
|
70
|
+
hierarchical_modalities={
|
|
71
|
+
"intrinsics": Modality("/data/vkitti2/textgt", loader=vkitti2.read_intrinsics),
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
sample = dataset[0]
|
|
76
|
+
sample["rgb"] # torch.Tensor (3, H, W) float32 in [0, 1]
|
|
77
|
+
sample["depth"] # torch.Tensor (1, H, W) float32, metres
|
|
78
|
+
sample["intrinsics"] # {file_id: (3, 3) tensor} for every calib file above this sample
|
|
79
|
+
sample["id"] # leaf file ID, shared across modalities
|
|
80
|
+
sample["full_id"] # full hierarchical path, e.g. "/Scene01/Camera_0/00000"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Drop it straight into a `DataLoader` — it is a standard `torch.utils.data.Dataset`:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
loader = DataLoader(dataset, batch_size=16, num_workers=4, pin_memory=True)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Automatic loader resolution
|
|
90
|
+
|
|
91
|
+
Omit `loader=` and euler-loading resolves the loader declared by that
|
|
92
|
+
modality's ds-crawler dataset contract:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
dataset = MultiModalDataset(
|
|
96
|
+
modalities={
|
|
97
|
+
"rgb": Modality("/data/vkitti2/rgb", split="train"),
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The modality root must contain `.ds_crawler/dataset-head.json` (or the scoped
|
|
103
|
+
equivalent) with a named `euler_loading` entry in its `addons` object. A minimal
|
|
104
|
+
RGB contract looks like this:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"contract": {
|
|
109
|
+
"kind": "dataset_head",
|
|
110
|
+
"version": "1.0"
|
|
111
|
+
},
|
|
112
|
+
"dataset": {
|
|
113
|
+
"id": "vkitti2_rgb",
|
|
114
|
+
"name": "Virtual KITTI 2 RGB"
|
|
115
|
+
},
|
|
116
|
+
"modality": {
|
|
117
|
+
"key": "rgb",
|
|
118
|
+
"meta": {
|
|
119
|
+
"range": [0, 255]
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"addons": {
|
|
123
|
+
"euler_loading": {
|
|
124
|
+
"version": "1.0",
|
|
125
|
+
"loader": "vkitti2",
|
|
126
|
+
"function": "rgb"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`loader` selects a built-in loader module and `function` selects the callable
|
|
133
|
+
inside it. Automatic resolution uses the GPU variant; pass a loader explicitly
|
|
134
|
+
when you want the CPU variant or a custom callable. See
|
|
135
|
+
[Automatic loader resolution](docs/loaders.md#automatic-loader-resolution) for
|
|
136
|
+
the full contract and writer rules.
|
|
137
|
+
|
|
138
|
+
## What you get
|
|
139
|
+
|
|
140
|
+
| | |
|
|
141
|
+
|---|---|
|
|
142
|
+
| **ID intersection** | Every sample has exactly one file per modality. Unmatched files are reported, not silently dropped. |
|
|
143
|
+
| **Hierarchical modalities** | Per-scene or per-sequence calibration is matched by tree position and cached, with deepest-file-wins inheritance. |
|
|
144
|
+
| **Zip-native** | Point a modality at a `.zip` and files are read from the archive without extraction. One handle per worker. |
|
|
145
|
+
| **Splits** | `Modality(path, split="train")` overlays a ds-crawler inline split on the canonical index. |
|
|
146
|
+
| **Scoped metadata** | Several logical modalities can share one physical root or archive via `metadata_scope`. |
|
|
147
|
+
| **Loader resolution** | Loaders and writers resolve from the `dataset-head.json` `addons.euler_loading` contract, so datasets describe how to read themselves. |
|
|
148
|
+
| **Writing back** | Resolved writers put inference outputs back in dataset-native formats, re-indexable with matching IDs. |
|
|
149
|
+
| **Spatial preprocessing** | `SamplePreprocessor` resizes and crops consistently across images, depth, masks, ray maps *and* intrinsics. |
|
|
150
|
+
|
|
151
|
+
## Built-in loaders
|
|
152
|
+
|
|
153
|
+
Every dataset module exists in two variants: `loaders.gpu.*` returns
|
|
154
|
+
`torch.Tensor` in CHW layout, `loaders.cpu.*` returns `numpy.ndarray` in HWC.
|
|
155
|
+
All of them accept both filesystem paths and in-memory buffers.
|
|
156
|
+
|
|
157
|
+
| Module | Dataset | Modalities |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `vkitti2` | Virtual KITTI 2 | rgb, depth, class/instance segmentation, scene flow, sky mask, intrinsics, extrinsics |
|
|
160
|
+
| `muses` | MUSES | rgb, reference rgb, semantic & panoptic segmentation, sky mask, lidar point cloud, sparse depth, calibration |
|
|
161
|
+
| `real_drive_sim` | Real Drive Sim | rgb, depth, class segmentation, sky mask, calibration, intrinsics, extrinsics |
|
|
162
|
+
| `princeton_dense` | Princeton DENSE / SeeingThroughFog | rgb, rccb, sparse depth, intrinsics, extrinsics |
|
|
163
|
+
| `generic_dense_depth` | *any* — inferred from file extension | rgb, depth, sky mask, intrinsics |
|
|
164
|
+
| `generic` | *any* — `.npy` / `.npz` modalities | points 3d, maps, segmentation, spherical maps, SH coefficients, … |
|
|
165
|
+
|
|
166
|
+
Full inventory with shapes, dtypes and units: [docs/loaders.md](docs/loaders.md).
|
|
167
|
+
The machine-readable version is
|
|
168
|
+
[`loaders.json`](euler_loading/loaders/generate/loaders.json).
|
|
169
|
+
|
|
170
|
+
## Documentation
|
|
171
|
+
|
|
172
|
+
- [Serializable resize/crop plans](docs/transform-descriptors.md): Phase 1 export,
|
|
173
|
+
explicit backend and calibration bindings, resolution, and output profiles.
|
|
174
|
+
|
|
175
|
+
| Guide | Covers |
|
|
176
|
+
|---|---|
|
|
177
|
+
| [Dataset & modalities](docs/dataset.md) | `Modality` and `MultiModalDataset` reference, the sample dict, splits, scoped metadata, zip archives, layout-aware loading |
|
|
178
|
+
| [Loaders & writers](docs/loaders.md) | The loader contract, automatic resolution, per-file attributes, the full built-in inventory |
|
|
179
|
+
| [Preprocessing & transforms](docs/preprocessing.md) | Cross-modal transforms, `SamplePreprocessor`, calibration-aware resize and crop |
|
|
180
|
+
| [Writing outputs](docs/writing.md) | Writing predictions back in dataset-native formats and re-indexing them |
|
|
181
|
+
| [Examples](examples/) | Runnable scripts against real datasets |
|
|
182
|
+
|
|
183
|
+
## Development
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
git clone https://github.com/d-rothen/euler-loading.git
|
|
187
|
+
cd euler-loading
|
|
188
|
+
pip install -e ".[gpu,dev]"
|
|
189
|
+
pytest
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the loader-authoring workflow and
|
|
193
|
+
release process.
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
[MIT](LICENSE) © Daniel Rothenpieler
|
|
198
|
+
|
|
199
|
+
See [Phase 2 materialization](docs/materialization.md) for the opt-in captured spatial workflow (2.24.0, unreleased).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# euler-loading documentation
|
|
2
|
+
|
|
3
|
+
| Guide | Covers |
|
|
4
|
+
|---|---|
|
|
5
|
+
| [Dataset & modalities](dataset.md) | `Modality` and `MultiModalDataset` reference, the sample dict, hierarchical modalities, splits, scoped metadata, zip archives, layout-aware loading |
|
|
6
|
+
| [Loaders & writers](loaders.md) | The loader contract, per-file attributes, automatic resolution, protocols, and the full built-in loader inventory |
|
|
7
|
+
| [Preprocessing & transforms](preprocessing.md) | Cross-modal transforms, `SamplePreprocessor`, field kinds, calibration-aware resize and crop |
|
|
8
|
+
| [Writing outputs](writing.md) | Writing predictions back in dataset-native formats and re-indexing them |
|
|
9
|
+
|
|
10
|
+
Runnable scripts live in [`examples/`](../examples/). Contributor-facing notes —
|
|
11
|
+
adding a loader, running tests, cutting a release — are in
|
|
12
|
+
[CONTRIBUTING.md](../CONTRIBUTING.md).
|
|
13
|
+
|
|
14
|
+
## Concepts in one page
|
|
15
|
+
|
|
16
|
+
**ds-crawler indexes, euler-loading joins.** Each modality root carries its own
|
|
17
|
+
[ds-crawler](https://github.com/d-rothen/ds-crawler) index describing the files
|
|
18
|
+
it contains and the hierarchy they sit in. euler-loading reads those indexes and
|
|
19
|
+
intersects file IDs so every sample holds one file per modality.
|
|
20
|
+
|
|
21
|
+
**Regular vs hierarchical modalities.** Regular modalities participate in the ID
|
|
22
|
+
intersection — one file each, per sample. Hierarchical modalities do not; their
|
|
23
|
+
files are matched by tree position, so a per-scene calibration file is shared by
|
|
24
|
+
every sample beneath it.
|
|
25
|
+
|
|
26
|
+
**Loaders own all file semantics.** euler-loading never interprets file
|
|
27
|
+
contents. It resolves which file to read and passes a path — or an in-memory
|
|
28
|
+
buffer, for zip-backed modalities — to a loader function.
|
|
29
|
+
|
|
30
|
+
**The dataset-head contract drives resolution.** Each modality can declare an
|
|
31
|
+
`addons.euler_loading` entry in `.ds_crawler/dataset-head.json`. Its `loader`
|
|
32
|
+
and `function` fields select the built-in reader, while the same addon can
|
|
33
|
+
describe writer choice, modality roles and logging slots. See
|
|
34
|
+
[Automatic loader resolution](loaders.md#automatic-loader-resolution).
|