euler-eval 2.11.0__tar.gz → 2.12.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_eval-2.11.0 → euler_eval-2.12.0}/PKG-INFO +9 -5
- {euler_eval-2.11.0 → euler_eval-2.12.0}/README.md +8 -4
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/cli.py +69 -15
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/config_paths.py +2 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/data.py +12 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/evaluate.py +33 -2
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval.egg-info/PKG-INFO +9 -5
- {euler_eval-2.11.0 → euler_eval-2.12.0}/pyproject.toml +1 -1
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_config.py +29 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_data_builders.py +23 -2
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_save_results.py +12 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_sparse_depth.py +60 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/__init__.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/__init__.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/absrel.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/daniel_error.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/depth_binned_error.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/depth_standard.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/fid_kid.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/high_freq_energy.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/lpips_metric.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/normal_consistency.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/psnr.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/rgb_lpips.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/rho_a.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/rmse.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/ssim.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/tail_errors.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/metrics/utils.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/sanity_checker.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval/utils/hierarchy_parser.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval.egg-info/SOURCES.txt +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval.egg-info/dependency_links.txt +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval.egg-info/entry_points.txt +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval.egg-info/requires.txt +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/euler_eval.egg-info/top_level.txt +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/init_cache.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/setup.cfg +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_alignment.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_cli_device.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_data.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_depth_alignment_output.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_depth_standard.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_evaluate_helpers.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_init_cache.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_integration.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_meta_output.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_metrics_utils.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_rgb_fid_output.py +0 -0
- {euler_eval-2.11.0 → euler_eval-2.12.0}/tests/test_rho_a.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-eval
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.12.0
|
|
4
4
|
Summary: Depth map evaluation toolkit with comprehensive metrics
|
|
5
5
|
Author: Depth Eval Contributors
|
|
6
6
|
License: MIT
|
|
@@ -241,7 +241,7 @@ Defines GT modalities, prediction datasets to evaluate, and optional euler_train
|
|
|
241
241
|
|
|
242
242
|
Each modality entry can optionally include a `split` field to select a specific split from the dataset (e.g. `{ "path": "/data/gt/depth", "split": "test" }`). euler-loading inline selectors are also accepted in `path`, such as `/data/muses.zip:test` or `/data/muses.zip:test#scope=rgb`.
|
|
243
243
|
|
|
244
|
-
For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.depth`. The prediction
|
|
244
|
+
For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.depth`. The prediction uses a dense depth-like map under `datasets[].depth`, `datasets[].relative_depth`, or `datasets[].affine_depth`. The evaluator projects the sparse GT point cloud into the prediction image plane using `gt.intrinsics` and `gt.camera_extrinsics`, then computes pointwise depth metrics only at projected valid pixels.
|
|
245
245
|
|
|
246
246
|
#### GT section
|
|
247
247
|
|
|
@@ -261,17 +261,21 @@ For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.dep
|
|
|
261
261
|
|
|
262
262
|
#### Prediction datasets
|
|
263
263
|
|
|
264
|
-
Each entry in `datasets` can include `rgb`, `depth`, `rays`, or any combination:
|
|
264
|
+
Each entry in `datasets` can include `rgb`, one dense depth-like prediction (`depth`, `relative_depth`, or `affine_depth`), `rays`, or any combination:
|
|
265
265
|
|
|
266
266
|
| Field | Required | Description |
|
|
267
267
|
|---|---|---|
|
|
268
268
|
| `name` | yes | Display name for this prediction dataset |
|
|
269
269
|
| `rgb.path` | no\* | Path to predicted RGB dataset |
|
|
270
|
-
| `depth.path` | no\* | Path to predicted dense depth dataset; also used when evaluating against sparse pointcloud GT |
|
|
270
|
+
| `depth.path` | no\* | Path to predicted dense metric depth dataset; also used when evaluating against sparse pointcloud GT |
|
|
271
|
+
| `relative_depth.path` | no\* | Path to predicted dense relative depth dataset; evaluated through the same depth pipeline with scale/shift alignment support |
|
|
272
|
+
| `affine_depth.path` | no\* | Path to predicted dense affine-depth dataset; evaluated through the same depth pipeline with scale/shift alignment support |
|
|
271
273
|
| `rays.path` | no\* | Path to predicted ray direction map dataset |
|
|
272
274
|
| `output_file` | no | Custom output path for results JSON (default: `eval.json` inside the first available modality path) |
|
|
273
275
|
|
|
274
|
-
\* At least one of `rgb.path`, `depth.path`, or `rays.path` is required.
|
|
276
|
+
\* At least one of `rgb.path`, `depth.path`, `relative_depth.path`, `affine_depth.path`, or `rays.path` is required. Use only one dense depth-like entry per prediction dataset.
|
|
277
|
+
|
|
278
|
+
When `relative_depth` or `affine_depth` is used, `--depth-alignment auto_affine` treats the entry as declared non-metric depth and runs scale/shift alignment even if the raw value range is not normalized. `--depth-alignment none` still disables calibration.
|
|
275
279
|
|
|
276
280
|
#### `euler_train` section (optional)
|
|
277
281
|
|
|
@@ -203,7 +203,7 @@ Defines GT modalities, prediction datasets to evaluate, and optional euler_train
|
|
|
203
203
|
|
|
204
204
|
Each modality entry can optionally include a `split` field to select a specific split from the dataset (e.g. `{ "path": "/data/gt/depth", "split": "test" }`). euler-loading inline selectors are also accepted in `path`, such as `/data/muses.zip:test` or `/data/muses.zip:test#scope=rgb`.
|
|
205
205
|
|
|
206
|
-
For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.depth`. The prediction
|
|
206
|
+
For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.depth`. The prediction uses a dense depth-like map under `datasets[].depth`, `datasets[].relative_depth`, or `datasets[].affine_depth`. The evaluator projects the sparse GT point cloud into the prediction image plane using `gt.intrinsics` and `gt.camera_extrinsics`, then computes pointwise depth metrics only at projected valid pixels.
|
|
207
207
|
|
|
208
208
|
#### GT section
|
|
209
209
|
|
|
@@ -223,17 +223,21 @@ For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.dep
|
|
|
223
223
|
|
|
224
224
|
#### Prediction datasets
|
|
225
225
|
|
|
226
|
-
Each entry in `datasets` can include `rgb`, `depth`, `rays`, or any combination:
|
|
226
|
+
Each entry in `datasets` can include `rgb`, one dense depth-like prediction (`depth`, `relative_depth`, or `affine_depth`), `rays`, or any combination:
|
|
227
227
|
|
|
228
228
|
| Field | Required | Description |
|
|
229
229
|
|---|---|---|
|
|
230
230
|
| `name` | yes | Display name for this prediction dataset |
|
|
231
231
|
| `rgb.path` | no\* | Path to predicted RGB dataset |
|
|
232
|
-
| `depth.path` | no\* | Path to predicted dense depth dataset; also used when evaluating against sparse pointcloud GT |
|
|
232
|
+
| `depth.path` | no\* | Path to predicted dense metric depth dataset; also used when evaluating against sparse pointcloud GT |
|
|
233
|
+
| `relative_depth.path` | no\* | Path to predicted dense relative depth dataset; evaluated through the same depth pipeline with scale/shift alignment support |
|
|
234
|
+
| `affine_depth.path` | no\* | Path to predicted dense affine-depth dataset; evaluated through the same depth pipeline with scale/shift alignment support |
|
|
233
235
|
| `rays.path` | no\* | Path to predicted ray direction map dataset |
|
|
234
236
|
| `output_file` | no | Custom output path for results JSON (default: `eval.json` inside the first available modality path) |
|
|
235
237
|
|
|
236
|
-
\* At least one of `rgb.path`, `depth.path`, or `rays.path` is required.
|
|
238
|
+
\* At least one of `rgb.path`, `depth.path`, `relative_depth.path`, `affine_depth.path`, or `rays.path` is required. Use only one dense depth-like entry per prediction dataset.
|
|
239
|
+
|
|
240
|
+
When `relative_depth` or `affine_depth` is used, `--depth-alignment auto_affine` treats the entry as declared non-metric depth and runs scale/shift alignment even if the raw value range is not normalized. `--depth-alignment none` still disables calibration.
|
|
237
241
|
|
|
238
242
|
#### `euler_train` section (optional)
|
|
239
243
|
|
|
@@ -151,6 +151,8 @@ def _rgb_eval_axes(*, benchmark: bool = False) -> dict[str, AxisDeclaration]:
|
|
|
151
151
|
|
|
152
152
|
_RAYS_EVAL_AXES: dict[str, AxisDeclaration] = {}
|
|
153
153
|
|
|
154
|
+
_PRED_DEPTH_KEYS = ("depth", "relative_depth", "affine_depth")
|
|
155
|
+
|
|
154
156
|
# Downstream eval consumers validate metricSet.metricNamespace with a stricter
|
|
155
157
|
# first-segment rule than euler_metric_naming's modality validator. Keep the
|
|
156
158
|
# public Python sparse_depth result keys, but use a wire-compatible metric root
|
|
@@ -562,6 +564,34 @@ def print_device_info(requested_device: str, resolved_device: str) -> None:
|
|
|
562
564
|
pass
|
|
563
565
|
|
|
564
566
|
|
|
567
|
+
def _prediction_depth_entry(
|
|
568
|
+
entry: dict, *, label: str = "Prediction dataset"
|
|
569
|
+
) -> tuple[str | None, dict | None]:
|
|
570
|
+
"""Return the configured dense-depth prediction entry, if any."""
|
|
571
|
+
matches = [
|
|
572
|
+
key
|
|
573
|
+
for key in _PRED_DEPTH_KEYS
|
|
574
|
+
if key in entry and "path" in entry.get(key, {})
|
|
575
|
+
]
|
|
576
|
+
if not matches:
|
|
577
|
+
return None, None
|
|
578
|
+
if len(matches) > 1:
|
|
579
|
+
raise ValueError(
|
|
580
|
+
f"{label} contains multiple dense depth entries "
|
|
581
|
+
f"{matches}. Use only one of {list(_PRED_DEPTH_KEYS)}."
|
|
582
|
+
)
|
|
583
|
+
key = matches[0]
|
|
584
|
+
return key, entry[key]
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def _prediction_depth_space_hint(key: str | None) -> str | None:
|
|
588
|
+
if key == "relative_depth":
|
|
589
|
+
return "relative"
|
|
590
|
+
if key == "affine_depth":
|
|
591
|
+
return "affine"
|
|
592
|
+
return None
|
|
593
|
+
|
|
594
|
+
|
|
565
595
|
def validate_gt_config(gt: dict) -> None:
|
|
566
596
|
"""Validate the ``gt`` section of the configuration.
|
|
567
597
|
|
|
@@ -619,14 +649,16 @@ def validate_dataset_entry(entry: dict, index: int) -> None:
|
|
|
619
649
|
raise ValueError(f"{label} must have a 'name' field")
|
|
620
650
|
|
|
621
651
|
has_rgb = "rgb" in entry and "path" in entry.get("rgb", {})
|
|
622
|
-
|
|
652
|
+
depth_key, _ = _prediction_depth_entry(entry, label=label)
|
|
653
|
+
has_depth = depth_key is not None
|
|
623
654
|
has_rays = "rays" in entry and "path" in entry.get("rays", {})
|
|
624
655
|
if not has_rgb and not has_depth and not has_rays:
|
|
625
656
|
raise ValueError(
|
|
626
|
-
f"{label} must have at least 'rgb.path', 'depth.path',
|
|
657
|
+
f"{label} must have at least 'rgb.path', 'depth.path', "
|
|
658
|
+
"'relative_depth.path', 'affine_depth.path', or 'rays.path'"
|
|
627
659
|
)
|
|
628
660
|
|
|
629
|
-
for modality in ("rgb",
|
|
661
|
+
for modality in ("rgb", *_PRED_DEPTH_KEYS, "rays"):
|
|
630
662
|
if modality in entry and "path" in entry[modality]:
|
|
631
663
|
p = normalize_modality_path(
|
|
632
664
|
entry[modality]["path"],
|
|
@@ -751,21 +783,24 @@ def save_results(
|
|
|
751
783
|
"""
|
|
752
784
|
output_file = dataset_config.get("output_file")
|
|
753
785
|
if output_file is None:
|
|
786
|
+
selected_modality = modality
|
|
787
|
+
if selected_modality == "depth" and "depth" not in dataset_config:
|
|
788
|
+
selected_modality, _ = _prediction_depth_entry(dataset_config)
|
|
754
789
|
if (
|
|
755
|
-
|
|
756
|
-
and
|
|
757
|
-
and "path" in dataset_config[
|
|
790
|
+
selected_modality is not None
|
|
791
|
+
and selected_modality in dataset_config
|
|
792
|
+
and "path" in dataset_config[selected_modality]
|
|
758
793
|
):
|
|
759
794
|
output_file = (
|
|
760
795
|
normalize_modality_path(
|
|
761
|
-
dataset_config[
|
|
762
|
-
split=dataset_config[
|
|
796
|
+
dataset_config[selected_modality]["path"],
|
|
797
|
+
split=dataset_config[selected_modality].get("split"),
|
|
763
798
|
)
|
|
764
799
|
/ "eval.json"
|
|
765
800
|
)
|
|
766
801
|
else:
|
|
767
802
|
# Default: save alongside first available modality path
|
|
768
|
-
for mod in (
|
|
803
|
+
for mod in (*_PRED_DEPTH_KEYS, "rgb", "rays"):
|
|
769
804
|
if mod in dataset_config and "path" in dataset_config[mod]:
|
|
770
805
|
output_file = (
|
|
771
806
|
normalize_modality_path(
|
|
@@ -988,7 +1023,8 @@ def main():
|
|
|
988
1023
|
# Evaluate each prediction dataset
|
|
989
1024
|
for dataset_config in config["datasets"]:
|
|
990
1025
|
ds_name = dataset_config["name"]
|
|
991
|
-
|
|
1026
|
+
pred_depth_key, pred_depth_config = _prediction_depth_entry(dataset_config)
|
|
1027
|
+
has_depth = pred_depth_config is not None
|
|
992
1028
|
has_rgb = "rgb" in dataset_config and "path" in dataset_config["rgb"]
|
|
993
1029
|
has_rays = "rays" in dataset_config and "path" in dataset_config["rays"]
|
|
994
1030
|
|
|
@@ -1011,17 +1047,22 @@ def main():
|
|
|
1011
1047
|
and not gt_sparse_depth_path
|
|
1012
1048
|
and not args.skip_depth
|
|
1013
1049
|
):
|
|
1014
|
-
pred_depth_path =
|
|
1015
|
-
pred_depth_split =
|
|
1050
|
+
pred_depth_path = pred_depth_config["path"]
|
|
1051
|
+
pred_depth_split = pred_depth_config.get("split")
|
|
1016
1052
|
print(f"\n[DEPTH] Evaluating: '{ds_name}'")
|
|
1017
1053
|
print(f" GT: {gt_depth_path}")
|
|
1018
1054
|
print(f" Pred: {pred_depth_path}")
|
|
1055
|
+
if pred_depth_key != "depth":
|
|
1056
|
+
print(f" Pred depth entry: {pred_depth_key}")
|
|
1019
1057
|
|
|
1020
1058
|
depth_dataset = build_depth_eval_dataset(
|
|
1021
1059
|
gt_depth_path=gt_depth_path,
|
|
1022
1060
|
pred_depth_path=pred_depth_path,
|
|
1023
1061
|
calibration_path=calibration_path,
|
|
1024
1062
|
segmentation_path=segmentation_path,
|
|
1063
|
+
pred_depth_metadata_scope=(
|
|
1064
|
+
pred_depth_key if pred_depth_key != "depth" else None
|
|
1065
|
+
),
|
|
1025
1066
|
gt_depth_split=gt_depth_split,
|
|
1026
1067
|
pred_depth_split=pred_depth_split,
|
|
1027
1068
|
calibration_split=calibration_split,
|
|
@@ -1050,6 +1091,7 @@ def main():
|
|
|
1050
1091
|
if args.benchmark_depth_range
|
|
1051
1092
|
else None
|
|
1052
1093
|
),
|
|
1094
|
+
input_space_hint=_prediction_depth_space_hint(pred_depth_key),
|
|
1053
1095
|
)
|
|
1054
1096
|
|
|
1055
1097
|
if sanity_checker is not None:
|
|
@@ -1101,6 +1143,7 @@ def main():
|
|
|
1101
1143
|
"pred": {
|
|
1102
1144
|
"path": pred_depth_path,
|
|
1103
1145
|
"split": pred_depth_split,
|
|
1146
|
+
"entry": pred_depth_key,
|
|
1104
1147
|
"dimensions": depth_spatial.get("pred_dimensions"),
|
|
1105
1148
|
},
|
|
1106
1149
|
"spatial_alignment": {
|
|
@@ -1190,11 +1233,13 @@ def main():
|
|
|
1190
1233
|
# -- Sparse pointcloud depth evaluation --
|
|
1191
1234
|
sparse_depth_dataset = None
|
|
1192
1235
|
if has_depth and gt_sparse_depth_path and not args.skip_depth:
|
|
1193
|
-
pred_depth_path =
|
|
1194
|
-
pred_depth_split =
|
|
1236
|
+
pred_depth_path = pred_depth_config["path"]
|
|
1237
|
+
pred_depth_split = pred_depth_config.get("split")
|
|
1195
1238
|
print(f"\n[SPARSE_DEPTH] Evaluating: '{ds_name}'")
|
|
1196
1239
|
print(f" GT sparse pointcloud: {gt_sparse_depth_path}")
|
|
1197
1240
|
print(f" Pred dense depth: {pred_depth_path}")
|
|
1241
|
+
if pred_depth_key != "depth":
|
|
1242
|
+
print(f" Pred depth entry: {pred_depth_key}")
|
|
1198
1243
|
print(f" Intrinsics: {intrinsics_path}")
|
|
1199
1244
|
print(f" Camera extrinsics: {camera_extrinsics_path}")
|
|
1200
1245
|
|
|
@@ -1204,6 +1249,9 @@ def main():
|
|
|
1204
1249
|
intrinsics_path=intrinsics_path,
|
|
1205
1250
|
camera_extrinsics_path=camera_extrinsics_path,
|
|
1206
1251
|
segmentation_path=segmentation_path,
|
|
1252
|
+
pred_depth_metadata_scope=(
|
|
1253
|
+
pred_depth_key if pred_depth_key != "depth" else None
|
|
1254
|
+
),
|
|
1207
1255
|
gt_sparse_depth_split=gt_sparse_depth_split,
|
|
1208
1256
|
pred_depth_split=pred_depth_split,
|
|
1209
1257
|
intrinsics_split=intrinsics_split,
|
|
@@ -1231,6 +1279,7 @@ def main():
|
|
|
1231
1279
|
if args.benchmark_depth_range
|
|
1232
1280
|
else None
|
|
1233
1281
|
),
|
|
1282
|
+
input_space_hint=_prediction_depth_space_hint(pred_depth_key),
|
|
1234
1283
|
)
|
|
1235
1284
|
|
|
1236
1285
|
if sanity_checker is not None:
|
|
@@ -1277,6 +1326,7 @@ def main():
|
|
|
1277
1326
|
"pred": {
|
|
1278
1327
|
"path": pred_depth_path,
|
|
1279
1328
|
"split": pred_depth_split,
|
|
1329
|
+
"entry": pred_depth_key,
|
|
1280
1330
|
"dimensions": sparse_depth_spatial.get("pred_dimensions"),
|
|
1281
1331
|
},
|
|
1282
1332
|
"calibration": {
|
|
@@ -1632,7 +1682,11 @@ def main():
|
|
|
1632
1682
|
|
|
1633
1683
|
# Save per-modality results to respective dataset paths
|
|
1634
1684
|
if depth_save:
|
|
1635
|
-
depth_out = save_results(
|
|
1685
|
+
depth_out = save_results(
|
|
1686
|
+
depth_save,
|
|
1687
|
+
dataset_config,
|
|
1688
|
+
modality=pred_depth_key or "depth",
|
|
1689
|
+
)
|
|
1636
1690
|
depth_label = (
|
|
1637
1691
|
"Sparse depth"
|
|
1638
1692
|
if _SPARSE_DEPTH_METRIC_ROOT in depth_save
|
|
@@ -107,6 +107,7 @@ def build_modality(
|
|
|
107
107
|
path: str | Path,
|
|
108
108
|
modality_key: str,
|
|
109
109
|
split: str | None = None,
|
|
110
|
+
metadata_scope: str | None = None,
|
|
110
111
|
loader=None,
|
|
111
112
|
used_as: str | None = None,
|
|
112
113
|
) -> Modality:
|
|
@@ -114,6 +115,7 @@ def build_modality(
|
|
|
114
115
|
parsed = parse_modality_path(
|
|
115
116
|
path,
|
|
116
117
|
split=split,
|
|
118
|
+
metadata_scope=metadata_scope,
|
|
117
119
|
)
|
|
118
120
|
return Modality(
|
|
119
121
|
path=parsed.path,
|
|
@@ -571,6 +571,7 @@ def _modality(
|
|
|
571
571
|
path: str,
|
|
572
572
|
modality_key: str,
|
|
573
573
|
split: Optional[str] = None,
|
|
574
|
+
metadata_scope: Optional[str] = None,
|
|
574
575
|
loader: Optional[Callable[..., Any]] = None,
|
|
575
576
|
used_as: Optional[str] = None,
|
|
576
577
|
) -> Modality:
|
|
@@ -580,6 +581,7 @@ def _modality(
|
|
|
580
581
|
loader=loader,
|
|
581
582
|
used_as=used_as,
|
|
582
583
|
modality_key=modality_key,
|
|
584
|
+
metadata_scope=metadata_scope,
|
|
583
585
|
split=split,
|
|
584
586
|
)
|
|
585
587
|
|
|
@@ -593,6 +595,7 @@ def build_depth_eval_dataset(
|
|
|
593
595
|
pred_depth_split: Optional[str] = None,
|
|
594
596
|
calibration_split: Optional[str] = None,
|
|
595
597
|
segmentation_split: Optional[str] = None,
|
|
598
|
+
pred_depth_metadata_scope: Optional[str] = None,
|
|
596
599
|
) -> MultiModalDataset:
|
|
597
600
|
"""Build a MultiModalDataset for depth evaluation.
|
|
598
601
|
|
|
@@ -611,6 +614,9 @@ def build_depth_eval_dataset(
|
|
|
611
614
|
pred_depth_split: Optional split name for the prediction depth modality.
|
|
612
615
|
calibration_split: Optional split name for the calibration modality.
|
|
613
616
|
segmentation_split: Optional split name for the segmentation modality.
|
|
617
|
+
pred_depth_metadata_scope: Optional metadata scope for the prediction
|
|
618
|
+
depth modality, useful when loading depth-like outputs such as
|
|
619
|
+
``relative_depth`` or ``affine_depth`` through the depth loader.
|
|
614
620
|
|
|
615
621
|
Returns:
|
|
616
622
|
A MultiModalDataset instance.
|
|
@@ -624,6 +630,7 @@ def build_depth_eval_dataset(
|
|
|
624
630
|
"pred": _modality(
|
|
625
631
|
path=pred_depth_path,
|
|
626
632
|
modality_key="depth",
|
|
633
|
+
metadata_scope=pred_depth_metadata_scope,
|
|
627
634
|
used_as="output",
|
|
628
635
|
split=pred_depth_split,
|
|
629
636
|
),
|
|
@@ -662,12 +669,16 @@ def build_sparse_depth_eval_dataset(
|
|
|
662
669
|
intrinsics_split: Optional[str] = None,
|
|
663
670
|
camera_extrinsics_split: Optional[str] = None,
|
|
664
671
|
segmentation_split: Optional[str] = None,
|
|
672
|
+
pred_depth_metadata_scope: Optional[str] = None,
|
|
665
673
|
) -> MultiModalDataset:
|
|
666
674
|
"""Build a MultiModalDataset for sparse pointcloud depth evaluation.
|
|
667
675
|
|
|
668
676
|
The returned dataset yields dense predicted depth under ``"pred"``,
|
|
669
677
|
sparse GT point clouds under ``"gt"``, and hierarchical camera
|
|
670
678
|
calibration under ``"intrinsics"`` and ``"camera_extrinsics"``.
|
|
679
|
+
``pred_depth_metadata_scope`` can select a depth-like prediction scope
|
|
680
|
+
such as ``relative_depth`` or ``affine_depth`` while still loading it
|
|
681
|
+
as a dense depth map.
|
|
671
682
|
"""
|
|
672
683
|
modalities = {
|
|
673
684
|
"gt": _modality(
|
|
@@ -678,6 +689,7 @@ def build_sparse_depth_eval_dataset(
|
|
|
678
689
|
"pred": _modality(
|
|
679
690
|
path=pred_depth_path,
|
|
680
691
|
modality_key="depth",
|
|
692
|
+
metadata_scope=pred_depth_metadata_scope,
|
|
681
693
|
used_as="output",
|
|
682
694
|
split=pred_depth_split,
|
|
683
695
|
),
|
|
@@ -552,6 +552,7 @@ def evaluate_depth_samples(
|
|
|
552
552
|
sky_mask_enabled: bool = False,
|
|
553
553
|
alignment_mode: str = "auto_affine",
|
|
554
554
|
benchmark_depth_range: Optional[tuple[float, float]] = None,
|
|
555
|
+
input_space_hint: Optional[str] = None,
|
|
555
556
|
) -> dict:
|
|
556
557
|
"""Evaluate all depth metrics from a MultiModalDataset.
|
|
557
558
|
|
|
@@ -574,6 +575,9 @@ def evaluate_depth_samples(
|
|
|
574
575
|
benchmark_depth_range: Optional ``(min_meters, max_meters)`` tuple.
|
|
575
576
|
When set, also computes depth metrics for pixels within this
|
|
576
577
|
range, subdivided into square-root-scaled near/mid/far bins.
|
|
578
|
+
input_space_hint: Optional declaration from the prediction config.
|
|
579
|
+
``relative`` or ``affine`` makes ``auto_affine`` run alignment
|
|
580
|
+
even when values are outside the normalized range.
|
|
577
581
|
|
|
578
582
|
Returns:
|
|
579
583
|
Dictionary containing depth aggregate/per-file metrics with:
|
|
@@ -587,6 +591,12 @@ def evaluate_depth_samples(
|
|
|
587
591
|
f"Invalid alignment_mode '{alignment_mode}'. "
|
|
588
592
|
f"Expected one of {sorted(valid_alignment_modes)}."
|
|
589
593
|
)
|
|
594
|
+
valid_input_space_hints = {None, "relative", "affine"}
|
|
595
|
+
if input_space_hint not in valid_input_space_hints:
|
|
596
|
+
raise ValueError(
|
|
597
|
+
f"Invalid input_space_hint '{input_space_hint}'. "
|
|
598
|
+
"Expected None, 'relative', or 'affine'."
|
|
599
|
+
)
|
|
590
600
|
|
|
591
601
|
num_samples = len(dataset)
|
|
592
602
|
if num_samples == 0:
|
|
@@ -1007,7 +1017,14 @@ def evaluate_depth_samples(
|
|
|
1007
1017
|
if i == 0:
|
|
1008
1018
|
pred_min = float(np.nanmin(depth_pred))
|
|
1009
1019
|
pred_max = float(np.nanmax(depth_pred))
|
|
1010
|
-
if
|
|
1020
|
+
if input_space_hint in {"relative", "affine"}:
|
|
1021
|
+
normalized_predictions = True
|
|
1022
|
+
input_space_detected = input_space_hint
|
|
1023
|
+
print(
|
|
1024
|
+
f" Detected native depth space: {input_space_hint} "
|
|
1025
|
+
f"(declared; range [{pred_min:.3f}, {pred_max:.3f}])"
|
|
1026
|
+
)
|
|
1027
|
+
elif pred_max <= 1.0 + 1e-3 and pred_min >= -1.0 - 1e-3:
|
|
1011
1028
|
normalized_predictions = True
|
|
1012
1029
|
input_space_detected = "normalized"
|
|
1013
1030
|
print(
|
|
@@ -1496,6 +1513,7 @@ def evaluate_sparse_depth_samples(
|
|
|
1496
1513
|
sky_mask_enabled: bool = False,
|
|
1497
1514
|
alignment_mode: str = "auto_affine",
|
|
1498
1515
|
benchmark_depth_range: Optional[tuple[float, float]] = None,
|
|
1516
|
+
input_space_hint: Optional[str] = None,
|
|
1499
1517
|
) -> dict:
|
|
1500
1518
|
"""Evaluate dense depth predictions against sparse pointcloud GT.
|
|
1501
1519
|
|
|
@@ -1510,6 +1528,12 @@ def evaluate_sparse_depth_samples(
|
|
|
1510
1528
|
f"Invalid alignment_mode '{alignment_mode}'. "
|
|
1511
1529
|
f"Expected one of {sorted(valid_alignment_modes)}."
|
|
1512
1530
|
)
|
|
1531
|
+
valid_input_space_hints = {None, "relative", "affine"}
|
|
1532
|
+
if input_space_hint not in valid_input_space_hints:
|
|
1533
|
+
raise ValueError(
|
|
1534
|
+
f"Invalid input_space_hint '{input_space_hint}'. "
|
|
1535
|
+
"Expected None, 'relative', or 'affine'."
|
|
1536
|
+
)
|
|
1513
1537
|
|
|
1514
1538
|
num_samples = len(dataset)
|
|
1515
1539
|
if num_samples == 0:
|
|
@@ -1700,7 +1724,14 @@ def evaluate_sparse_depth_samples(
|
|
|
1700
1724
|
if i == 0:
|
|
1701
1725
|
pred_native_dims = depth_pred.shape[:2]
|
|
1702
1726
|
finite_pred = depth_pred[np.isfinite(depth_pred)]
|
|
1703
|
-
if
|
|
1727
|
+
if input_space_hint in {"relative", "affine"} and finite_pred.size:
|
|
1728
|
+
normalized_predictions = True
|
|
1729
|
+
input_space_detected = input_space_hint
|
|
1730
|
+
print(
|
|
1731
|
+
f" Detected native depth space: {input_space_hint} "
|
|
1732
|
+
f"(declared; range [{float(finite_pred.min()):.3f}, {float(finite_pred.max()):.3f}])"
|
|
1733
|
+
)
|
|
1734
|
+
elif finite_pred.size and finite_pred.max() <= 1.0 + 1e-3 and finite_pred.min() >= -1.0 - 1e-3:
|
|
1704
1735
|
normalized_predictions = True
|
|
1705
1736
|
input_space_detected = "normalized"
|
|
1706
1737
|
print(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-eval
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.12.0
|
|
4
4
|
Summary: Depth map evaluation toolkit with comprehensive metrics
|
|
5
5
|
Author: Depth Eval Contributors
|
|
6
6
|
License: MIT
|
|
@@ -241,7 +241,7 @@ Defines GT modalities, prediction datasets to evaluate, and optional euler_train
|
|
|
241
241
|
|
|
242
242
|
Each modality entry can optionally include a `split` field to select a specific split from the dataset (e.g. `{ "path": "/data/gt/depth", "split": "test" }`). euler-loading inline selectors are also accepted in `path`, such as `/data/muses.zip:test` or `/data/muses.zip:test#scope=rgb`.
|
|
243
243
|
|
|
244
|
-
For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.depth`. The prediction
|
|
244
|
+
For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.depth`. The prediction uses a dense depth-like map under `datasets[].depth`, `datasets[].relative_depth`, or `datasets[].affine_depth`. The evaluator projects the sparse GT point cloud into the prediction image plane using `gt.intrinsics` and `gt.camera_extrinsics`, then computes pointwise depth metrics only at projected valid pixels.
|
|
245
245
|
|
|
246
246
|
#### GT section
|
|
247
247
|
|
|
@@ -261,17 +261,21 @@ For sparse pointcloud depth evaluation, use `gt.sparse_depth` instead of `gt.dep
|
|
|
261
261
|
|
|
262
262
|
#### Prediction datasets
|
|
263
263
|
|
|
264
|
-
Each entry in `datasets` can include `rgb`, `depth`, `rays`, or any combination:
|
|
264
|
+
Each entry in `datasets` can include `rgb`, one dense depth-like prediction (`depth`, `relative_depth`, or `affine_depth`), `rays`, or any combination:
|
|
265
265
|
|
|
266
266
|
| Field | Required | Description |
|
|
267
267
|
|---|---|---|
|
|
268
268
|
| `name` | yes | Display name for this prediction dataset |
|
|
269
269
|
| `rgb.path` | no\* | Path to predicted RGB dataset |
|
|
270
|
-
| `depth.path` | no\* | Path to predicted dense depth dataset; also used when evaluating against sparse pointcloud GT |
|
|
270
|
+
| `depth.path` | no\* | Path to predicted dense metric depth dataset; also used when evaluating against sparse pointcloud GT |
|
|
271
|
+
| `relative_depth.path` | no\* | Path to predicted dense relative depth dataset; evaluated through the same depth pipeline with scale/shift alignment support |
|
|
272
|
+
| `affine_depth.path` | no\* | Path to predicted dense affine-depth dataset; evaluated through the same depth pipeline with scale/shift alignment support |
|
|
271
273
|
| `rays.path` | no\* | Path to predicted ray direction map dataset |
|
|
272
274
|
| `output_file` | no | Custom output path for results JSON (default: `eval.json` inside the first available modality path) |
|
|
273
275
|
|
|
274
|
-
\* At least one of `rgb.path`, `depth.path`, or `rays.path` is required.
|
|
276
|
+
\* At least one of `rgb.path`, `depth.path`, `relative_depth.path`, `affine_depth.path`, or `rays.path` is required. Use only one dense depth-like entry per prediction dataset.
|
|
277
|
+
|
|
278
|
+
When `relative_depth` or `affine_depth` is used, `--depth-alignment auto_affine` treats the entry as declared non-metric depth and runs scale/shift alignment even if the raw value range is not normalized. `--depth-alignment none` still disables calibration.
|
|
275
279
|
|
|
276
280
|
#### `euler_train` section (optional)
|
|
277
281
|
|
|
@@ -127,6 +127,35 @@ class TestValidateDatasetEntry:
|
|
|
127
127
|
}
|
|
128
128
|
validate_dataset_entry(entry, 0)
|
|
129
129
|
|
|
130
|
+
def test_valid_relative_depth_only(self, tmp_path):
|
|
131
|
+
depth_path = tmp_path / "relative_depth"
|
|
132
|
+
depth_path.mkdir()
|
|
133
|
+
entry = {
|
|
134
|
+
"name": "model_a",
|
|
135
|
+
"relative_depth": {"path": str(depth_path)},
|
|
136
|
+
}
|
|
137
|
+
validate_dataset_entry(entry, 0)
|
|
138
|
+
|
|
139
|
+
def test_valid_affine_depth_only(self, tmp_path):
|
|
140
|
+
depth_path = tmp_path / "affine_depth"
|
|
141
|
+
depth_path.mkdir()
|
|
142
|
+
entry = {
|
|
143
|
+
"name": "model_a",
|
|
144
|
+
"affine_depth": {"path": str(depth_path)},
|
|
145
|
+
}
|
|
146
|
+
validate_dataset_entry(entry, 0)
|
|
147
|
+
|
|
148
|
+
def test_multiple_depth_prediction_entries_are_rejected(self, tmp_path):
|
|
149
|
+
for name in ("depth", "relative_depth"):
|
|
150
|
+
(tmp_path / name).mkdir()
|
|
151
|
+
entry = {
|
|
152
|
+
"name": "model_a",
|
|
153
|
+
"depth": {"path": str(tmp_path / "depth")},
|
|
154
|
+
"relative_depth": {"path": str(tmp_path / "relative_depth")},
|
|
155
|
+
}
|
|
156
|
+
with pytest.raises(ValueError, match="multiple dense depth entries"):
|
|
157
|
+
validate_dataset_entry(entry, 0)
|
|
158
|
+
|
|
130
159
|
def test_valid_rgb_only(self, tmp_path):
|
|
131
160
|
rgb_path = tmp_path / "rgb"
|
|
132
161
|
rgb_path.mkdir()
|
|
@@ -15,8 +15,10 @@ def _install_captured_dataset(monkeypatch):
|
|
|
15
15
|
monkeypatch.setattr(data, "MultiModalDataset", _CapturedDataset)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def _assert_modality(
|
|
19
|
-
|
|
18
|
+
def _assert_modality(
|
|
19
|
+
modality, *, key, split=None, used_as=None, loader=None, scope=None
|
|
20
|
+
):
|
|
21
|
+
assert modality.metadata_scope == (scope or key)
|
|
20
22
|
assert modality.modality_type == key
|
|
21
23
|
assert modality.split == split
|
|
22
24
|
assert modality.used_as == used_as
|
|
@@ -100,6 +102,25 @@ def test_sparse_depth_builder_sets_projection_modality_scopes(monkeypatch):
|
|
|
100
102
|
)
|
|
101
103
|
|
|
102
104
|
|
|
105
|
+
def test_sparse_depth_builder_can_load_relative_depth_prediction_scope(monkeypatch):
|
|
106
|
+
_install_captured_dataset(monkeypatch)
|
|
107
|
+
|
|
108
|
+
dataset = data.build_sparse_depth_eval_dataset(
|
|
109
|
+
gt_sparse_depth_path="/datasets/shared",
|
|
110
|
+
pred_depth_path="/predictions/shared",
|
|
111
|
+
intrinsics_path="/datasets/shared",
|
|
112
|
+
camera_extrinsics_path="/datasets/shared",
|
|
113
|
+
pred_depth_metadata_scope="relative_depth",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
_assert_modality(
|
|
117
|
+
dataset.modalities["pred"],
|
|
118
|
+
key="depth",
|
|
119
|
+
scope="relative_depth",
|
|
120
|
+
used_as="output",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
103
124
|
def test_rgb_builder_sets_rgb_and_auxiliary_modality_scopes(monkeypatch):
|
|
104
125
|
_install_captured_dataset(monkeypatch)
|
|
105
126
|
|
|
@@ -126,6 +126,18 @@ class TestSaveResultsDirectory:
|
|
|
126
126
|
assert out.exists()
|
|
127
127
|
assert json.loads(out.read_text()) == results
|
|
128
128
|
|
|
129
|
+
def test_saves_to_relative_depth_path(self, tmp_path):
|
|
130
|
+
depth_dir = tmp_path / "pred_relative_depth"
|
|
131
|
+
depth_dir.mkdir()
|
|
132
|
+
|
|
133
|
+
results = {"depth": {"rmse": 0.5}}
|
|
134
|
+
config = {"name": "model", "relative_depth": {"path": str(depth_dir)}}
|
|
135
|
+
out = save_results(results, config, modality="depth")
|
|
136
|
+
|
|
137
|
+
assert out == depth_dir / "eval.json"
|
|
138
|
+
assert out.exists()
|
|
139
|
+
assert json.loads(out.read_text()) == results
|
|
140
|
+
|
|
129
141
|
def test_saves_to_rgb_path_when_no_depth(self, tmp_path):
|
|
130
142
|
rgb_dir = tmp_path / "pred_rgb"
|
|
131
143
|
rgb_dir.mkdir()
|
|
@@ -99,6 +99,22 @@ class _ZeroValidSparseDataset(_OneSampleSparseDataset):
|
|
|
99
99
|
self.pred = np.zeros((3, 3), dtype=np.float32)
|
|
100
100
|
|
|
101
101
|
|
|
102
|
+
class _RelativeSparseDataset(_OneSampleSparseDataset):
|
|
103
|
+
def __init__(self):
|
|
104
|
+
super().__init__()
|
|
105
|
+
self.pred = np.zeros((3, 3), dtype=np.float32)
|
|
106
|
+
self.pred[1, 1] = (np.sqrt(12.0) - 3.0) / 2.0
|
|
107
|
+
self.pred[1, 2] = (np.sqrt(24.0) - 3.0) / 2.0
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class _AffineSparseDataset(_OneSampleSparseDataset):
|
|
111
|
+
def __init__(self):
|
|
112
|
+
super().__init__()
|
|
113
|
+
self.pred = np.zeros((3, 3), dtype=np.float32)
|
|
114
|
+
self.pred[1, 1] = np.sqrt(12.0) * 10.0 + 7.0
|
|
115
|
+
self.pred[1, 2] = np.sqrt(24.0) * 10.0 + 7.0
|
|
116
|
+
|
|
117
|
+
|
|
102
118
|
def test_sparse_depth_eval_reports_only_pointwise_depth_metrics():
|
|
103
119
|
dataset = _OneSampleSparseDataset()
|
|
104
120
|
|
|
@@ -119,6 +135,50 @@ def test_sparse_depth_eval_reports_only_pointwise_depth_metrics():
|
|
|
119
135
|
np.testing.assert_allclose(metrics["depth_metrics"]["rmse"]["median"], 0.0)
|
|
120
136
|
|
|
121
137
|
|
|
138
|
+
def test_sparse_depth_eval_auto_affine_aligns_relative_depth():
|
|
139
|
+
result = evaluate_sparse_depth_samples(
|
|
140
|
+
_RelativeSparseDataset(),
|
|
141
|
+
pred_is_radial=True,
|
|
142
|
+
num_workers=0,
|
|
143
|
+
alignment_mode="auto_affine",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
assert result["space_info"]["input_space_detected"] == "normalized"
|
|
147
|
+
assert result["space_info"]["calibration_applied"] is True
|
|
148
|
+
assert result["space_info"]["emitted_spaces"] == ["native", "metric"]
|
|
149
|
+
|
|
150
|
+
native_rmse = result["sparse_depth_native"]["depth_metrics"]["rmse"]["median"]
|
|
151
|
+
metric_rmse = result["sparse_depth_metric"]["depth_metrics"]["rmse"]["median"]
|
|
152
|
+
assert metric_rmse < native_rmse
|
|
153
|
+
np.testing.assert_allclose(metric_rmse, 0.0, atol=1e-6)
|
|
154
|
+
|
|
155
|
+
per_file = result["per_file_metrics"]["files"][0]["metrics"]
|
|
156
|
+
assert "sparse_depth_native" in per_file
|
|
157
|
+
assert "sparse_depth_metric" in per_file
|
|
158
|
+
assert (
|
|
159
|
+
per_file["sparse_depth_metric"]["depth_metrics"]["rmse"]
|
|
160
|
+
< per_file["sparse_depth_native"]["depth_metrics"]["rmse"]
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_sparse_depth_eval_auto_affine_uses_declared_affine_depth_hint():
|
|
165
|
+
result = evaluate_sparse_depth_samples(
|
|
166
|
+
_AffineSparseDataset(),
|
|
167
|
+
pred_is_radial=True,
|
|
168
|
+
num_workers=0,
|
|
169
|
+
alignment_mode="auto_affine",
|
|
170
|
+
input_space_hint="affine",
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
assert result["space_info"]["input_space_detected"] == "affine"
|
|
174
|
+
assert result["space_info"]["calibration_applied"] is True
|
|
175
|
+
|
|
176
|
+
native_rmse = result["sparse_depth_native"]["depth_metrics"]["rmse"]["median"]
|
|
177
|
+
metric_rmse = result["sparse_depth_metric"]["depth_metrics"]["rmse"]["median"]
|
|
178
|
+
assert metric_rmse < native_rmse
|
|
179
|
+
np.testing.assert_allclose(metric_rmse, 0.0, atol=1e-5)
|
|
180
|
+
|
|
181
|
+
|
|
122
182
|
def test_sparse_depth_per_file_reports_zero_valid_support():
|
|
123
183
|
result = evaluate_sparse_depth_samples(
|
|
124
184
|
_ZeroValidSparseDataset(),
|
|
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
|
|
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
|