euler-loading 2.14.0__tar.gz → 2.18.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.14.0 → euler_loading-2.18.0}/PKG-INFO +1 -1
- {euler_loading-2.14.0 → euler_loading-2.18.0}/README.md +10 -2
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/_resolution.py +4 -5
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/cpu/generic.py +33 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/cpu/princeton_dense.py +22 -3
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/generate/loaders.json +45 -8
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/gpu/generic.py +31 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/gpu/princeton_dense.py +24 -3
- euler_loading-2.18.0/gen_loaders.sh +7 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/package-lock.json +1 -1
- {euler_loading-2.14.0 → euler_loading-2.18.0}/pyproject.toml +1 -1
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/test_loaders.py +113 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/.github/workflows/workflow.yml +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/.gitignore +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/docs/loader-attributes.md +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/__init__.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/_dataset_contract.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/_ds_crawler_utils.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/_metadata.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/_writing.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/dataset.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/indexing.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/__init__.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/_annotations.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/_princeton_dense.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/_writer_utils.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/contracts.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/cpu/__init__.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/cpu/generic_dense_depth.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/cpu/muses.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/cpu/real_drive_sim.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/cpu/vkitti2.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/generate/__init__.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/generate/__main__.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/generic.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/gpu/__init__.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/gpu/generic_dense_depth.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/gpu/muses.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/gpu/real_drive_sim.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/gpu/vkitti2.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/muses.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/princeton_dense.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/real_drive_sim.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/loaders/vkitti2.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/euler_loading/preprocessing.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/example.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/sample_rds.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/__init__.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/conftest.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/example_rds_calib.json +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/test_dataset.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/test_id_schema.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/test_indexing.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/test_preprocessing.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/test_real_dataset.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/tests/test_writing.py +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/vkitti_cpu_example_output.json +0 -0
- {euler_loading-2.14.0 → euler_loading-2.18.0}/vkitti_gpu_example_output.json +0 -0
|
@@ -381,7 +381,7 @@ When `Modality.loader` is `None`, euler-loading resolves the loader from the ds-
|
|
|
381
381
|
}
|
|
382
382
|
```
|
|
383
383
|
|
|
384
|
-
`loader` is the module name (`vkitti2`, `real_drive_sim`, `muses`, `princeton_dense`, or `generic_dense_depth`) and `function` is the function within that module. The GPU variant is used by default.
|
|
384
|
+
`loader` is the module name (`vkitti2`, `real_drive_sim`, `muses`, `princeton_dense`, `generic`, or `generic_dense_depth`) and `function` is the function within that module. The GPU variant is used by default.
|
|
385
385
|
|
|
386
386
|
Writer resolution uses the same module and function metadata:
|
|
387
387
|
|
|
@@ -550,7 +550,15 @@ A format-agnostic loader that infers the loading strategy from the file extensio
|
|
|
550
550
|
| `sky_mask` | Binary mask by comparing pixels against `meta["sky_mask"]` (`[R, G, B]`). Requires `meta` |
|
|
551
551
|
| `read_intrinsics` | Returns `meta["intrinsics"]` as a `(3, 3)` tensor. Ignores path; requires `meta` |
|
|
552
552
|
|
|
553
|
-
|
|
553
|
+
### Generic NumPy Modalities (`euler_loading.loaders.gpu.generic`)
|
|
554
|
+
|
|
555
|
+
Generic loaders for `.npy` and `.npz` modalities without dataset-specific decoding.
|
|
556
|
+
|
|
557
|
+
| Function | Description |
|
|
558
|
+
|----------|-------------|
|
|
559
|
+
| `points_3d` | Dense 3D point map from NumPy files stored as `(3, H, W)` float32 |
|
|
560
|
+
|
|
561
|
+
CPU variants of all loaders live under `euler_loading.loaders.cpu.{vkitti2,real_drive_sim,muses,princeton_dense,generic,generic_dense_depth}`.
|
|
554
562
|
|
|
555
563
|
### Flattening hierarchical modalities
|
|
556
564
|
|
|
@@ -58,9 +58,7 @@ def resolve_loader_module(name: str) -> ModuleType:
|
|
|
58
58
|
module_path = _LOADER_MODULES.get(name)
|
|
59
59
|
if module_path is None:
|
|
60
60
|
available = ", ".join(sorted(_LOADER_MODULES))
|
|
61
|
-
raise ValueError(
|
|
62
|
-
f"Unknown loader {name!r}. Available loaders: {available}"
|
|
63
|
-
)
|
|
61
|
+
raise ValueError(f"Unknown loader {name!r}. Available loaders: {available}")
|
|
64
62
|
return importlib.import_module(module_path)
|
|
65
63
|
|
|
66
64
|
|
|
@@ -132,7 +130,8 @@ def _resolve_loader(
|
|
|
132
130
|
func = getattr(module, func_name, None)
|
|
133
131
|
if func is None or not callable(func):
|
|
134
132
|
available = [
|
|
135
|
-
attr
|
|
133
|
+
attr
|
|
134
|
+
for attr in dir(module)
|
|
136
135
|
if not attr.startswith("_") and callable(getattr(module, attr))
|
|
137
136
|
]
|
|
138
137
|
raise ValueError(
|
|
@@ -150,7 +149,7 @@ def _writer_name_candidates(read_function_name: str, explicit: Any) -> list[str]
|
|
|
150
149
|
names.append(explicit_name)
|
|
151
150
|
|
|
152
151
|
if read_function_name.startswith("read_"):
|
|
153
|
-
names.append(f"write_{read_function_name[len('read_'):]}")
|
|
152
|
+
names.append(f"write_{read_function_name[len('read_') :]}")
|
|
154
153
|
names.append(f"write_{read_function_name}")
|
|
155
154
|
|
|
156
155
|
deduped: list[str] = []
|
|
@@ -12,6 +12,7 @@ Return types
|
|
|
12
12
|
------------
|
|
13
13
|
- **map_2d** / **scattering_coefficient** -- ``np.ndarray`` of shape ``(H, W)`` float32.
|
|
14
14
|
- **map_3d** / **atmospheric_light** -- ``np.ndarray`` of shape ``(H, W, C)`` float32.
|
|
15
|
+
- **points_3d** -- ``np.ndarray`` of shape ``(3, H, W)`` float32.
|
|
15
16
|
- **spherical_map** -- ``np.ndarray`` of shape ``(H, W, C)`` float32.
|
|
16
17
|
- **intrinsics** -- ``np.ndarray`` of shape ``(3, 3)`` float32.
|
|
17
18
|
- **sh_coeffs** -- ``np.ndarray`` of shape ``(N, 3)`` float32.
|
|
@@ -23,6 +24,7 @@ Usage::
|
|
|
23
24
|
|
|
24
25
|
Modality("/data/my_dataset/scattering_coefficient", loader=generic.scattering_coefficient)
|
|
25
26
|
Modality("/data/my_dataset/atmospheric_light", loader=generic.atmospheric_light)
|
|
27
|
+
Modality("/data/my_dataset/points_3d", loader=generic.points_3d)
|
|
26
28
|
Modality("/data/my_dataset/spherical_map", loader=generic.spherical_map)
|
|
27
29
|
Modality("/data/my_dataset/intrinsics", loader=generic.intrinsics)
|
|
28
30
|
Modality("/data/my_dataset/sh_coeffs", loader=generic.sh_coeffs)
|
|
@@ -85,6 +87,14 @@ def _write_numpy(path: Union[str, BinaryIO], value: Any) -> None:
|
|
|
85
87
|
raise ValueError(f"Unsupported output extension: {ext}")
|
|
86
88
|
|
|
87
89
|
|
|
90
|
+
def _as_3d_points(value: Any) -> np.ndarray:
|
|
91
|
+
"""Return a float32 ``(3, H, W)`` array for dense 3D point maps."""
|
|
92
|
+
arr = to_numpy(value).astype(np.float32)
|
|
93
|
+
if arr.ndim != 3 or arr.shape[0] != 3:
|
|
94
|
+
raise ValueError(f"points_3d must have shape (3, H, W), got {arr.shape}")
|
|
95
|
+
return arr
|
|
96
|
+
|
|
97
|
+
|
|
88
98
|
# ---------------------------------------------------------------------------
|
|
89
99
|
# Public loaders
|
|
90
100
|
# ---------------------------------------------------------------------------
|
|
@@ -124,6 +134,23 @@ def map_3d(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, at
|
|
|
124
134
|
return np.transpose(arr, (1, 2, 0))
|
|
125
135
|
|
|
126
136
|
|
|
137
|
+
@modality_meta(
|
|
138
|
+
modality_type="points_3d",
|
|
139
|
+
dtype="float32",
|
|
140
|
+
shape="3HW",
|
|
141
|
+
file_formats=[".npy", ".npz"],
|
|
142
|
+
)
|
|
143
|
+
def points_3d(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> np.ndarray:
|
|
144
|
+
"""Load dense 3D points as a ``(3, H, W)`` float32 array.
|
|
145
|
+
|
|
146
|
+
Files are expected to store the per-pixel 3D point coordinates directly in
|
|
147
|
+
``(3, H, W)`` layout. Unlike :func:`map_3d`, this loader preserves the
|
|
148
|
+
channel-first representation on CPU because it is a coordinate point map,
|
|
149
|
+
not a generic HWC image-style map.
|
|
150
|
+
"""
|
|
151
|
+
return _as_3d_points(_load_numpy(path))
|
|
152
|
+
|
|
153
|
+
|
|
127
154
|
@modality_meta(
|
|
128
155
|
modality_type="scattering_coefficient",
|
|
129
156
|
dtype="float32",
|
|
@@ -239,6 +266,12 @@ def write_map_3d(path: Union[str, BinaryIO], value: Any, meta: dict[str, Any] |
|
|
|
239
266
|
raise ValueError(f"Unsupported map_3d output extension: {ext}")
|
|
240
267
|
|
|
241
268
|
|
|
269
|
+
@mark_stream_supported
|
|
270
|
+
def write_points_3d(path: Union[str, BinaryIO], value: Any, meta: dict[str, Any] | None = None) -> None:
|
|
271
|
+
"""Write dense 3D points to NumPy formats in ``(3, H, W)`` layout."""
|
|
272
|
+
_write_numpy(path, _as_3d_points(value))
|
|
273
|
+
|
|
274
|
+
|
|
242
275
|
@mark_stream_supported
|
|
243
276
|
def write_scattering_coefficient(path: Union[str, BinaryIO], value: Any, meta: dict[str, Any] | None = None) -> None:
|
|
244
277
|
"""Write a scattering-coefficient map (delegates to :func:`write_map_2d`)."""
|
|
@@ -5,6 +5,7 @@ images and Velodyne lidar point clouds as binary ``float32`` records.
|
|
|
5
5
|
|
|
6
6
|
Return types
|
|
7
7
|
------------
|
|
8
|
+
- **rccb** -- ``np.ndarray`` of shape ``(H, W, 3)`` float32 in ``[0, 1]``.
|
|
8
9
|
- **rgb** -- ``np.ndarray`` of shape ``(H, W, 3)`` float32 in ``[0, 1]``.
|
|
9
10
|
- **sparse_depth** -- ``np.ndarray`` of shape ``(N, 5)`` float32 with columns
|
|
10
11
|
``x, y, z, intensity, ring``.
|
|
@@ -20,6 +21,7 @@ from __future__ import annotations
|
|
|
20
21
|
from typing import Any, BinaryIO, Union
|
|
21
22
|
|
|
22
23
|
import numpy as np
|
|
24
|
+
from PIL import Image
|
|
23
25
|
|
|
24
26
|
from euler_loading.loaders._annotations import modality_meta
|
|
25
27
|
from euler_loading.loaders._princeton_dense import DEFAULT_CAMERA_FRAME
|
|
@@ -32,7 +34,7 @@ from euler_loading.loaders._princeton_dense import load_sparse_depth_array
|
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
@modality_meta(
|
|
35
|
-
modality_type="
|
|
37
|
+
modality_type="rccb",
|
|
36
38
|
dtype="float32",
|
|
37
39
|
shape="HWC",
|
|
38
40
|
file_formats=[".tif", ".tiff"],
|
|
@@ -44,16 +46,33 @@ from euler_loading.loaders._princeton_dense import load_sparse_depth_array
|
|
|
44
46
|
"raw_max_value": 4095.0,
|
|
45
47
|
},
|
|
46
48
|
)
|
|
47
|
-
def
|
|
49
|
+
def rccb(
|
|
48
50
|
path: Union[str, BinaryIO],
|
|
49
51
|
meta: dict[str, Any] | None = None,
|
|
50
52
|
*,
|
|
51
53
|
attributes: dict[str, Any] | None = None,
|
|
52
54
|
) -> np.ndarray:
|
|
53
|
-
"""Load a SeeingThroughFog 12-bit Bayer TIFF as
|
|
55
|
+
"""Load a SeeingThroughFog 12-bit Bayer TIFF as RCCB float32 in ``[0, 1]``."""
|
|
54
56
|
return load_rgb_array(path, meta, attributes)
|
|
55
57
|
|
|
56
58
|
|
|
59
|
+
@modality_meta(
|
|
60
|
+
modality_type="rgb",
|
|
61
|
+
dtype="float32",
|
|
62
|
+
shape="HWC",
|
|
63
|
+
file_formats=[".png"],
|
|
64
|
+
output_range=[0.0, 1.0],
|
|
65
|
+
)
|
|
66
|
+
def rgb(
|
|
67
|
+
path: Union[str, BinaryIO],
|
|
68
|
+
meta: dict[str, Any] | None = None,
|
|
69
|
+
*,
|
|
70
|
+
attributes: dict[str, Any] | None = None,
|
|
71
|
+
) -> np.ndarray:
|
|
72
|
+
"""Load a SeeingThroughFog plain 8-bit PNG as RGB float32 in ``[0, 1]``."""
|
|
73
|
+
return np.array(Image.open(path).convert("RGB"), dtype=np.float32) / 255.0
|
|
74
|
+
|
|
75
|
+
|
|
57
76
|
@modality_meta(
|
|
58
77
|
modality_type="sparse_depth",
|
|
59
78
|
dtype="float32",
|
|
@@ -71,6 +71,23 @@
|
|
|
71
71
|
"shape": "CHW"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
+
{
|
|
75
|
+
"type": "points_3d",
|
|
76
|
+
"function": "points_3d",
|
|
77
|
+
"hierarchical": false,
|
|
78
|
+
"dtype": "float32",
|
|
79
|
+
"access": "key",
|
|
80
|
+
"file_formats": [
|
|
81
|
+
".npy",
|
|
82
|
+
".npz"
|
|
83
|
+
],
|
|
84
|
+
"cpu": {
|
|
85
|
+
"shape": "3HW"
|
|
86
|
+
},
|
|
87
|
+
"gpu": {
|
|
88
|
+
"shape": "3HW"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
74
91
|
{
|
|
75
92
|
"type": "scattering_coefficient",
|
|
76
93
|
"function": "scattering_coefficient",
|
|
@@ -456,6 +473,33 @@
|
|
|
456
473
|
{
|
|
457
474
|
"name": "princeton_dense",
|
|
458
475
|
"modalities": [
|
|
476
|
+
{
|
|
477
|
+
"type": "rccb",
|
|
478
|
+
"function": "rccb",
|
|
479
|
+
"hierarchical": false,
|
|
480
|
+
"dtype": "float32",
|
|
481
|
+
"access": "key",
|
|
482
|
+
"output_range": [
|
|
483
|
+
0.0,
|
|
484
|
+
1.0
|
|
485
|
+
],
|
|
486
|
+
"file_formats": [
|
|
487
|
+
".tif",
|
|
488
|
+
".tiff"
|
|
489
|
+
],
|
|
490
|
+
"meta": {
|
|
491
|
+
"dataset": "SeeingThroughFog",
|
|
492
|
+
"raw_bit_depth": 12,
|
|
493
|
+
"bayer_pattern": "GBRG",
|
|
494
|
+
"raw_max_value": 4095.0
|
|
495
|
+
},
|
|
496
|
+
"cpu": {
|
|
497
|
+
"shape": "HWC"
|
|
498
|
+
},
|
|
499
|
+
"gpu": {
|
|
500
|
+
"shape": "CHW"
|
|
501
|
+
}
|
|
502
|
+
},
|
|
459
503
|
{
|
|
460
504
|
"type": "camera_extrinsics",
|
|
461
505
|
"function": "read_extrinsics",
|
|
@@ -510,15 +554,8 @@
|
|
|
510
554
|
1.0
|
|
511
555
|
],
|
|
512
556
|
"file_formats": [
|
|
513
|
-
".
|
|
514
|
-
".tiff"
|
|
557
|
+
".png"
|
|
515
558
|
],
|
|
516
|
-
"meta": {
|
|
517
|
-
"dataset": "SeeingThroughFog",
|
|
518
|
-
"raw_bit_depth": 12,
|
|
519
|
-
"bayer_pattern": "GBRG",
|
|
520
|
-
"raw_max_value": 4095.0
|
|
521
|
-
},
|
|
522
559
|
"cpu": {
|
|
523
560
|
"shape": "HWC"
|
|
524
561
|
},
|
|
@@ -12,6 +12,7 @@ Return types
|
|
|
12
12
|
------------
|
|
13
13
|
- **map_2d** / **scattering_coefficient** -- ``torch.FloatTensor`` of shape ``(H, W)``.
|
|
14
14
|
- **map_3d** / **atmospheric_light** -- ``torch.FloatTensor`` of shape ``(C, H, W)``.
|
|
15
|
+
- **points_3d** -- ``torch.FloatTensor`` of shape ``(3, H, W)``.
|
|
15
16
|
- **spherical_map** -- ``torch.FloatTensor`` of shape ``(C, H, W)``.
|
|
16
17
|
- **intrinsics** -- ``torch.FloatTensor`` of shape ``(3, 3)``.
|
|
17
18
|
- **sh_coeffs** -- ``torch.FloatTensor`` of shape ``(N, 3)``.
|
|
@@ -23,6 +24,7 @@ Usage::
|
|
|
23
24
|
|
|
24
25
|
Modality("/data/my_dataset/scattering_coefficient", loader=generic.scattering_coefficient)
|
|
25
26
|
Modality("/data/my_dataset/atmospheric_light", loader=generic.atmospheric_light)
|
|
27
|
+
Modality("/data/my_dataset/points_3d", loader=generic.points_3d)
|
|
26
28
|
Modality("/data/my_dataset/spherical_map", loader=generic.spherical_map)
|
|
27
29
|
Modality("/data/my_dataset/intrinsics", loader=generic.intrinsics)
|
|
28
30
|
Modality("/data/my_dataset/sh_coeffs", loader=generic.sh_coeffs)
|
|
@@ -86,6 +88,14 @@ def _write_numpy(path: Union[str, BinaryIO], value: Any) -> None:
|
|
|
86
88
|
raise ValueError(f"Unsupported output extension: {ext}")
|
|
87
89
|
|
|
88
90
|
|
|
91
|
+
def _as_3d_points(value: Any) -> np.ndarray:
|
|
92
|
+
"""Return a float32 ``(3, H, W)`` array for dense 3D point maps."""
|
|
93
|
+
arr = to_numpy(value).astype(np.float32)
|
|
94
|
+
if arr.ndim != 3 or arr.shape[0] != 3:
|
|
95
|
+
raise ValueError(f"points_3d must have shape (3, H, W), got {arr.shape}")
|
|
96
|
+
return arr
|
|
97
|
+
|
|
98
|
+
|
|
89
99
|
# ---------------------------------------------------------------------------
|
|
90
100
|
# Public loaders
|
|
91
101
|
# ---------------------------------------------------------------------------
|
|
@@ -125,6 +135,21 @@ def map_3d(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, at
|
|
|
125
135
|
return torch.from_numpy(arr).contiguous()
|
|
126
136
|
|
|
127
137
|
|
|
138
|
+
@modality_meta(
|
|
139
|
+
modality_type="points_3d",
|
|
140
|
+
dtype="float32",
|
|
141
|
+
shape="3HW",
|
|
142
|
+
file_formats=[".npy", ".npz"],
|
|
143
|
+
)
|
|
144
|
+
def points_3d(path: Union[str, BinaryIO], meta: dict[str, Any] | None = None, *, attributes: dict[str, Any] | None = None) -> torch.Tensor:
|
|
145
|
+
"""Load dense 3D points as a ``(3, H, W)`` float32 tensor.
|
|
146
|
+
|
|
147
|
+
Files are expected to store the per-pixel 3D point coordinates directly in
|
|
148
|
+
``(3, H, W)`` layout.
|
|
149
|
+
"""
|
|
150
|
+
return torch.from_numpy(_as_3d_points(_load_numpy(path))).contiguous()
|
|
151
|
+
|
|
152
|
+
|
|
128
153
|
@modality_meta(
|
|
129
154
|
modality_type="scattering_coefficient",
|
|
130
155
|
dtype="float32",
|
|
@@ -229,6 +254,12 @@ def write_map_3d(path: Union[str, BinaryIO], value: Any, meta: dict[str, Any] |
|
|
|
229
254
|
_write_numpy(path, value)
|
|
230
255
|
|
|
231
256
|
|
|
257
|
+
@mark_stream_supported
|
|
258
|
+
def write_points_3d(path: Union[str, BinaryIO], value: Any, meta: dict[str, Any] | None = None) -> None:
|
|
259
|
+
"""Write dense 3D points to NumPy formats in ``(3, H, W)`` layout."""
|
|
260
|
+
_write_numpy(path, _as_3d_points(value))
|
|
261
|
+
|
|
262
|
+
|
|
232
263
|
@mark_stream_supported
|
|
233
264
|
def write_scattering_coefficient(path: Union[str, BinaryIO], value: Any, meta: dict[str, Any] | None = None) -> None:
|
|
234
265
|
"""Write a scattering-coefficient map (delegates to :func:`write_map_2d`)."""
|
|
@@ -5,6 +5,7 @@ images and Velodyne lidar point clouds as binary ``float32`` records.
|
|
|
5
5
|
|
|
6
6
|
Return types
|
|
7
7
|
------------
|
|
8
|
+
- **rccb** -- ``torch.FloatTensor`` of shape ``(3, H, W)`` in ``[0, 1]``.
|
|
8
9
|
- **rgb** -- ``torch.FloatTensor`` of shape ``(3, H, W)`` in ``[0, 1]``.
|
|
9
10
|
- **sparse_depth** -- ``torch.FloatTensor`` of shape ``(N, 5)`` with columns
|
|
10
11
|
``x, y, z, intensity, ring``.
|
|
@@ -19,6 +20,8 @@ from __future__ import annotations
|
|
|
19
20
|
|
|
20
21
|
from typing import Any, BinaryIO, Union
|
|
21
22
|
|
|
23
|
+
import numpy as np
|
|
24
|
+
from PIL import Image
|
|
22
25
|
import torch
|
|
23
26
|
|
|
24
27
|
from euler_loading.loaders._annotations import modality_meta
|
|
@@ -32,7 +35,7 @@ from euler_loading.loaders._princeton_dense import load_sparse_depth_array
|
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
@modality_meta(
|
|
35
|
-
modality_type="
|
|
38
|
+
modality_type="rccb",
|
|
36
39
|
dtype="float32",
|
|
37
40
|
shape="CHW",
|
|
38
41
|
file_formats=[".tif", ".tiff"],
|
|
@@ -44,17 +47,35 @@ from euler_loading.loaders._princeton_dense import load_sparse_depth_array
|
|
|
44
47
|
"raw_max_value": 4095.0,
|
|
45
48
|
},
|
|
46
49
|
)
|
|
47
|
-
def
|
|
50
|
+
def rccb(
|
|
48
51
|
path: Union[str, BinaryIO],
|
|
49
52
|
meta: dict[str, Any] | None = None,
|
|
50
53
|
*,
|
|
51
54
|
attributes: dict[str, Any] | None = None,
|
|
52
55
|
) -> torch.Tensor:
|
|
53
|
-
"""Load a SeeingThroughFog 12-bit Bayer TIFF as an
|
|
56
|
+
"""Load a SeeingThroughFog 12-bit Bayer TIFF as an RCCB tensor."""
|
|
54
57
|
arr = load_rgb_array(path, meta, attributes)
|
|
55
58
|
return torch.from_numpy(arr).permute(2, 0, 1).contiguous()
|
|
56
59
|
|
|
57
60
|
|
|
61
|
+
@modality_meta(
|
|
62
|
+
modality_type="rgb",
|
|
63
|
+
dtype="float32",
|
|
64
|
+
shape="CHW",
|
|
65
|
+
file_formats=[".png"],
|
|
66
|
+
output_range=[0.0, 1.0],
|
|
67
|
+
)
|
|
68
|
+
def rgb(
|
|
69
|
+
path: Union[str, BinaryIO],
|
|
70
|
+
meta: dict[str, Any] | None = None,
|
|
71
|
+
*,
|
|
72
|
+
attributes: dict[str, Any] | None = None,
|
|
73
|
+
) -> torch.Tensor:
|
|
74
|
+
"""Load a SeeingThroughFog plain 8-bit PNG as an RGB tensor."""
|
|
75
|
+
arr = np.array(Image.open(path).convert("RGB"), dtype=np.float32) / 255.0
|
|
76
|
+
return torch.from_numpy(arr).permute(2, 0, 1).contiguous()
|
|
77
|
+
|
|
78
|
+
|
|
58
79
|
@modality_meta(
|
|
59
80
|
modality_type="sparse_depth",
|
|
60
81
|
dtype="float32",
|
|
@@ -159,6 +159,7 @@ class TestGenericDenseDepthAttributes:
|
|
|
159
159
|
|
|
160
160
|
PRINCETON_DENSE_LOADER_NAMES = [
|
|
161
161
|
"rgb",
|
|
162
|
+
"rccb",
|
|
162
163
|
"sparse_depth",
|
|
163
164
|
"read_intrinsics",
|
|
164
165
|
"read_extrinsics",
|
|
@@ -167,6 +168,14 @@ PRINCETON_DENSE_LOADER_NAMES = [
|
|
|
167
168
|
|
|
168
169
|
@pytest.fixture()
|
|
169
170
|
def princeton_dense_rgb_path(tmp_path):
|
|
171
|
+
arr = np.full((4, 4, 3), 128, dtype=np.uint8)
|
|
172
|
+
path = tmp_path / "2018-02-05_12-09-01_00000.png"
|
|
173
|
+
Image.fromarray(arr).save(path)
|
|
174
|
+
return str(path)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@pytest.fixture()
|
|
178
|
+
def princeton_dense_rccb_path(tmp_path):
|
|
170
179
|
arr = np.full((4, 4), 2048, dtype=np.uint16)
|
|
171
180
|
path = tmp_path / "2018-02-05_12-09-01_00000.tiff"
|
|
172
181
|
Image.fromarray(arr).save(path)
|
|
@@ -264,6 +273,14 @@ class TestPrincetonDenseModuleContents:
|
|
|
264
273
|
class TestPrincetonDenseGPULoaders:
|
|
265
274
|
"""GPU Princeton DENSE loaders produce torch tensors."""
|
|
266
275
|
|
|
276
|
+
def test_rccb_shape_dtype_and_range(self, princeton_dense_rccb_path):
|
|
277
|
+
result = gpu_princeton_dense.rccb(princeton_dense_rccb_path)
|
|
278
|
+
assert isinstance(result, torch.Tensor)
|
|
279
|
+
assert result.dtype == torch.float32
|
|
280
|
+
assert result.shape == (3, 4, 4)
|
|
281
|
+
assert result.min() >= 0.0
|
|
282
|
+
assert result.max() <= 1.0
|
|
283
|
+
|
|
267
284
|
def test_rgb_shape_dtype_and_range(self, princeton_dense_rgb_path):
|
|
268
285
|
result = gpu_princeton_dense.rgb(princeton_dense_rgb_path)
|
|
269
286
|
assert isinstance(result, torch.Tensor)
|
|
@@ -297,6 +314,14 @@ class TestPrincetonDenseGPULoaders:
|
|
|
297
314
|
class TestPrincetonDenseCPULoaders:
|
|
298
315
|
"""CPU Princeton DENSE loaders produce numpy arrays."""
|
|
299
316
|
|
|
317
|
+
def test_rccb_shape_dtype_and_range(self, princeton_dense_rccb_path):
|
|
318
|
+
result = cpu_princeton_dense.rccb(princeton_dense_rccb_path)
|
|
319
|
+
assert isinstance(result, np.ndarray)
|
|
320
|
+
assert result.dtype == np.float32
|
|
321
|
+
assert result.shape == (4, 4, 3)
|
|
322
|
+
assert result.min() >= 0.0
|
|
323
|
+
assert result.max() <= 1.0
|
|
324
|
+
|
|
300
325
|
def test_rgb_shape_dtype_and_range(self, princeton_dense_rgb_path):
|
|
301
326
|
result = cpu_princeton_dense.rgb(princeton_dense_rgb_path)
|
|
302
327
|
assert isinstance(result, np.ndarray)
|
|
@@ -347,6 +372,12 @@ class TestPrincetonDenseCPULoaders:
|
|
|
347
372
|
class TestPrincetonDenseBackwardCompat:
|
|
348
373
|
"""``from euler_loading.loaders import princeton_dense`` returns GPU loaders."""
|
|
349
374
|
|
|
375
|
+
def test_top_level_rccb_matches_gpu(self, princeton_dense_rccb_path):
|
|
376
|
+
assert torch.equal(
|
|
377
|
+
princeton_dense_top.rccb(princeton_dense_rccb_path),
|
|
378
|
+
gpu_princeton_dense.rccb(princeton_dense_rccb_path),
|
|
379
|
+
)
|
|
380
|
+
|
|
350
381
|
def test_top_level_rgb_matches_gpu(self, princeton_dense_rgb_path):
|
|
351
382
|
assert torch.equal(
|
|
352
383
|
princeton_dense_top.rgb(princeton_dense_rgb_path),
|
|
@@ -1148,6 +1179,7 @@ class TestRDSWriters:
|
|
|
1148
1179
|
GENERIC_LOADER_NAMES = [
|
|
1149
1180
|
"map_2d",
|
|
1150
1181
|
"map_3d",
|
|
1182
|
+
"points_3d",
|
|
1151
1183
|
"scattering_coefficient",
|
|
1152
1184
|
"atmospheric_light",
|
|
1153
1185
|
"spherical_map",
|
|
@@ -1155,6 +1187,7 @@ GENERIC_LOADER_NAMES = [
|
|
|
1155
1187
|
GENERIC_WRITER_NAMES = [
|
|
1156
1188
|
"write_map_2d",
|
|
1157
1189
|
"write_map_3d",
|
|
1190
|
+
"write_points_3d",
|
|
1158
1191
|
"write_scattering_coefficient",
|
|
1159
1192
|
"write_atmospheric_light",
|
|
1160
1193
|
"write_spherical_map",
|
|
@@ -1353,6 +1386,24 @@ def map_3d_npz_path(tmp_path):
|
|
|
1353
1386
|
return str(p), arr
|
|
1354
1387
|
|
|
1355
1388
|
|
|
1389
|
+
@pytest.fixture()
|
|
1390
|
+
def points_3d_npy_path(tmp_path):
|
|
1391
|
+
"""Write a small (3, 4, 5) float32 .npy file in 3HW layout."""
|
|
1392
|
+
arr = np.random.default_rng(4).random((3, 4, 5), dtype=np.float32)
|
|
1393
|
+
p = tmp_path / "points_3d.npy"
|
|
1394
|
+
np.save(str(p), arr)
|
|
1395
|
+
return str(p), arr
|
|
1396
|
+
|
|
1397
|
+
|
|
1398
|
+
@pytest.fixture()
|
|
1399
|
+
def points_3d_npz_path(tmp_path):
|
|
1400
|
+
"""Write a small (3, 4, 5) float32 .npz file in 3HW layout."""
|
|
1401
|
+
arr = np.random.default_rng(5).random((3, 4, 5), dtype=np.float32)
|
|
1402
|
+
p = tmp_path / "points_3d.npz"
|
|
1403
|
+
np.savez_compressed(str(p), data=arr)
|
|
1404
|
+
return str(p), arr
|
|
1405
|
+
|
|
1406
|
+
|
|
1356
1407
|
class TestGPUMap2DLoader:
|
|
1357
1408
|
"""GPU ``map_2d`` loads a 2D map as an ``(H, W)`` float32 tensor."""
|
|
1358
1409
|
|
|
@@ -1434,6 +1485,52 @@ class TestCPUMap3DLoader:
|
|
|
1434
1485
|
assert np.allclose(result, np.transpose(expected, (1, 2, 0)))
|
|
1435
1486
|
|
|
1436
1487
|
|
|
1488
|
+
class TestGPUPoints3DLoader:
|
|
1489
|
+
"""GPU ``points_3d`` loads dense 3D points as a ``(3, H, W)`` tensor."""
|
|
1490
|
+
|
|
1491
|
+
def test_npy_dtype_and_shape(self, points_3d_npy_path):
|
|
1492
|
+
path, _ = points_3d_npy_path
|
|
1493
|
+
result = gpu_generic.points_3d(path)
|
|
1494
|
+
assert isinstance(result, torch.Tensor)
|
|
1495
|
+
assert result.dtype == torch.float32
|
|
1496
|
+
assert result.shape == (3, 4, 5)
|
|
1497
|
+
|
|
1498
|
+
def test_npy_values_match(self, points_3d_npy_path):
|
|
1499
|
+
path, expected = points_3d_npy_path
|
|
1500
|
+
result = gpu_generic.points_3d(path)
|
|
1501
|
+
assert torch.allclose(result, torch.from_numpy(expected))
|
|
1502
|
+
|
|
1503
|
+
def test_npz_dtype_and_shape(self, points_3d_npz_path):
|
|
1504
|
+
path, _ = points_3d_npz_path
|
|
1505
|
+
result = gpu_generic.points_3d(path)
|
|
1506
|
+
assert result.dtype == torch.float32
|
|
1507
|
+
assert result.shape == (3, 4, 5)
|
|
1508
|
+
|
|
1509
|
+
|
|
1510
|
+
class TestCPUPoints3DLoader:
|
|
1511
|
+
"""CPU ``points_3d`` preserves the ``(3, H, W)`` dense point layout."""
|
|
1512
|
+
|
|
1513
|
+
def test_npy_dtype_and_shape(self, points_3d_npy_path):
|
|
1514
|
+
path, _ = points_3d_npy_path
|
|
1515
|
+
result = cpu_generic.points_3d(path)
|
|
1516
|
+
assert isinstance(result, np.ndarray)
|
|
1517
|
+
assert result.dtype == np.float32
|
|
1518
|
+
assert result.shape == (3, 4, 5)
|
|
1519
|
+
|
|
1520
|
+
def test_npy_values_match(self, points_3d_npy_path):
|
|
1521
|
+
path, expected = points_3d_npy_path
|
|
1522
|
+
result = cpu_generic.points_3d(path)
|
|
1523
|
+
assert np.allclose(result, expected)
|
|
1524
|
+
|
|
1525
|
+
def test_rejects_hwc_input(self, tmp_path):
|
|
1526
|
+
arr = np.random.default_rng(6).random((4, 5, 3), dtype=np.float32)
|
|
1527
|
+
path = tmp_path / "points_3d.npy"
|
|
1528
|
+
np.save(str(path), arr)
|
|
1529
|
+
|
|
1530
|
+
with pytest.raises(ValueError, match=r"points_3d must have shape"):
|
|
1531
|
+
cpu_generic.points_3d(str(path))
|
|
1532
|
+
|
|
1533
|
+
|
|
1437
1534
|
class TestMapWriters:
|
|
1438
1535
|
"""Writer round-trip tests for ``map_2d`` / ``map_3d``."""
|
|
1439
1536
|
|
|
@@ -1473,6 +1570,13 @@ class TestMapWriters:
|
|
|
1473
1570
|
loaded = gpu_generic.map_3d(str(path))
|
|
1474
1571
|
assert torch.allclose(loaded, data)
|
|
1475
1572
|
|
|
1573
|
+
def test_gpu_write_points_3d_npy_roundtrip(self, tmp_path):
|
|
1574
|
+
data = torch.rand(3, 4, 5, dtype=torch.float32)
|
|
1575
|
+
path = tmp_path / "points.npy"
|
|
1576
|
+
gpu_generic.write_points_3d(str(path), data)
|
|
1577
|
+
loaded = gpu_generic.points_3d(str(path))
|
|
1578
|
+
assert torch.allclose(loaded, data)
|
|
1579
|
+
|
|
1476
1580
|
def test_cpu_write_map_3d_npy_roundtrip(self, tmp_path):
|
|
1477
1581
|
data = np.random.default_rng(0).random((4, 5, 2)).astype(np.float32)
|
|
1478
1582
|
path = tmp_path / "m.npy"
|
|
@@ -1480,6 +1584,13 @@ class TestMapWriters:
|
|
|
1480
1584
|
loaded = cpu_generic.map_3d(str(path))
|
|
1481
1585
|
assert np.allclose(loaded, data)
|
|
1482
1586
|
|
|
1587
|
+
def test_cpu_write_points_3d_npz_roundtrip(self, tmp_path):
|
|
1588
|
+
data = np.random.default_rng(0).random((3, 4, 5)).astype(np.float32)
|
|
1589
|
+
path = tmp_path / "points.npz"
|
|
1590
|
+
cpu_generic.write_points_3d(str(path), data)
|
|
1591
|
+
loaded = cpu_generic.points_3d(str(path))
|
|
1592
|
+
assert np.allclose(loaded, data)
|
|
1593
|
+
|
|
1483
1594
|
def test_cpu_write_map_3d_npz_roundtrip(self, tmp_path):
|
|
1484
1595
|
data = np.random.default_rng(0).random((4, 5, 2)).astype(np.float32)
|
|
1485
1596
|
path = tmp_path / "m.npz"
|
|
@@ -1529,6 +1640,8 @@ class TestSpecificMapAliases:
|
|
|
1529
1640
|
|
|
1530
1641
|
def test_modality_meta_distinct_types(self):
|
|
1531
1642
|
"""Each alias carries its own modality_type even though logic is shared."""
|
|
1643
|
+
assert gpu_generic.points_3d._modality_meta["type"] == "points_3d"
|
|
1644
|
+
assert cpu_generic.points_3d._modality_meta["type"] == "points_3d"
|
|
1532
1645
|
assert (
|
|
1533
1646
|
gpu_generic.scattering_coefficient._modality_meta["type"]
|
|
1534
1647
|
== "scattering_coefficient"
|
|
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
|
{euler_loading-2.14.0 → euler_loading-2.18.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
|
|
File without changes
|
{euler_loading-2.14.0 → euler_loading-2.18.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|