euler-loading 2.8.0__tar.gz → 2.9.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.8.0 → euler_loading-2.9.0}/PKG-INFO +1 -1
- {euler_loading-2.8.0 → euler_loading-2.9.0}/README.md +14 -2
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/_resolution.py +1 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/__init__.py +4 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/cpu/__init__.py +2 -0
- euler_loading-2.9.0/euler_loading/loaders/cpu/muses.py +180 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/generate/loaders.json +169 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/gpu/__init__.py +2 -0
- euler_loading-2.9.0/euler_loading/loaders/gpu/muses.py +186 -0
- euler_loading-2.9.0/euler_loading/loaders/muses.py +12 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/package-lock.json +1 -1
- {euler_loading-2.8.0 → euler_loading-2.9.0}/pyproject.toml +1 -1
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/test_loaders.py +229 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/.github/workflows/workflow.yml +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/.gitignore +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/docs/loader-attributes.md +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/__init__.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/_dataset_contract.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/_ds_crawler_utils.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/_metadata.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/_writing.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/dataset.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/indexing.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/_annotations.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/_writer_utils.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/contracts.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/cpu/generic.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/cpu/generic_dense_depth.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/cpu/real_drive_sim.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/cpu/vkitti2.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/generate/__init__.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/generate/__main__.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/generic.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/gpu/generic.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/gpu/generic_dense_depth.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/gpu/real_drive_sim.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/gpu/vkitti2.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/real_drive_sim.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/vkitti2.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/preprocessing.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/example.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/sample_rds.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/__init__.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/conftest.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/example_rds_calib.json +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/test_dataset.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/test_id_schema.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/test_indexing.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/test_preprocessing.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/test_real_dataset.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/tests/test_writing.py +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/vkitti_cpu_example_output.json +0 -0
- {euler_loading-2.8.0 → euler_loading-2.9.0}/vkitti_gpu_example_output.json +0 -0
|
@@ -309,7 +309,7 @@ When `Modality.loader` is `None`, euler-loading resolves the loader from the ds-
|
|
|
309
309
|
}
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
-
`loader` is the module name (`vkitti2`, `real_drive_sim`, or `generic_dense_depth`) and `function` is the function within that module. The GPU variant is used by default.
|
|
312
|
+
`loader` is the module name (`vkitti2`, `real_drive_sim`, `muses`, or `generic_dense_depth`) and `function` is the function within that module. The GPU variant is used by default.
|
|
313
313
|
|
|
314
314
|
Writer resolution uses the same module and function metadata:
|
|
315
315
|
|
|
@@ -439,6 +439,18 @@ All built-in loaders accept both filesystem paths (`str`) and in-memory buffers
|
|
|
439
439
|
| `sky_mask` | Binary mask where class ID == 29 (sky) |
|
|
440
440
|
| `calibration` | Per-sensor calibration from JSON: returns `dict[sensor_name, {"K": (3,3), "T": (4,4), "distortion": (8,)}]` (use with `hierarchical_modalities`) |
|
|
441
441
|
|
|
442
|
+
### MUSES (`euler_loading.loaders.muses`)
|
|
443
|
+
|
|
444
|
+
| Function | Description |
|
|
445
|
+
|----------|-------------|
|
|
446
|
+
| `rgb` | Frame-camera RGB image as float32, normalised to [0, 1] |
|
|
447
|
+
| `reference_rgb` | Clear-weather reference RGB image as float32, normalised to [0, 1] |
|
|
448
|
+
| `semantic_segmentation` | Single-channel Cityscapes `labelIds` or `labelTrainIds` PNG as class IDs |
|
|
449
|
+
| `semantic_segmentation_color` | Cityscapes `labelColor` PNG as RGB uint8 labels |
|
|
450
|
+
| `panoptic_segmentation` | COCO-style RGB panoptic PNG decoded to integer segment IDs |
|
|
451
|
+
| `lidar_point_cloud` / `point_cloud` | Lidar `.bin` file as `(N, 6)` float64: `x, y, z, intensity, ring, timestamp` |
|
|
452
|
+
| `sparse_depth` | Alias for MUSES lidar points for sparse-depth style workflows |
|
|
453
|
+
|
|
442
454
|
### Generic Dense Depth (`euler_loading.loaders.gpu.generic_dense_depth`)
|
|
443
455
|
|
|
444
456
|
A format-agnostic loader that infers the loading strategy from the file extension. Useful for datasets that don't have a dedicated loader module.
|
|
@@ -450,7 +462,7 @@ A format-agnostic loader that infers the loading strategy from the file extensio
|
|
|
450
462
|
| `sky_mask` | Binary mask by comparing pixels against `meta["sky_mask"]` (`[R, G, B]`). Requires `meta` |
|
|
451
463
|
| `read_intrinsics` | Returns `meta["intrinsics"]` as a `(3, 3)` tensor. Ignores path; requires `meta` |
|
|
452
464
|
|
|
453
|
-
CPU variants of all loaders live under `euler_loading.loaders.cpu.{vkitti2,real_drive_sim,generic_dense_depth}`.
|
|
465
|
+
CPU variants of all loaders live under `euler_loading.loaders.cpu.{vkitti2,real_drive_sim,muses,generic_dense_depth}`.
|
|
454
466
|
|
|
455
467
|
### Flattening hierarchical modalities
|
|
456
468
|
|
|
@@ -23,6 +23,7 @@ _LOADER_MODULES: dict[str, str] = {
|
|
|
23
23
|
"real_drive_sim": "euler_loading.loaders.gpu.real_drive_sim",
|
|
24
24
|
"generic_dense_depth": "euler_loading.loaders.gpu.generic_dense_depth",
|
|
25
25
|
"generic": "euler_loading.loaders.gpu.generic",
|
|
26
|
+
"muses": "euler_loading.loaders.gpu.muses",
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
|
|
@@ -23,4 +23,8 @@ Available submodules:
|
|
|
23
23
|
|
|
24
24
|
- :mod:`euler_loading.loaders.gpu.vkitti2` — Virtual KITTI 2 (torch)
|
|
25
25
|
- :mod:`euler_loading.loaders.cpu.vkitti2` — Virtual KITTI 2 (numpy)
|
|
26
|
+
- :mod:`euler_loading.loaders.gpu.real_drive_sim` — Real Drive Sim (torch)
|
|
27
|
+
- :mod:`euler_loading.loaders.cpu.real_drive_sim` — Real Drive Sim (numpy)
|
|
28
|
+
- :mod:`euler_loading.loaders.gpu.muses` — MUSES (torch)
|
|
29
|
+
- :mod:`euler_loading.loaders.cpu.muses` — MUSES (numpy)
|
|
26
30
|
"""
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""CPU-oriented loader functions for the MUSES dataset.
|
|
2
|
+
|
|
3
|
+
MUSES stores RGB camera frames, reference frames, semantic labels, panoptic
|
|
4
|
+
labels, and lidar point clouds in separate modality folders. These loaders
|
|
5
|
+
return NumPy arrays for CPU-based processing.
|
|
6
|
+
|
|
7
|
+
Return types
|
|
8
|
+
------------
|
|
9
|
+
- **rgb** / **reference_rgb** -- ``np.ndarray`` of shape ``(H, W, 3)``
|
|
10
|
+
float32 in ``[0, 1]``.
|
|
11
|
+
- **semantic_segmentation** -- ``np.ndarray`` of shape ``(H, W)`` int64
|
|
12
|
+
containing raw Cityscapes ``labelIds`` or ``labelTrainIds``.
|
|
13
|
+
- **semantic_segmentation_color** -- ``np.ndarray`` of shape ``(H, W, 3)``
|
|
14
|
+
uint8 containing Cityscapes RGB colours.
|
|
15
|
+
- **panoptic_segmentation** -- ``np.ndarray`` of shape ``(H, W)`` int64
|
|
16
|
+
containing COCO-style panoptic segment IDs decoded from RGB.
|
|
17
|
+
- **lidar_point_cloud** / **sparse_depth** -- ``np.ndarray`` of shape
|
|
18
|
+
``(N, 6)`` float64 with columns ``x, y, z, intensity, ring, timestamp``.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
from typing import Any, BinaryIO, Union
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
from PIL import Image
|
|
28
|
+
|
|
29
|
+
from euler_loading.loaders._annotations import modality_meta
|
|
30
|
+
|
|
31
|
+
_LIDAR_COLUMNS = ["x", "y", "z", "intensity", "ring", "timestamp"]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _load_image_rgb(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
35
|
+
"""Load an image file as ``(H, W, 3)`` float32 in ``[0, 1]``."""
|
|
36
|
+
with Image.open(path) as image:
|
|
37
|
+
return np.array(image.convert("RGB"), dtype=np.float32) / 255.0
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _load_single_channel_labels(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
41
|
+
"""Load a single-channel semantic label image as int64."""
|
|
42
|
+
with Image.open(path) as image:
|
|
43
|
+
arr = np.array(image, dtype=np.int64)
|
|
44
|
+
if arr.ndim != 2:
|
|
45
|
+
raise ValueError(
|
|
46
|
+
"MUSES semantic_segmentation expects a single-channel labelIds "
|
|
47
|
+
"or labelTrainIds PNG. Use semantic_segmentation_color for "
|
|
48
|
+
"labelColor PNG files."
|
|
49
|
+
)
|
|
50
|
+
return arr
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _load_rgb_uint8(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
54
|
+
"""Load an RGB image without normalisation."""
|
|
55
|
+
with Image.open(path) as image:
|
|
56
|
+
return np.array(image.convert("RGB"), dtype=np.uint8)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _decode_panoptic_rgb(rgb: np.ndarray) -> np.ndarray:
|
|
60
|
+
"""Decode COCO-style RGB panoptic IDs as ``R + 256*G + 256^2*B``."""
|
|
61
|
+
values = rgb.astype(np.int64)
|
|
62
|
+
return values[:, :, 0] + 256 * values[:, :, 1] + 65536 * values[:, :, 2]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _load_lidar_array(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
66
|
+
"""Load a MUSES lidar ``.bin`` file as an ``(N, 6)`` float64 array."""
|
|
67
|
+
if isinstance(path, (str, os.PathLike)):
|
|
68
|
+
arr = np.fromfile(path, dtype=np.float64)
|
|
69
|
+
else:
|
|
70
|
+
arr = np.frombuffer(path.read(), dtype=np.float64).copy()
|
|
71
|
+
|
|
72
|
+
if arr.size % 6 != 0:
|
|
73
|
+
name = getattr(path, "name", path)
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"MUSES lidar file {name!r} contains {arr.size} float64 values, "
|
|
76
|
+
"which is not divisible by 6."
|
|
77
|
+
)
|
|
78
|
+
return arr.reshape((-1, 6))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@modality_meta(
|
|
82
|
+
modality_type="rgb",
|
|
83
|
+
dtype="float32",
|
|
84
|
+
shape="HWC",
|
|
85
|
+
file_formats=[".png"],
|
|
86
|
+
output_range=[0.0, 1.0],
|
|
87
|
+
)
|
|
88
|
+
def rgb(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
89
|
+
"""Load a MUSES frame-camera RGB image as float32 in ``[0, 1]``."""
|
|
90
|
+
return _load_image_rgb(path)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@modality_meta(
|
|
94
|
+
modality_type="rgb",
|
|
95
|
+
dtype="float32",
|
|
96
|
+
shape="HWC",
|
|
97
|
+
file_formats=[".png"],
|
|
98
|
+
output_range=[0.0, 1.0],
|
|
99
|
+
meta={"source": "reference_frames"},
|
|
100
|
+
)
|
|
101
|
+
def reference_rgb(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
102
|
+
"""Load a MUSES clear-weather reference RGB image as float32 in ``[0, 1]``."""
|
|
103
|
+
return _load_image_rgb(path)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@modality_meta(
|
|
107
|
+
modality_type="semantic_segmentation",
|
|
108
|
+
dtype="int64",
|
|
109
|
+
shape="HW",
|
|
110
|
+
file_formats=[".png"],
|
|
111
|
+
meta={
|
|
112
|
+
"encoding": "single_channel",
|
|
113
|
+
"supported_suffixes": ["labelIds", "labelTrainIds"],
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
def semantic_segmentation(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
117
|
+
"""Load MUSES ``labelIds`` or ``labelTrainIds`` semantic labels."""
|
|
118
|
+
return _load_single_channel_labels(path)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@modality_meta(
|
|
122
|
+
modality_type="semantic_segmentation_color",
|
|
123
|
+
dtype="uint8",
|
|
124
|
+
shape="HWC",
|
|
125
|
+
file_formats=[".png"],
|
|
126
|
+
meta={"encoding": "rgb", "supported_suffixes": ["labelColor"]},
|
|
127
|
+
)
|
|
128
|
+
def semantic_segmentation_color(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
129
|
+
"""Load MUSES ``labelColor`` semantic labels as RGB uint8 values."""
|
|
130
|
+
return _load_rgb_uint8(path)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@modality_meta(
|
|
134
|
+
modality_type="panoptic_segmentation",
|
|
135
|
+
dtype="int64",
|
|
136
|
+
shape="HW",
|
|
137
|
+
file_formats=[".png"],
|
|
138
|
+
meta={"encoding": "coco_rgb_id"},
|
|
139
|
+
)
|
|
140
|
+
def panoptic_segmentation(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
141
|
+
"""Load a MUSES panoptic PNG as an integer segment-ID map."""
|
|
142
|
+
return _decode_panoptic_rgb(_load_rgb_uint8(path))
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@modality_meta(
|
|
146
|
+
modality_type="point_cloud",
|
|
147
|
+
dtype="float64",
|
|
148
|
+
shape="NC",
|
|
149
|
+
file_formats=[".bin"],
|
|
150
|
+
meta={
|
|
151
|
+
"columns": _LIDAR_COLUMNS,
|
|
152
|
+
"coordinate_unit": "meters",
|
|
153
|
+
"timestamp_unit": "seconds",
|
|
154
|
+
},
|
|
155
|
+
)
|
|
156
|
+
def lidar_point_cloud(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
157
|
+
"""Load a MUSES lidar point cloud as ``(N, 6)`` float64."""
|
|
158
|
+
return _load_lidar_array(path)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def point_cloud(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
162
|
+
"""Alias for :func:`lidar_point_cloud`."""
|
|
163
|
+
return _load_lidar_array(path)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@modality_meta(
|
|
167
|
+
modality_type="sparse_depth",
|
|
168
|
+
dtype="float64",
|
|
169
|
+
shape="NC",
|
|
170
|
+
file_formats=[".bin"],
|
|
171
|
+
meta={
|
|
172
|
+
"representation": "point_cloud",
|
|
173
|
+
"columns": _LIDAR_COLUMNS,
|
|
174
|
+
"coordinate_unit": "meters",
|
|
175
|
+
"timestamp_unit": "seconds",
|
|
176
|
+
},
|
|
177
|
+
)
|
|
178
|
+
def sparse_depth(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
179
|
+
"""Load MUSES lidar points for sparse-depth style workflows."""
|
|
180
|
+
return _load_lidar_array(path)
|
|
@@ -219,6 +219,175 @@
|
|
|
219
219
|
}
|
|
220
220
|
]
|
|
221
221
|
},
|
|
222
|
+
{
|
|
223
|
+
"name": "muses",
|
|
224
|
+
"modalities": [
|
|
225
|
+
{
|
|
226
|
+
"type": "point_cloud",
|
|
227
|
+
"function": "lidar_point_cloud",
|
|
228
|
+
"hierarchical": false,
|
|
229
|
+
"dtype": "float64",
|
|
230
|
+
"access": "key",
|
|
231
|
+
"file_formats": [
|
|
232
|
+
".bin"
|
|
233
|
+
],
|
|
234
|
+
"meta": {
|
|
235
|
+
"columns": [
|
|
236
|
+
"x",
|
|
237
|
+
"y",
|
|
238
|
+
"z",
|
|
239
|
+
"intensity",
|
|
240
|
+
"ring",
|
|
241
|
+
"timestamp"
|
|
242
|
+
],
|
|
243
|
+
"coordinate_unit": "meters",
|
|
244
|
+
"timestamp_unit": "seconds"
|
|
245
|
+
},
|
|
246
|
+
"cpu": {
|
|
247
|
+
"shape": "NC"
|
|
248
|
+
},
|
|
249
|
+
"gpu": {
|
|
250
|
+
"shape": "NC"
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"type": "panoptic_segmentation",
|
|
255
|
+
"function": "panoptic_segmentation",
|
|
256
|
+
"hierarchical": false,
|
|
257
|
+
"dtype": "int64",
|
|
258
|
+
"access": "key",
|
|
259
|
+
"file_formats": [
|
|
260
|
+
".png"
|
|
261
|
+
],
|
|
262
|
+
"meta": {
|
|
263
|
+
"encoding": "coco_rgb_id"
|
|
264
|
+
},
|
|
265
|
+
"cpu": {
|
|
266
|
+
"shape": "HW"
|
|
267
|
+
},
|
|
268
|
+
"gpu": {
|
|
269
|
+
"shape": "1HW"
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"type": "rgb",
|
|
274
|
+
"function": "reference_rgb",
|
|
275
|
+
"hierarchical": false,
|
|
276
|
+
"dtype": "float32",
|
|
277
|
+
"access": "key",
|
|
278
|
+
"output_range": [
|
|
279
|
+
0.0,
|
|
280
|
+
1.0
|
|
281
|
+
],
|
|
282
|
+
"file_formats": [
|
|
283
|
+
".png"
|
|
284
|
+
],
|
|
285
|
+
"meta": {
|
|
286
|
+
"source": "reference_frames"
|
|
287
|
+
},
|
|
288
|
+
"cpu": {
|
|
289
|
+
"shape": "HWC"
|
|
290
|
+
},
|
|
291
|
+
"gpu": {
|
|
292
|
+
"shape": "CHW"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"type": "rgb",
|
|
297
|
+
"function": "rgb",
|
|
298
|
+
"hierarchical": false,
|
|
299
|
+
"dtype": "float32",
|
|
300
|
+
"access": "key",
|
|
301
|
+
"output_range": [
|
|
302
|
+
0.0,
|
|
303
|
+
1.0
|
|
304
|
+
],
|
|
305
|
+
"file_formats": [
|
|
306
|
+
".png"
|
|
307
|
+
],
|
|
308
|
+
"cpu": {
|
|
309
|
+
"shape": "HWC"
|
|
310
|
+
},
|
|
311
|
+
"gpu": {
|
|
312
|
+
"shape": "CHW"
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"type": "semantic_segmentation",
|
|
317
|
+
"function": "semantic_segmentation",
|
|
318
|
+
"hierarchical": false,
|
|
319
|
+
"dtype": "int64",
|
|
320
|
+
"access": "key",
|
|
321
|
+
"file_formats": [
|
|
322
|
+
".png"
|
|
323
|
+
],
|
|
324
|
+
"meta": {
|
|
325
|
+
"encoding": "single_channel",
|
|
326
|
+
"supported_suffixes": [
|
|
327
|
+
"labelIds",
|
|
328
|
+
"labelTrainIds"
|
|
329
|
+
]
|
|
330
|
+
},
|
|
331
|
+
"cpu": {
|
|
332
|
+
"shape": "HW"
|
|
333
|
+
},
|
|
334
|
+
"gpu": {
|
|
335
|
+
"shape": "1HW"
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"type": "semantic_segmentation_color",
|
|
340
|
+
"function": "semantic_segmentation_color",
|
|
341
|
+
"hierarchical": false,
|
|
342
|
+
"dtype": "uint8",
|
|
343
|
+
"access": "key",
|
|
344
|
+
"file_formats": [
|
|
345
|
+
".png"
|
|
346
|
+
],
|
|
347
|
+
"meta": {
|
|
348
|
+
"encoding": "rgb",
|
|
349
|
+
"supported_suffixes": [
|
|
350
|
+
"labelColor"
|
|
351
|
+
]
|
|
352
|
+
},
|
|
353
|
+
"cpu": {
|
|
354
|
+
"shape": "HWC"
|
|
355
|
+
},
|
|
356
|
+
"gpu": {
|
|
357
|
+
"shape": "CHW"
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"type": "sparse_depth",
|
|
362
|
+
"function": "sparse_depth",
|
|
363
|
+
"hierarchical": false,
|
|
364
|
+
"dtype": "float64",
|
|
365
|
+
"access": "key",
|
|
366
|
+
"file_formats": [
|
|
367
|
+
".bin"
|
|
368
|
+
],
|
|
369
|
+
"meta": {
|
|
370
|
+
"representation": "point_cloud",
|
|
371
|
+
"columns": [
|
|
372
|
+
"x",
|
|
373
|
+
"y",
|
|
374
|
+
"z",
|
|
375
|
+
"intensity",
|
|
376
|
+
"ring",
|
|
377
|
+
"timestamp"
|
|
378
|
+
],
|
|
379
|
+
"coordinate_unit": "meters",
|
|
380
|
+
"timestamp_unit": "seconds"
|
|
381
|
+
},
|
|
382
|
+
"cpu": {
|
|
383
|
+
"shape": "NC"
|
|
384
|
+
},
|
|
385
|
+
"gpu": {
|
|
386
|
+
"shape": "NC"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
]
|
|
390
|
+
},
|
|
222
391
|
{
|
|
223
392
|
"name": "real_drive_sim",
|
|
224
393
|
"modalities": [
|
|
@@ -7,4 +7,6 @@ All loaders return **torch tensors** suitable for direct GPU-based training.
|
|
|
7
7
|
Available submodules:
|
|
8
8
|
|
|
9
9
|
- :mod:`euler_loading.loaders.gpu.vkitti2` — Virtual KITTI 2
|
|
10
|
+
- :mod:`euler_loading.loaders.gpu.real_drive_sim` — Real Drive Sim
|
|
11
|
+
- :mod:`euler_loading.loaders.gpu.muses` — MUSES
|
|
10
12
|
"""
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""GPU-oriented loader functions for the MUSES dataset.
|
|
2
|
+
|
|
3
|
+
MUSES stores RGB camera frames, reference frames, semantic labels, panoptic
|
|
4
|
+
labels, and lidar point clouds in separate modality folders. These loaders
|
|
5
|
+
return PyTorch tensors for GPU-oriented training pipelines.
|
|
6
|
+
|
|
7
|
+
Return types
|
|
8
|
+
------------
|
|
9
|
+
- **rgb** / **reference_rgb** -- ``torch.FloatTensor`` of shape
|
|
10
|
+
``(3, H, W)`` in ``[0, 1]``.
|
|
11
|
+
- **semantic_segmentation** -- ``torch.LongTensor`` of shape ``(1, H, W)``
|
|
12
|
+
containing raw Cityscapes ``labelIds`` or ``labelTrainIds``.
|
|
13
|
+
- **semantic_segmentation_color** -- ``torch.ByteTensor`` of shape
|
|
14
|
+
``(3, H, W)`` containing Cityscapes RGB colours.
|
|
15
|
+
- **panoptic_segmentation** -- ``torch.LongTensor`` of shape ``(1, H, W)``
|
|
16
|
+
containing COCO-style panoptic segment IDs decoded from RGB.
|
|
17
|
+
- **lidar_point_cloud** / **sparse_depth** -- ``torch.DoubleTensor`` of shape
|
|
18
|
+
``(N, 6)`` with columns ``x, y, z, intensity, ring, timestamp``.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
from typing import Any, BinaryIO, Union
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
import torch
|
|
28
|
+
from PIL import Image
|
|
29
|
+
|
|
30
|
+
from euler_loading.loaders._annotations import modality_meta
|
|
31
|
+
|
|
32
|
+
_LIDAR_COLUMNS = ["x", "y", "z", "intensity", "ring", "timestamp"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _load_image_rgb(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
36
|
+
"""Load an image file as ``(H, W, 3)`` float32 in ``[0, 1]``."""
|
|
37
|
+
with Image.open(path) as image:
|
|
38
|
+
return np.array(image.convert("RGB"), dtype=np.float32) / 255.0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _load_single_channel_labels(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
42
|
+
"""Load a single-channel semantic label image as int64."""
|
|
43
|
+
with Image.open(path) as image:
|
|
44
|
+
arr = np.array(image, dtype=np.int64)
|
|
45
|
+
if arr.ndim != 2:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"MUSES semantic_segmentation expects a single-channel labelIds "
|
|
48
|
+
"or labelTrainIds PNG. Use semantic_segmentation_color for "
|
|
49
|
+
"labelColor PNG files."
|
|
50
|
+
)
|
|
51
|
+
return arr
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _load_rgb_uint8(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
55
|
+
"""Load an RGB image without normalisation."""
|
|
56
|
+
with Image.open(path) as image:
|
|
57
|
+
return np.array(image.convert("RGB"), dtype=np.uint8)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _decode_panoptic_rgb(rgb: np.ndarray) -> np.ndarray:
|
|
61
|
+
"""Decode COCO-style RGB panoptic IDs as ``R + 256*G + 256^2*B``."""
|
|
62
|
+
values = rgb.astype(np.int64)
|
|
63
|
+
return values[:, :, 0] + 256 * values[:, :, 1] + 65536 * values[:, :, 2]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _load_lidar_array(path: Union[str, BinaryIO]) -> np.ndarray:
|
|
67
|
+
"""Load a MUSES lidar ``.bin`` file as an ``(N, 6)`` float64 array."""
|
|
68
|
+
if isinstance(path, (str, os.PathLike)):
|
|
69
|
+
arr = np.fromfile(path, dtype=np.float64)
|
|
70
|
+
else:
|
|
71
|
+
arr = np.frombuffer(path.read(), dtype=np.float64).copy()
|
|
72
|
+
|
|
73
|
+
if arr.size % 6 != 0:
|
|
74
|
+
name = getattr(path, "name", path)
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"MUSES lidar file {name!r} contains {arr.size} float64 values, "
|
|
77
|
+
"which is not divisible by 6."
|
|
78
|
+
)
|
|
79
|
+
return arr.reshape((-1, 6))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@modality_meta(
|
|
83
|
+
modality_type="rgb",
|
|
84
|
+
dtype="float32",
|
|
85
|
+
shape="CHW",
|
|
86
|
+
file_formats=[".png"],
|
|
87
|
+
output_range=[0.0, 1.0],
|
|
88
|
+
)
|
|
89
|
+
def rgb(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
90
|
+
"""Load a MUSES frame-camera RGB image as a float32 tensor in ``[0, 1]``."""
|
|
91
|
+
arr = _load_image_rgb(path)
|
|
92
|
+
return torch.from_numpy(arr).permute(2, 0, 1).contiguous()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@modality_meta(
|
|
96
|
+
modality_type="rgb",
|
|
97
|
+
dtype="float32",
|
|
98
|
+
shape="CHW",
|
|
99
|
+
file_formats=[".png"],
|
|
100
|
+
output_range=[0.0, 1.0],
|
|
101
|
+
meta={"source": "reference_frames"},
|
|
102
|
+
)
|
|
103
|
+
def reference_rgb(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
104
|
+
"""Load a MUSES clear-weather reference RGB image as float32 in ``[0, 1]``."""
|
|
105
|
+
arr = _load_image_rgb(path)
|
|
106
|
+
return torch.from_numpy(arr).permute(2, 0, 1).contiguous()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@modality_meta(
|
|
110
|
+
modality_type="semantic_segmentation",
|
|
111
|
+
dtype="int64",
|
|
112
|
+
shape="1HW",
|
|
113
|
+
file_formats=[".png"],
|
|
114
|
+
meta={
|
|
115
|
+
"encoding": "single_channel",
|
|
116
|
+
"supported_suffixes": ["labelIds", "labelTrainIds"],
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
|
+
def semantic_segmentation(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
120
|
+
"""Load MUSES ``labelIds`` or ``labelTrainIds`` semantic labels."""
|
|
121
|
+
arr = _load_single_channel_labels(path)
|
|
122
|
+
return torch.from_numpy(arr).unsqueeze(0).contiguous()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@modality_meta(
|
|
126
|
+
modality_type="semantic_segmentation_color",
|
|
127
|
+
dtype="uint8",
|
|
128
|
+
shape="CHW",
|
|
129
|
+
file_formats=[".png"],
|
|
130
|
+
meta={"encoding": "rgb", "supported_suffixes": ["labelColor"]},
|
|
131
|
+
)
|
|
132
|
+
def semantic_segmentation_color(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
133
|
+
"""Load MUSES ``labelColor`` semantic labels as RGB uint8 values."""
|
|
134
|
+
arr = _load_rgb_uint8(path)
|
|
135
|
+
return torch.from_numpy(arr).permute(2, 0, 1).contiguous()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@modality_meta(
|
|
139
|
+
modality_type="panoptic_segmentation",
|
|
140
|
+
dtype="int64",
|
|
141
|
+
shape="1HW",
|
|
142
|
+
file_formats=[".png"],
|
|
143
|
+
meta={"encoding": "coco_rgb_id"},
|
|
144
|
+
)
|
|
145
|
+
def panoptic_segmentation(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
146
|
+
"""Load a MUSES panoptic PNG as an integer segment-ID map."""
|
|
147
|
+
arr = _decode_panoptic_rgb(_load_rgb_uint8(path))
|
|
148
|
+
return torch.from_numpy(arr).unsqueeze(0).contiguous()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@modality_meta(
|
|
152
|
+
modality_type="point_cloud",
|
|
153
|
+
dtype="float64",
|
|
154
|
+
shape="NC",
|
|
155
|
+
file_formats=[".bin"],
|
|
156
|
+
meta={
|
|
157
|
+
"columns": _LIDAR_COLUMNS,
|
|
158
|
+
"coordinate_unit": "meters",
|
|
159
|
+
"timestamp_unit": "seconds",
|
|
160
|
+
},
|
|
161
|
+
)
|
|
162
|
+
def lidar_point_cloud(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
163
|
+
"""Load a MUSES lidar point cloud as ``(N, 6)`` float64."""
|
|
164
|
+
return torch.from_numpy(_load_lidar_array(path)).contiguous()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def point_cloud(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
168
|
+
"""Alias for :func:`lidar_point_cloud`."""
|
|
169
|
+
return torch.from_numpy(_load_lidar_array(path)).contiguous()
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@modality_meta(
|
|
173
|
+
modality_type="sparse_depth",
|
|
174
|
+
dtype="float64",
|
|
175
|
+
shape="NC",
|
|
176
|
+
file_formats=[".bin"],
|
|
177
|
+
meta={
|
|
178
|
+
"representation": "point_cloud",
|
|
179
|
+
"columns": _LIDAR_COLUMNS,
|
|
180
|
+
"coordinate_unit": "meters",
|
|
181
|
+
"timestamp_unit": "seconds",
|
|
182
|
+
},
|
|
183
|
+
)
|
|
184
|
+
def sparse_depth(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
185
|
+
"""Load MUSES lidar points for sparse-depth style workflows."""
|
|
186
|
+
return torch.from_numpy(_load_lidar_array(path)).contiguous()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Loader functions for the MUSES dataset.
|
|
2
|
+
|
|
3
|
+
This module re-exports the GPU-oriented loaders from
|
|
4
|
+
:mod:`euler_loading.loaders.gpu.muses` for convenience. For explicit
|
|
5
|
+
control, import from :mod:`~euler_loading.loaders.gpu` or
|
|
6
|
+
:mod:`~euler_loading.loaders.cpu` directly::
|
|
7
|
+
|
|
8
|
+
from euler_loading.loaders.gpu import muses # torch tensors (CHW)
|
|
9
|
+
from euler_loading.loaders.cpu import muses # numpy arrays (HWC)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from euler_loading.loaders.gpu.muses import * # noqa: F401,F403
|
|
@@ -2,22 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import io
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import numpy as np
|
|
8
9
|
import pytest
|
|
9
10
|
import torch
|
|
11
|
+
from PIL import Image
|
|
10
12
|
|
|
11
13
|
from euler_loading.loaders import vkitti2
|
|
12
14
|
from euler_loading.loaders import generic as generic_top
|
|
15
|
+
from euler_loading.loaders import muses as muses_top
|
|
13
16
|
from euler_loading.loaders.gpu import vkitti2 as gpu_vkitti2
|
|
14
17
|
from euler_loading.loaders.gpu import real_drive_sim as gpu_rds
|
|
15
18
|
from euler_loading.loaders.gpu import generic as gpu_generic
|
|
16
19
|
from euler_loading.loaders.gpu import generic_dense_depth as gpu_generic_dense_depth
|
|
20
|
+
from euler_loading.loaders.gpu import muses as gpu_muses
|
|
17
21
|
from euler_loading.loaders.cpu import vkitti2 as cpu_vkitti2
|
|
18
22
|
from euler_loading.loaders.cpu import real_drive_sim as cpu_rds
|
|
19
23
|
from euler_loading.loaders.cpu import generic as cpu_generic
|
|
20
24
|
from euler_loading.loaders.cpu import generic_dense_depth as cpu_generic_dense_depth
|
|
25
|
+
from euler_loading.loaders.cpu import muses as cpu_muses
|
|
21
26
|
|
|
22
27
|
# ---------------------------------------------------------------------------
|
|
23
28
|
# Shared fixtures
|
|
@@ -143,6 +148,230 @@ class TestGenericDenseDepthAttributes:
|
|
|
143
148
|
np.testing.assert_allclose(result, expected)
|
|
144
149
|
|
|
145
150
|
|
|
151
|
+
# ---------------------------------------------------------------------------
|
|
152
|
+
# MUSES loader smoke tests
|
|
153
|
+
# ---------------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
MUSES_LOADER_NAMES = [
|
|
156
|
+
"rgb",
|
|
157
|
+
"reference_rgb",
|
|
158
|
+
"semantic_segmentation",
|
|
159
|
+
"semantic_segmentation_color",
|
|
160
|
+
"panoptic_segmentation",
|
|
161
|
+
"lidar_point_cloud",
|
|
162
|
+
"point_cloud",
|
|
163
|
+
"sparse_depth",
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@pytest.fixture()
|
|
168
|
+
def muses_rgb_path(tmp_path):
|
|
169
|
+
arr = np.array(
|
|
170
|
+
[
|
|
171
|
+
[[0, 64, 128], [255, 128, 0]],
|
|
172
|
+
[[32, 16, 8], [4, 2, 1]],
|
|
173
|
+
],
|
|
174
|
+
dtype=np.uint8,
|
|
175
|
+
)
|
|
176
|
+
path = tmp_path / "REC0001_frame_000001_frame_camera.png"
|
|
177
|
+
Image.fromarray(arr, mode="RGB").save(path)
|
|
178
|
+
return str(path), arr
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@pytest.fixture()
|
|
182
|
+
def muses_semantic_path(tmp_path):
|
|
183
|
+
arr = np.array([[0, 7], [24, 255]], dtype=np.uint8)
|
|
184
|
+
path = tmp_path / "REC0001_frame_000001_gt_labelTrainIds.png"
|
|
185
|
+
Image.fromarray(arr, mode="L").save(path)
|
|
186
|
+
return str(path), arr
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@pytest.fixture()
|
|
190
|
+
def muses_semantic_color_path(tmp_path):
|
|
191
|
+
arr = np.array(
|
|
192
|
+
[
|
|
193
|
+
[[128, 64, 128], [70, 70, 70]],
|
|
194
|
+
[[220, 20, 60], [0, 0, 142]],
|
|
195
|
+
],
|
|
196
|
+
dtype=np.uint8,
|
|
197
|
+
)
|
|
198
|
+
path = tmp_path / "REC0001_frame_000001_gt_labelColor.png"
|
|
199
|
+
Image.fromarray(arr, mode="RGB").save(path)
|
|
200
|
+
return str(path), arr
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@pytest.fixture()
|
|
204
|
+
def muses_panoptic_path(tmp_path):
|
|
205
|
+
arr = np.array(
|
|
206
|
+
[
|
|
207
|
+
[[1, 0, 0], [2, 1, 0]],
|
|
208
|
+
[[3, 2, 1], [255, 255, 255]],
|
|
209
|
+
],
|
|
210
|
+
dtype=np.uint8,
|
|
211
|
+
)
|
|
212
|
+
path = tmp_path / "REC0001_frame_000001_gt_panoptic.png"
|
|
213
|
+
Image.fromarray(arr, mode="RGB").save(path)
|
|
214
|
+
expected = (
|
|
215
|
+
arr[:, :, 0].astype(np.int64)
|
|
216
|
+
+ 256 * arr[:, :, 1].astype(np.int64)
|
|
217
|
+
+ 65536 * arr[:, :, 2].astype(np.int64)
|
|
218
|
+
)
|
|
219
|
+
return str(path), expected
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@pytest.fixture()
|
|
223
|
+
def muses_lidar_path(tmp_path):
|
|
224
|
+
arr = np.array(
|
|
225
|
+
[
|
|
226
|
+
[1.0, 2.0, 3.0, 19.0, 1.0, 1671182560.125],
|
|
227
|
+
[4.0, 5.0, 6.0, 27.0, 5.0, 1671182560.250],
|
|
228
|
+
],
|
|
229
|
+
dtype=np.float64,
|
|
230
|
+
)
|
|
231
|
+
path = tmp_path / "REC0001_frame_000001_lidar.bin"
|
|
232
|
+
arr.tofile(path)
|
|
233
|
+
return str(path), arr
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class TestMUSESModuleContents:
|
|
237
|
+
"""The muses module exposes the expected loader functions."""
|
|
238
|
+
|
|
239
|
+
@pytest.mark.parametrize("name", MUSES_LOADER_NAMES)
|
|
240
|
+
def test_top_level_has_callable(self, name):
|
|
241
|
+
assert callable(getattr(muses_top, name))
|
|
242
|
+
|
|
243
|
+
@pytest.mark.parametrize("name", MUSES_LOADER_NAMES)
|
|
244
|
+
def test_gpu_has_callable(self, name):
|
|
245
|
+
assert callable(getattr(gpu_muses, name))
|
|
246
|
+
|
|
247
|
+
@pytest.mark.parametrize("name", MUSES_LOADER_NAMES)
|
|
248
|
+
def test_cpu_has_callable(self, name):
|
|
249
|
+
assert callable(getattr(cpu_muses, name))
|
|
250
|
+
|
|
251
|
+
def test_reference_rgb_is_marked_as_rgb_modality(self):
|
|
252
|
+
assert gpu_muses.reference_rgb._modality_meta["type"] == "rgb"
|
|
253
|
+
assert cpu_muses.reference_rgb._modality_meta["type"] == "rgb"
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class TestMUSESGPULoaders:
|
|
257
|
+
"""GPU MUSES loaders produce torch tensors from minimal on-disk data."""
|
|
258
|
+
|
|
259
|
+
def test_rgb_shape_dtype_and_range(self, muses_rgb_path):
|
|
260
|
+
path, _ = muses_rgb_path
|
|
261
|
+
result = gpu_muses.rgb(path)
|
|
262
|
+
assert isinstance(result, torch.Tensor)
|
|
263
|
+
assert result.dtype == torch.float32
|
|
264
|
+
assert result.shape == (3, 2, 2)
|
|
265
|
+
assert result.min() >= 0.0
|
|
266
|
+
assert result.max() <= 1.0
|
|
267
|
+
|
|
268
|
+
def test_reference_rgb_matches_rgb_loader(self, muses_rgb_path):
|
|
269
|
+
path, _ = muses_rgb_path
|
|
270
|
+
assert torch.equal(gpu_muses.reference_rgb(path), gpu_muses.rgb(path))
|
|
271
|
+
|
|
272
|
+
def test_semantic_segmentation_is_single_channel_long(self, muses_semantic_path):
|
|
273
|
+
path, expected = muses_semantic_path
|
|
274
|
+
result = gpu_muses.semantic_segmentation(path)
|
|
275
|
+
assert result.dtype == torch.int64
|
|
276
|
+
assert result.shape == (1, 2, 2)
|
|
277
|
+
assert torch.equal(result, torch.from_numpy(expected.astype(np.int64)).unsqueeze(0))
|
|
278
|
+
|
|
279
|
+
def test_semantic_color_is_chw_uint8(self, muses_semantic_color_path):
|
|
280
|
+
path, expected = muses_semantic_color_path
|
|
281
|
+
result = gpu_muses.semantic_segmentation_color(path)
|
|
282
|
+
assert result.dtype == torch.uint8
|
|
283
|
+
assert result.shape == (3, 2, 2)
|
|
284
|
+
assert torch.equal(result, torch.from_numpy(expected).permute(2, 0, 1))
|
|
285
|
+
|
|
286
|
+
def test_panoptic_segmentation_decodes_rgb_ids(self, muses_panoptic_path):
|
|
287
|
+
path, expected = muses_panoptic_path
|
|
288
|
+
result = gpu_muses.panoptic_segmentation(path)
|
|
289
|
+
assert result.dtype == torch.int64
|
|
290
|
+
assert result.shape == (1, 2, 2)
|
|
291
|
+
assert torch.equal(result, torch.from_numpy(expected).unsqueeze(0))
|
|
292
|
+
|
|
293
|
+
def test_lidar_point_cloud_preserves_float64_columns(self, muses_lidar_path):
|
|
294
|
+
path, expected = muses_lidar_path
|
|
295
|
+
result = gpu_muses.lidar_point_cloud(path)
|
|
296
|
+
assert result.dtype == torch.float64
|
|
297
|
+
assert result.shape == (2, 6)
|
|
298
|
+
assert torch.equal(result, torch.from_numpy(expected))
|
|
299
|
+
|
|
300
|
+
def test_point_cloud_alias_matches_lidar_point_cloud(self, muses_lidar_path):
|
|
301
|
+
path, _ = muses_lidar_path
|
|
302
|
+
assert torch.equal(gpu_muses.point_cloud(path), gpu_muses.lidar_point_cloud(path))
|
|
303
|
+
|
|
304
|
+
def test_sparse_depth_matches_lidar_point_cloud(self, muses_lidar_path):
|
|
305
|
+
path, _ = muses_lidar_path
|
|
306
|
+
assert torch.equal(gpu_muses.sparse_depth(path), gpu_muses.lidar_point_cloud(path))
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class TestMUSESCPULoaders:
|
|
310
|
+
"""CPU MUSES loaders produce numpy arrays from minimal on-disk data."""
|
|
311
|
+
|
|
312
|
+
def test_rgb_shape_dtype_and_range(self, muses_rgb_path):
|
|
313
|
+
path, _ = muses_rgb_path
|
|
314
|
+
result = cpu_muses.rgb(path)
|
|
315
|
+
assert isinstance(result, np.ndarray)
|
|
316
|
+
assert result.dtype == np.float32
|
|
317
|
+
assert result.shape == (2, 2, 3)
|
|
318
|
+
assert result.min() >= 0.0
|
|
319
|
+
assert result.max() <= 1.0
|
|
320
|
+
|
|
321
|
+
def test_semantic_segmentation_is_hw_int64(self, muses_semantic_path):
|
|
322
|
+
path, expected = muses_semantic_path
|
|
323
|
+
result = cpu_muses.semantic_segmentation(path)
|
|
324
|
+
assert result.dtype == np.int64
|
|
325
|
+
assert result.shape == (2, 2)
|
|
326
|
+
assert np.array_equal(result, expected.astype(np.int64))
|
|
327
|
+
|
|
328
|
+
def test_semantic_color_is_hwc_uint8(self, muses_semantic_color_path):
|
|
329
|
+
path, expected = muses_semantic_color_path
|
|
330
|
+
result = cpu_muses.semantic_segmentation_color(path)
|
|
331
|
+
assert result.dtype == np.uint8
|
|
332
|
+
assert result.shape == (2, 2, 3)
|
|
333
|
+
assert np.array_equal(result, expected)
|
|
334
|
+
|
|
335
|
+
def test_panoptic_segmentation_decodes_rgb_ids(self, muses_panoptic_path):
|
|
336
|
+
path, expected = muses_panoptic_path
|
|
337
|
+
result = cpu_muses.panoptic_segmentation(path)
|
|
338
|
+
assert result.dtype == np.int64
|
|
339
|
+
assert result.shape == (2, 2)
|
|
340
|
+
assert np.array_equal(result, expected)
|
|
341
|
+
|
|
342
|
+
def test_lidar_point_cloud_preserves_float64_columns(self, muses_lidar_path):
|
|
343
|
+
path, expected = muses_lidar_path
|
|
344
|
+
result = cpu_muses.lidar_point_cloud(path)
|
|
345
|
+
assert result.dtype == np.float64
|
|
346
|
+
assert result.shape == (2, 6)
|
|
347
|
+
assert np.array_equal(result, expected)
|
|
348
|
+
|
|
349
|
+
def test_point_cloud_alias_matches_lidar_point_cloud(self, muses_lidar_path):
|
|
350
|
+
path, _ = muses_lidar_path
|
|
351
|
+
assert np.array_equal(cpu_muses.point_cloud(path), cpu_muses.lidar_point_cloud(path))
|
|
352
|
+
|
|
353
|
+
def test_lidar_point_cloud_supports_binary_streams(self, muses_lidar_path):
|
|
354
|
+
_, expected = muses_lidar_path
|
|
355
|
+
stream = io.BytesIO(expected.tobytes())
|
|
356
|
+
result = cpu_muses.lidar_point_cloud(stream)
|
|
357
|
+
assert np.array_equal(result, expected)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class TestMUSESBackwardCompat:
|
|
361
|
+
"""``from euler_loading.loaders import muses`` returns GPU loaders."""
|
|
362
|
+
|
|
363
|
+
def test_top_level_rgb_matches_gpu(self, muses_rgb_path):
|
|
364
|
+
path, _ = muses_rgb_path
|
|
365
|
+
assert torch.equal(muses_top.rgb(path), gpu_muses.rgb(path))
|
|
366
|
+
|
|
367
|
+
def test_top_level_panoptic_matches_gpu(self, muses_panoptic_path):
|
|
368
|
+
path, _ = muses_panoptic_path
|
|
369
|
+
assert torch.equal(
|
|
370
|
+
muses_top.panoptic_segmentation(path),
|
|
371
|
+
gpu_muses.panoptic_segmentation(path),
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
146
375
|
# ---------------------------------------------------------------------------
|
|
147
376
|
# GPU loader smoke tests
|
|
148
377
|
# ---------------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/cpu/generic_dense_depth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{euler_loading-2.8.0 → euler_loading-2.9.0}/euler_loading/loaders/gpu/generic_dense_depth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|