euler-eval 2.17.0__tar.gz → 2.20.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.17.0 → euler_eval-2.20.0}/PKG-INFO +3 -3
- {euler_eval-2.17.0 → euler_eval-2.20.0}/README.md +2 -2
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/cli.py +3 -22
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/evaluate.py +9 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/sanity_checker.py +16 -4
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval.egg-info/PKG-INFO +3 -3
- {euler_eval-2.17.0 → euler_eval-2.20.0}/pyproject.toml +1 -1
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_points_3d.py +9 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_points_3d_sparse.py +43 -19
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/__init__.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/calibration.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/config_paths.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/data.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/__init__.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/absrel.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/daniel_error.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/depth_binned_error.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/depth_standard.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/fid_kid.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/high_freq_energy.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/lpips_metric.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/normal_consistency.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/points3d_cloud.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/points3d_decomposition.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/points3d_distance.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/points3d_geometry.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/psnr.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/rgb_lpips.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/rho_a.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/rmse.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/ssim.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/tail_errors.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/metrics/utils.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/utils/hierarchy_parser.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval/validation.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval.egg-info/SOURCES.txt +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval.egg-info/dependency_links.txt +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval.egg-info/entry_points.txt +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval.egg-info/requires.txt +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/euler_eval.egg-info/top_level.txt +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/init_cache.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/setup.cfg +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_alignment.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_cli_device.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_config.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_data.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_data_builders.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_depth_alignment_output.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_depth_standard.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_evaluate_helpers.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_init_cache.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_integration.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_meta_output.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_metrics_utils.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_rgb_fid_output.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_rho_a.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_save_results.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_sparse_depth.py +0 -0
- {euler_eval-2.17.0 → euler_eval-2.20.0}/tests/test_validation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-eval
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.20.0
|
|
4
4
|
Summary: Depth map evaluation toolkit with comprehensive metrics
|
|
5
5
|
Author: Depth Eval Contributors
|
|
6
6
|
License: MIT
|
|
@@ -339,7 +339,7 @@ When the GT is a sparse pointcloud, the evaluator also produces **3D (`points_3d
|
|
|
339
339
|
- a **predicted point map** (`datasets[].points_3d`, an `(H,W,3)` map) — evaluated *directly* against the sparse GT cloud, with the 3D **similarity** gauge selected by `--points-3d-alignment`; or
|
|
340
340
|
- a **dense depth map** (`datasets[].depth`/`relative_depth`/`affine_depth`) — unprojected with `gt.intrinsics` into a point map, with the depth **affine** gauge selected by `--depth-alignment`.
|
|
341
341
|
|
|
342
|
-
If a dataset entry provides both, the predicted `points_3d` map is preferred (the depth is still scored by the pointwise sparse-depth metrics). Either way the sparse GT cloud is projected into the prediction plane, and the 3D results are written
|
|
342
|
+
If a dataset entry provides both, the predicted `points_3d` map is preferred (the depth is still scored by the pointwise sparse-depth metrics). Either way the sparse GT cloud is projected into the prediction plane, and the 3D results are written as `eval.json` in the selected prediction modality path (or to the configured `output_file`). Give simultaneous evaluations distinct prediction paths: one `output_file` applies to the whole dataset entry.
|
|
343
343
|
|
|
344
344
|
Sparse depth does not require segmentation GT. `gt.segmentation` and
|
|
345
345
|
`gt.semantic_segmentation` are optional aliases for the same sky-mask source.
|
|
@@ -607,7 +607,7 @@ For sparse depth outputs, the internal Python result dict still uses `sparse_dep
|
|
|
607
607
|
|
|
608
608
|
For points_3d outputs, the internal Python result dict uses `points_3d_native`, `points_3d_metric`, and `points_3d` (canonical alias), but serialized `eval.json` metric paths are rooted at `points3d.eval` (no underscore) to satisfy the namespace first-segment rule, mirroring `sparsedepth`. The `metric` space is emitted only when a gauge alignment is applied; otherwise only `native` is present and aliased.
|
|
609
609
|
|
|
610
|
-
When the points_3d metrics come from a sparse pointcloud GT (`gt.sparse_depth` + a predicted `points_3d` map or a dense depth prediction), they use the same `points3d.eval` namespace
|
|
610
|
+
When the points_3d metrics come from a sparse pointcloud GT (`gt.sparse_depth` + a predicted `points_3d` map or a dense depth prediction), they use the same `points3d.eval` namespace and are written as `eval.json` beside the selected prediction modality (or to the configured `output_file`). Only the `point_error`, `error_decomposition`, and (directed) `cloud_distance` categories are present; the `metric` space is emitted only when the gauge (`--points-3d-alignment` for a point-map prediction, `--depth-alignment` for a depth prediction) calibrates the prediction.
|
|
611
611
|
|
|
612
612
|
Previous single-depth structure (kept under `depth`) is:
|
|
613
613
|
|
|
@@ -301,7 +301,7 @@ When the GT is a sparse pointcloud, the evaluator also produces **3D (`points_3d
|
|
|
301
301
|
- a **predicted point map** (`datasets[].points_3d`, an `(H,W,3)` map) — evaluated *directly* against the sparse GT cloud, with the 3D **similarity** gauge selected by `--points-3d-alignment`; or
|
|
302
302
|
- a **dense depth map** (`datasets[].depth`/`relative_depth`/`affine_depth`) — unprojected with `gt.intrinsics` into a point map, with the depth **affine** gauge selected by `--depth-alignment`.
|
|
303
303
|
|
|
304
|
-
If a dataset entry provides both, the predicted `points_3d` map is preferred (the depth is still scored by the pointwise sparse-depth metrics). Either way the sparse GT cloud is projected into the prediction plane, and the 3D results are written
|
|
304
|
+
If a dataset entry provides both, the predicted `points_3d` map is preferred (the depth is still scored by the pointwise sparse-depth metrics). Either way the sparse GT cloud is projected into the prediction plane, and the 3D results are written as `eval.json` in the selected prediction modality path (or to the configured `output_file`). Give simultaneous evaluations distinct prediction paths: one `output_file` applies to the whole dataset entry.
|
|
305
305
|
|
|
306
306
|
Sparse depth does not require segmentation GT. `gt.segmentation` and
|
|
307
307
|
`gt.semantic_segmentation` are optional aliases for the same sky-mask source.
|
|
@@ -569,7 +569,7 @@ For sparse depth outputs, the internal Python result dict still uses `sparse_dep
|
|
|
569
569
|
|
|
570
570
|
For points_3d outputs, the internal Python result dict uses `points_3d_native`, `points_3d_metric`, and `points_3d` (canonical alias), but serialized `eval.json` metric paths are rooted at `points3d.eval` (no underscore) to satisfy the namespace first-segment rule, mirroring `sparsedepth`. The `metric` space is emitted only when a gauge alignment is applied; otherwise only `native` is present and aliased.
|
|
571
571
|
|
|
572
|
-
When the points_3d metrics come from a sparse pointcloud GT (`gt.sparse_depth` + a predicted `points_3d` map or a dense depth prediction), they use the same `points3d.eval` namespace
|
|
572
|
+
When the points_3d metrics come from a sparse pointcloud GT (`gt.sparse_depth` + a predicted `points_3d` map or a dense depth prediction), they use the same `points3d.eval` namespace and are written as `eval.json` beside the selected prediction modality (or to the configured `output_file`). Only the `point_error`, `error_decomposition`, and (directed) `cloud_distance` categories are present; the `metric` space is emitted only when the gauge (`--points-3d-alignment` for a point-map prediction, `--depth-alignment` for a depth prediction) calibrates the prediction.
|
|
573
573
|
|
|
574
574
|
Previous single-depth structure (kept under `depth`) is:
|
|
575
575
|
|
|
@@ -978,9 +978,6 @@ def save_results(
|
|
|
978
978
|
results: dict,
|
|
979
979
|
dataset_config: dict,
|
|
980
980
|
modality: str | None = None,
|
|
981
|
-
*,
|
|
982
|
-
default_basename: str = "eval.json",
|
|
983
|
-
output_file_suffix: str | None = None,
|
|
984
981
|
) -> Path:
|
|
985
982
|
"""Save results to output file.
|
|
986
983
|
|
|
@@ -994,14 +991,6 @@ def save_results(
|
|
|
994
991
|
modality: When set, save to this specific modality's path
|
|
995
992
|
(e.g. ``"depth"`` or ``"rgb"``). Falls back to the first
|
|
996
993
|
available modality path when *None*.
|
|
997
|
-
default_basename: File name used when no explicit ``output_file`` is
|
|
998
|
-
configured (default ``"eval.json"``). Lets a second modality that
|
|
999
|
-
shares a prediction path (e.g. sparse ``points_3d`` alongside sparse
|
|
1000
|
-
``depth``) write to a distinct file instead of clobbering it.
|
|
1001
|
-
output_file_suffix: When an explicit ``output_file`` is configured, this
|
|
1002
|
-
suffix is inserted before its extension (e.g. ``"_points3d"`` turns
|
|
1003
|
-
``model_a.json`` into ``model_a_points3d.json``) so multiple
|
|
1004
|
-
modalities can honour a single configured path without collision.
|
|
1005
994
|
|
|
1006
995
|
Returns:
|
|
1007
996
|
Path where results were saved.
|
|
@@ -1021,7 +1010,7 @@ def save_results(
|
|
|
1021
1010
|
dataset_config[selected_modality]["path"],
|
|
1022
1011
|
split=dataset_config[selected_modality].get("split"),
|
|
1023
1012
|
)
|
|
1024
|
-
/
|
|
1013
|
+
/ "eval.json"
|
|
1025
1014
|
)
|
|
1026
1015
|
else:
|
|
1027
1016
|
# Default: save alongside first available modality path
|
|
@@ -1032,17 +1021,13 @@ def save_results(
|
|
|
1032
1021
|
dataset_config[mod]["path"],
|
|
1033
1022
|
split=dataset_config[mod].get("split"),
|
|
1034
1023
|
)
|
|
1035
|
-
/
|
|
1024
|
+
/ "eval.json"
|
|
1036
1025
|
)
|
|
1037
1026
|
break
|
|
1038
1027
|
if output_file is None:
|
|
1039
|
-
output_file = Path(
|
|
1028
|
+
output_file = Path("eval.json")
|
|
1040
1029
|
else:
|
|
1041
1030
|
output_file = Path(output_file)
|
|
1042
|
-
if output_file_suffix:
|
|
1043
|
-
output_file = output_file.with_name(
|
|
1044
|
-
f"{output_file.stem}{output_file_suffix}{output_file.suffix}"
|
|
1045
|
-
)
|
|
1046
1031
|
|
|
1047
1032
|
zip_path, internal_name = _find_zip_ancestor(output_file)
|
|
1048
1033
|
if zip_path is not None and internal_name:
|
|
@@ -2360,14 +2345,10 @@ def main():
|
|
|
2360
2345
|
)
|
|
2361
2346
|
print(f"\n Points-3D results saved to: {points_3d_out}")
|
|
2362
2347
|
if points_3d_sparse_save:
|
|
2363
|
-
# Distinct file so it never clobbers the sparse-depth eval.json that
|
|
2364
|
-
# shares the same dense-depth prediction path / output_file.
|
|
2365
2348
|
points_3d_sparse_out = save_results(
|
|
2366
2349
|
points_3d_sparse_save,
|
|
2367
2350
|
dataset_config,
|
|
2368
2351
|
modality="points_3d",
|
|
2369
|
-
default_basename="points3d_eval.json",
|
|
2370
|
-
output_file_suffix="_points3d",
|
|
2371
2352
|
)
|
|
2372
2353
|
print(
|
|
2373
2354
|
f"\n Points-3D (sparse GT) results saved to: {points_3d_sparse_out}"
|
|
@@ -3829,6 +3829,15 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3829
3829
|
pred_ok_native = pred_ok_native & sky_valid
|
|
3830
3830
|
pred_ok_metric = pred_ok_metric & sky_valid
|
|
3831
3831
|
|
|
3832
|
+
if sanity_checker is not None:
|
|
3833
|
+
# Keep the sanity-check sample accounting consistent with
|
|
3834
|
+
# the dense points_3d evaluator. Metric validation below
|
|
3835
|
+
# may add warnings, but sample counting belongs to input
|
|
3836
|
+
# validation so each evaluated pair is counted once.
|
|
3837
|
+
sanity_checker.validate_points_3d_input(
|
|
3838
|
+
pred_map_native, gt_point_map, entry_id
|
|
3839
|
+
)
|
|
3840
|
+
|
|
3832
3841
|
# Native correspondence mask drives the shared angular metrics.
|
|
3833
3842
|
native_corr = gt_valid & pred_ok_native
|
|
3834
3843
|
total_evaluated_points += int(native_corr.sum())
|
|
@@ -1119,7 +1119,10 @@ class SanityChecker:
|
|
|
1119
1119
|
print("-" * 70)
|
|
1120
1120
|
|
|
1121
1121
|
for key, info in depth_report["warnings_by_type"].items():
|
|
1122
|
-
ratio =
|
|
1122
|
+
ratio = (
|
|
1123
|
+
info["count"] / depth_report["total_samples"]
|
|
1124
|
+
if depth_report["total_samples"] > 0 else 0
|
|
1125
|
+
)
|
|
1123
1126
|
print(f"\n {info['metric']} - {info['type']}:")
|
|
1124
1127
|
print(f" Occurrences: {info['count']}/{depth_report['total_samples']} ({ratio*100:.1f}%)")
|
|
1125
1128
|
print(f" {info['message']}")
|
|
@@ -1134,7 +1137,10 @@ class SanityChecker:
|
|
|
1134
1137
|
print("-" * 70)
|
|
1135
1138
|
|
|
1136
1139
|
for key, info in rgb_report["warnings_by_type"].items():
|
|
1137
|
-
ratio =
|
|
1140
|
+
ratio = (
|
|
1141
|
+
info["count"] / rgb_report["total_samples"]
|
|
1142
|
+
if rgb_report["total_samples"] > 0 else 0
|
|
1143
|
+
)
|
|
1138
1144
|
print(f"\n {info['metric']} - {info['type']}:")
|
|
1139
1145
|
print(f" Occurrences: {info['count']}/{rgb_report['total_samples']} ({ratio*100:.1f}%)")
|
|
1140
1146
|
print(f" {info['message']}")
|
|
@@ -1149,7 +1155,10 @@ class SanityChecker:
|
|
|
1149
1155
|
print("-" * 70)
|
|
1150
1156
|
|
|
1151
1157
|
for key, info in rays_report["warnings_by_type"].items():
|
|
1152
|
-
ratio =
|
|
1158
|
+
ratio = (
|
|
1159
|
+
info["count"] / rays_report["total_samples"]
|
|
1160
|
+
if rays_report["total_samples"] > 0 else 0
|
|
1161
|
+
)
|
|
1153
1162
|
print(f"\n {info['metric']} - {info['type']}:")
|
|
1154
1163
|
print(f" Occurrences: {info['count']}/{rays_report['total_samples']} ({ratio*100:.1f}%)")
|
|
1155
1164
|
print(f" {info['message']}")
|
|
@@ -1164,7 +1173,10 @@ class SanityChecker:
|
|
|
1164
1173
|
print("-" * 70)
|
|
1165
1174
|
|
|
1166
1175
|
for key, info in points_3d_report["warnings_by_type"].items():
|
|
1167
|
-
ratio =
|
|
1176
|
+
ratio = (
|
|
1177
|
+
info["count"] / points_3d_report["total_samples"]
|
|
1178
|
+
if points_3d_report["total_samples"] > 0 else 0
|
|
1179
|
+
)
|
|
1168
1180
|
print(f"\n {info['metric']} - {info['type']}:")
|
|
1169
1181
|
print(f" Occurrences: {info['count']}/{points_3d_report['total_samples']} ({ratio*100:.1f}%)")
|
|
1170
1182
|
print(f" {info['message']}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-eval
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.20.0
|
|
4
4
|
Summary: Depth map evaluation toolkit with comprehensive metrics
|
|
5
5
|
Author: Depth Eval Contributors
|
|
6
6
|
License: MIT
|
|
@@ -339,7 +339,7 @@ When the GT is a sparse pointcloud, the evaluator also produces **3D (`points_3d
|
|
|
339
339
|
- a **predicted point map** (`datasets[].points_3d`, an `(H,W,3)` map) — evaluated *directly* against the sparse GT cloud, with the 3D **similarity** gauge selected by `--points-3d-alignment`; or
|
|
340
340
|
- a **dense depth map** (`datasets[].depth`/`relative_depth`/`affine_depth`) — unprojected with `gt.intrinsics` into a point map, with the depth **affine** gauge selected by `--depth-alignment`.
|
|
341
341
|
|
|
342
|
-
If a dataset entry provides both, the predicted `points_3d` map is preferred (the depth is still scored by the pointwise sparse-depth metrics). Either way the sparse GT cloud is projected into the prediction plane, and the 3D results are written
|
|
342
|
+
If a dataset entry provides both, the predicted `points_3d` map is preferred (the depth is still scored by the pointwise sparse-depth metrics). Either way the sparse GT cloud is projected into the prediction plane, and the 3D results are written as `eval.json` in the selected prediction modality path (or to the configured `output_file`). Give simultaneous evaluations distinct prediction paths: one `output_file` applies to the whole dataset entry.
|
|
343
343
|
|
|
344
344
|
Sparse depth does not require segmentation GT. `gt.segmentation` and
|
|
345
345
|
`gt.semantic_segmentation` are optional aliases for the same sky-mask source.
|
|
@@ -607,7 +607,7 @@ For sparse depth outputs, the internal Python result dict still uses `sparse_dep
|
|
|
607
607
|
|
|
608
608
|
For points_3d outputs, the internal Python result dict uses `points_3d_native`, `points_3d_metric`, and `points_3d` (canonical alias), but serialized `eval.json` metric paths are rooted at `points3d.eval` (no underscore) to satisfy the namespace first-segment rule, mirroring `sparsedepth`. The `metric` space is emitted only when a gauge alignment is applied; otherwise only `native` is present and aliased.
|
|
609
609
|
|
|
610
|
-
When the points_3d metrics come from a sparse pointcloud GT (`gt.sparse_depth` + a predicted `points_3d` map or a dense depth prediction), they use the same `points3d.eval` namespace
|
|
610
|
+
When the points_3d metrics come from a sparse pointcloud GT (`gt.sparse_depth` + a predicted `points_3d` map or a dense depth prediction), they use the same `points3d.eval` namespace and are written as `eval.json` beside the selected prediction modality (or to the configured `output_file`). Only the `point_error`, `error_decomposition`, and (directed) `cloud_distance` categories are present; the `metric` space is emitted only when the gauge (`--points-3d-alignment` for a point-map prediction, `--depth-alignment` for a depth prediction) calibrates the prediction.
|
|
611
611
|
|
|
612
612
|
Previous single-depth structure (kept under `depth`) is:
|
|
613
613
|
|
|
@@ -485,6 +485,15 @@ class TestSanity:
|
|
|
485
485
|
assert "camera_dominated_error" in types
|
|
486
486
|
assert "rho_a_too_low" in types
|
|
487
487
|
|
|
488
|
+
def test_report_handles_metric_warning_without_counted_input(self, capsys):
|
|
489
|
+
sc = self._checker()
|
|
490
|
+
sc.validate_points_3d_metrics(lateral_fraction=0.95, file_id="f0")
|
|
491
|
+
|
|
492
|
+
sc.print_report()
|
|
493
|
+
|
|
494
|
+
output = capsys.readouterr().out
|
|
495
|
+
assert "Occurrences: 1/0 (0.0%)" in output
|
|
496
|
+
|
|
488
497
|
def test_full_report_includes_points_3d(self):
|
|
489
498
|
sc = self._checker()
|
|
490
499
|
assert "points_3d" in sc.get_full_report()
|
|
@@ -7,6 +7,9 @@ prediction and scores it as a 3D point map against a sparse LiDAR cloud
|
|
|
7
7
|
(``points_3d_metrics_proposal.md`` §4-D).
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
import json
|
|
11
|
+
import zipfile
|
|
12
|
+
|
|
10
13
|
import numpy as np
|
|
11
14
|
import pytest
|
|
12
15
|
|
|
@@ -17,6 +20,7 @@ from euler_eval.data import (
|
|
|
17
20
|
)
|
|
18
21
|
from euler_eval.evaluate import evaluate_points_3d_sparse_samples
|
|
19
22
|
from euler_eval.metrics import compute_sparse_cloud_distance_metrics
|
|
23
|
+
from euler_eval.sanity_checker import SanityChecker
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
def _rot_z(theta):
|
|
@@ -88,6 +92,21 @@ def _perfect_dataset(seed=0, **kwargs):
|
|
|
88
92
|
return _SparsePointDataset(cloud, depth, K, **kwargs), depth, K, cloud
|
|
89
93
|
|
|
90
94
|
|
|
95
|
+
def test_sparse_evaluation_counts_sanity_check_samples():
|
|
96
|
+
dataset, _, _, _ = _perfect_dataset()
|
|
97
|
+
sanity_checker = SanityChecker()
|
|
98
|
+
|
|
99
|
+
evaluate_points_3d_sparse_samples(
|
|
100
|
+
dataset,
|
|
101
|
+
pred_is_radial=False,
|
|
102
|
+
num_workers=0,
|
|
103
|
+
sanity_checker=sanity_checker,
|
|
104
|
+
alignment_mode="none",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
assert sanity_checker.get_points_3d_report()["total_samples"] == 1
|
|
108
|
+
|
|
109
|
+
|
|
91
110
|
# ---------------------------------------------------------------------------
|
|
92
111
|
# Directed (sparse) cloud distance
|
|
93
112
|
# ---------------------------------------------------------------------------
|
|
@@ -440,39 +459,44 @@ class TestEvaluateNativePoints:
|
|
|
440
459
|
|
|
441
460
|
|
|
442
461
|
# ---------------------------------------------------------------------------
|
|
443
|
-
# Save wiring
|
|
462
|
+
# Save wiring
|
|
444
463
|
# ---------------------------------------------------------------------------
|
|
445
464
|
|
|
446
465
|
|
|
447
466
|
class TestSaveWiring:
|
|
448
|
-
def
|
|
467
|
+
def test_points_3d_uses_eval_json_in_its_modality_path(self, tmp_path):
|
|
449
468
|
from euler_eval.cli import save_results
|
|
450
469
|
|
|
451
470
|
pred_dir = tmp_path / "pred"
|
|
452
471
|
pred_dir.mkdir()
|
|
453
|
-
cfg = {"name": "m", "
|
|
472
|
+
cfg = {"name": "m", "points_3d": {"path": str(pred_dir)}}
|
|
454
473
|
|
|
455
|
-
# Sparse-depth writes eval.json; sparse-points_3d writes points3d_eval.json.
|
|
456
|
-
depth_out = save_results({"a": 1}, cfg, modality="depth")
|
|
457
474
|
p3d_out = save_results(
|
|
458
|
-
{"
|
|
459
|
-
default_basename="points3d_eval.json",
|
|
475
|
+
{"points3d": {"eval": {}}}, cfg, modality="points_3d"
|
|
460
476
|
)
|
|
461
|
-
assert depth_out.name == "eval.json"
|
|
462
|
-
assert p3d_out.name == "points3d_eval.json"
|
|
463
|
-
assert depth_out != p3d_out
|
|
464
|
-
assert depth_out.exists() and p3d_out.exists()
|
|
465
477
|
|
|
466
|
-
|
|
478
|
+
assert p3d_out == pred_dir / "eval.json"
|
|
479
|
+
assert p3d_out.exists()
|
|
480
|
+
assert not (pred_dir / "points3d_eval.json").exists()
|
|
481
|
+
assert not (pred_dir / "points_3d_eval.json").exists()
|
|
482
|
+
|
|
483
|
+
def test_points_3d_writes_eval_json_into_zip(self, tmp_path):
|
|
467
484
|
from euler_eval.cli import save_results
|
|
468
485
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
486
|
+
archive = tmp_path / "predictions.zip"
|
|
487
|
+
with zipfile.ZipFile(archive, "w") as zf:
|
|
488
|
+
zf.writestr("points/frame_000.npy", b"points")
|
|
489
|
+
|
|
490
|
+
results = {"points3d": {"eval": {"native": {}}}}
|
|
491
|
+
cfg = {"name": "m", "points_3d": {"path": str(archive)}}
|
|
492
|
+
p3d_out = save_results(results, cfg, modality="points_3d")
|
|
493
|
+
|
|
494
|
+
assert p3d_out == archive / "eval.json"
|
|
495
|
+
with zipfile.ZipFile(archive) as zf:
|
|
496
|
+
assert "eval.json" in zf.namelist()
|
|
497
|
+
assert "points3d_eval.json" not in zf.namelist()
|
|
498
|
+
assert "points_3d_eval.json" not in zf.namelist()
|
|
499
|
+
assert json.loads(zf.read("eval.json")) == results
|
|
476
500
|
|
|
477
501
|
|
|
478
502
|
# ---------------------------------------------------------------------------
|
|
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
|
|
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
|