euler-eval 2.26.0__tar.gz → 2.28.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.26.0 → euler_eval-2.28.0}/PKG-INFO +3 -3
- {euler_eval-2.26.0 → euler_eval-2.28.0}/README.md +2 -2
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/cli.py +72 -68
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/data.py +31 -1
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/evaluate.py +107 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval.egg-info/PKG-INFO +3 -3
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval.egg-info/SOURCES.txt +1 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/pyproject.toml +1 -1
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_cli_device.py +20 -0
- euler_eval-2.28.0/tests/test_cli_sparse_outputs.py +237 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_config.py +36 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_data_builders.py +42 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_depth_alignment_output.py +129 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_evaluate_helpers.py +44 -1
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_integration.py +17 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_points_3d_sparse.py +30 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_sparse_depth.py +21 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/LICENSE +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/THIRD_PARTY_NOTICES.md +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/__init__.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/calibration.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/config_paths.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metric_sets.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/__init__.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/_natural_scene_models.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/absrel.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/daniel_error.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/depth_binned_error.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/depth_standard.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/fade.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/fid_kid.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/high_freq_energy.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/lpips_metric.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/niqe.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/normal_consistency.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/points3d_cloud.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/points3d_decomposition.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/points3d_distance.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/points3d_geometry.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/psnr.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/rgb_lpips.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/rho_a.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/rmse.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/ssim.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/tail_errors.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/metrics/utils.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/sanity_checker.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/utils/hierarchy_parser.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval/validation.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval.egg-info/dependency_links.txt +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval.egg-info/entry_points.txt +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval.egg-info/requires.txt +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/euler_eval.egg-info/top_level.txt +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/init_cache.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/setup.cfg +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_alignment.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_data.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_depth_standard.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_domain_metrics.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_init_cache.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_meta_output.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_metrics_utils.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_normal_consistency.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_points_3d.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_rgb_fid_output.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_rho_a.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.0}/tests/test_save_results.py +0 -0
- {euler_eval-2.26.0 → euler_eval-2.28.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.28.0
|
|
4
4
|
Summary: Evaluation toolkit for depth, RGB, ray and 3D point-map predictions
|
|
5
5
|
Author-email: Daniel Rothenpieler <rothenpielerdaniel@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -158,10 +158,10 @@ straight out of the archive. Full schema: [Configuration](docs/configuration.md)
|
|
|
158
158
|
| Modality | Config key | Scored against | Headline metrics |
|
|
159
159
|
|---|---|---|---|
|
|
160
160
|
| **Depth** | `depth`, `relative_depth`, `affine_depth` | dense GT depth | `absrel`…`delta3`, PSNR/SSIM/LPIPS/FID/KID, surface-normal consistency, depth-edge F1 |
|
|
161
|
-
| **Sparse depth** | `depth` + `gt.sparse_depth` | a LiDAR-style point cloud, projected into the prediction plane | pointwise depth metrics at projected points
|
|
161
|
+
| **Sparse depth** | `depth` + `gt.sparse_depth` | a LiDAR-style point cloud, projected into the prediction plane | pointwise depth metrics at projected points |
|
|
162
162
|
| **RGB** | `rgb` | GT RGB | PSNR, SSIM, LPIPS, FID, SCE, edge F1, tail errors, HF energy ratio, depth-binned photometric error; optional NIQE/FADE dehazing metrics |
|
|
163
163
|
| **Rays** | `rays` | GT ray direction map | ρ_A (angular-accuracy AUC), angular error, threshold percentages |
|
|
164
|
-
| **Points-3D** | `points_3d` | GT point map,
|
|
164
|
+
| **Points-3D** | `points_3d` | GT point map, GT depth unprojected on the fly, or a sparse point cloud | 3D EPE/RMSE/δ, radial-vs-lateral decomposition, true-3D normals and edge F1, Chamfer / F-score |
|
|
165
165
|
|
|
166
166
|
A run evaluates whichever modalities are configured on both sides; a depth-only
|
|
167
167
|
prediction is a perfectly ordinary run. The full inventory, with the key each
|
|
@@ -109,10 +109,10 @@ straight out of the archive. Full schema: [Configuration](docs/configuration.md)
|
|
|
109
109
|
| Modality | Config key | Scored against | Headline metrics |
|
|
110
110
|
|---|---|---|---|
|
|
111
111
|
| **Depth** | `depth`, `relative_depth`, `affine_depth` | dense GT depth | `absrel`…`delta3`, PSNR/SSIM/LPIPS/FID/KID, surface-normal consistency, depth-edge F1 |
|
|
112
|
-
| **Sparse depth** | `depth` + `gt.sparse_depth` | a LiDAR-style point cloud, projected into the prediction plane | pointwise depth metrics at projected points
|
|
112
|
+
| **Sparse depth** | `depth` + `gt.sparse_depth` | a LiDAR-style point cloud, projected into the prediction plane | pointwise depth metrics at projected points |
|
|
113
113
|
| **RGB** | `rgb` | GT RGB | PSNR, SSIM, LPIPS, FID, SCE, edge F1, tail errors, HF energy ratio, depth-binned photometric error; optional NIQE/FADE dehazing metrics |
|
|
114
114
|
| **Rays** | `rays` | GT ray direction map | ρ_A (angular-accuracy AUC), angular error, threshold percentages |
|
|
115
|
-
| **Points-3D** | `points_3d` | GT point map,
|
|
115
|
+
| **Points-3D** | `points_3d` | GT point map, GT depth unprojected on the fly, or a sparse point cloud | 3D EPE/RMSE/δ, radial-vs-lateral decomposition, true-3D normals and edge F1, Chamfer / F-score |
|
|
116
116
|
|
|
117
117
|
A run evaluates whichever modalities are configured on both sides; a depth-only
|
|
118
118
|
prediction is a perfectly ordinary run. The full inventory, with the key each
|
|
@@ -30,6 +30,7 @@ from .data import (
|
|
|
30
30
|
get_rays_metadata,
|
|
31
31
|
get_rgb_metadata,
|
|
32
32
|
get_sparse_depth_metadata,
|
|
33
|
+
validate_sky_depth,
|
|
33
34
|
)
|
|
34
35
|
from .evaluate import (
|
|
35
36
|
evaluate_depth_samples,
|
|
@@ -906,7 +907,16 @@ def validate_dataset_entry(entry: dict, index: int) -> None:
|
|
|
906
907
|
"or 'points_3d.path'"
|
|
907
908
|
)
|
|
908
909
|
|
|
909
|
-
|
|
910
|
+
if "sky_mask" in entry:
|
|
911
|
+
if not isinstance(entry["sky_mask"], dict) or not entry["sky_mask"].get("path"):
|
|
912
|
+
raise ValueError(f"{label}.sky_mask must have a 'path' field")
|
|
913
|
+
if not has_depth:
|
|
914
|
+
raise ValueError(
|
|
915
|
+
f"{label}.sky_mask requires a dense depth prediction "
|
|
916
|
+
"('depth', 'relative_depth', or 'affine_depth')"
|
|
917
|
+
)
|
|
918
|
+
|
|
919
|
+
for modality in ("rgb", *_PRED_DEPTH_KEYS, "rays", "points_3d", "sky_mask"):
|
|
910
920
|
if modality in entry and "path" in entry[modality]:
|
|
911
921
|
p = normalize_modality_path(
|
|
912
922
|
entry[modality]["path"],
|
|
@@ -1166,6 +1176,17 @@ def main():
|
|
|
1166
1176
|
action="store_true",
|
|
1167
1177
|
help="Mask sky regions from metrics using GT segmentation",
|
|
1168
1178
|
)
|
|
1179
|
+
parser.add_argument(
|
|
1180
|
+
"--sky-depth",
|
|
1181
|
+
type=float,
|
|
1182
|
+
default=None,
|
|
1183
|
+
metavar="METERS",
|
|
1184
|
+
help=(
|
|
1185
|
+
"Cap GT and predicted depths at this finite positive value after "
|
|
1186
|
+
"conversion/alignment; fill predicted sky_mask pixels with it "
|
|
1187
|
+
"(default: disabled)"
|
|
1188
|
+
),
|
|
1189
|
+
)
|
|
1169
1190
|
parser.add_argument(
|
|
1170
1191
|
"--no-sanity-check",
|
|
1171
1192
|
action="store_true",
|
|
@@ -1219,6 +1240,10 @@ def main():
|
|
|
1219
1240
|
)
|
|
1220
1241
|
|
|
1221
1242
|
args = parser.parse_args()
|
|
1243
|
+
try:
|
|
1244
|
+
validate_sky_depth(args.sky_depth)
|
|
1245
|
+
except ValueError as e:
|
|
1246
|
+
parser.error(f"--sky-depth: {e}")
|
|
1222
1247
|
|
|
1223
1248
|
selected_metric_sets = resolve_metric_sets(args.domains)
|
|
1224
1249
|
|
|
@@ -1237,6 +1262,8 @@ def main():
|
|
|
1237
1262
|
configure_torch_runtime(args.device)
|
|
1238
1263
|
print_device_info(requested_device, args.device)
|
|
1239
1264
|
print(f"Depth alignment: {args.depth_alignment}")
|
|
1265
|
+
if args.sky_depth is not None:
|
|
1266
|
+
print(f"Sky depth: {args.sky_depth} meters (depth cap and predicted sky fill)")
|
|
1240
1267
|
print(f"RGB FID backend: {args.rgb_fid_backend}")
|
|
1241
1268
|
print(
|
|
1242
1269
|
"Metric sets: "
|
|
@@ -1320,6 +1347,11 @@ def main():
|
|
|
1320
1347
|
ds_name = dataset_config["name"]
|
|
1321
1348
|
pred_depth_key, pred_depth_config = _prediction_depth_entry(dataset_config)
|
|
1322
1349
|
has_depth = pred_depth_config is not None
|
|
1350
|
+
pred_sky_mask_config = (
|
|
1351
|
+
dataset_config.get("sky_mask", {}) if args.sky_depth is not None else {}
|
|
1352
|
+
)
|
|
1353
|
+
pred_sky_mask_path = pred_sky_mask_config.get("path")
|
|
1354
|
+
pred_sky_mask_split = pred_sky_mask_config.get("split")
|
|
1323
1355
|
has_rgb = "rgb" in dataset_config and "path" in dataset_config["rgb"]
|
|
1324
1356
|
has_rays = "rays" in dataset_config and "path" in dataset_config["rays"]
|
|
1325
1357
|
has_points_3d = (
|
|
@@ -1364,6 +1396,8 @@ def main():
|
|
|
1364
1396
|
depth_dataset = build_depth_eval_dataset(
|
|
1365
1397
|
gt_depth_path=gt_depth_path,
|
|
1366
1398
|
pred_depth_path=pred_depth_path,
|
|
1399
|
+
pred_sky_mask_path=pred_sky_mask_path,
|
|
1400
|
+
pred_sky_mask_split=pred_sky_mask_split,
|
|
1367
1401
|
calibration_path=calibration_path,
|
|
1368
1402
|
segmentation_path=segmentation_path,
|
|
1369
1403
|
pred_depth_metadata_scope=(
|
|
@@ -1392,6 +1426,7 @@ def main():
|
|
|
1392
1426
|
verbose=args.verbose,
|
|
1393
1427
|
sanity_checker=sanity_checker,
|
|
1394
1428
|
sky_mask_enabled=args.mask_sky,
|
|
1429
|
+
sky_depth=args.sky_depth,
|
|
1395
1430
|
alignment_mode=args.depth_alignment,
|
|
1396
1431
|
benchmark_depth_range=(
|
|
1397
1432
|
tuple(args.benchmark_depth_range)
|
|
@@ -1452,6 +1487,7 @@ def main():
|
|
|
1452
1487
|
"split": pred_depth_split,
|
|
1453
1488
|
"entry": pred_depth_key,
|
|
1454
1489
|
"dimensions": depth_spatial.get("pred_dimensions"),
|
|
1490
|
+
"sky_mask": pred_sky_mask_config or None,
|
|
1455
1491
|
},
|
|
1456
1492
|
"spatial_alignment": {
|
|
1457
1493
|
"method": depth_spatial.get("method", "none"),
|
|
@@ -1463,6 +1499,7 @@ def main():
|
|
|
1463
1499
|
"eval_params": {
|
|
1464
1500
|
"sky_masking": args.mask_sky,
|
|
1465
1501
|
"depth_alignment_mode": args.depth_alignment,
|
|
1502
|
+
"sky_depth": args.sky_depth,
|
|
1466
1503
|
"batch_size": args.batch_size,
|
|
1467
1504
|
"num_workers": args.num_workers,
|
|
1468
1505
|
"benchmark_depth_range": (
|
|
@@ -1555,6 +1592,8 @@ def main():
|
|
|
1555
1592
|
sparse_depth_dataset = build_sparse_depth_eval_dataset(
|
|
1556
1593
|
gt_sparse_depth_path=gt_sparse_depth_path,
|
|
1557
1594
|
pred_depth_path=pred_depth_path,
|
|
1595
|
+
pred_sky_mask_path=pred_sky_mask_path,
|
|
1596
|
+
pred_sky_mask_split=pred_sky_mask_split,
|
|
1558
1597
|
intrinsics_path=intrinsics_path,
|
|
1559
1598
|
camera_extrinsics_path=camera_extrinsics_path,
|
|
1560
1599
|
lidar_extrinsics_path=lidar_extrinsics_path,
|
|
@@ -1585,6 +1624,7 @@ def main():
|
|
|
1585
1624
|
verbose=args.verbose,
|
|
1586
1625
|
sanity_checker=sanity_checker,
|
|
1587
1626
|
sky_mask_enabled=args.mask_sky,
|
|
1627
|
+
sky_depth=args.sky_depth,
|
|
1588
1628
|
alignment_mode=args.depth_alignment,
|
|
1589
1629
|
benchmark_depth_range=(
|
|
1590
1630
|
tuple(args.benchmark_depth_range)
|
|
@@ -1640,6 +1680,7 @@ def main():
|
|
|
1640
1680
|
"split": pred_depth_split,
|
|
1641
1681
|
"entry": pred_depth_key,
|
|
1642
1682
|
"dimensions": sparse_depth_spatial.get("pred_dimensions"),
|
|
1683
|
+
"sky_mask": pred_sky_mask_config or None,
|
|
1643
1684
|
},
|
|
1644
1685
|
"calibration": {
|
|
1645
1686
|
"intrinsics_path": intrinsics_path,
|
|
@@ -1661,6 +1702,7 @@ def main():
|
|
|
1661
1702
|
"eval_params": {
|
|
1662
1703
|
"sky_masking": args.mask_sky,
|
|
1663
1704
|
"depth_alignment_mode": args.depth_alignment,
|
|
1705
|
+
"sky_depth": args.sky_depth,
|
|
1664
1706
|
"num_workers": args.num_workers,
|
|
1665
1707
|
"benchmark_depth_range": (
|
|
1666
1708
|
list(args.benchmark_depth_range)
|
|
@@ -2198,80 +2240,42 @@ def main():
|
|
|
2198
2240
|
# -- Points-3D against sparse pointcloud GT --
|
|
2199
2241
|
# When the GT is a sparse LiDAR cloud (gt.sparse_depth), evaluate the
|
|
2200
2242
|
# *3D* metrics (Chamfer/F-score completeness + per-correspondence 3D
|
|
2201
|
-
# error) against the sparse GT cloud.
|
|
2202
|
-
#
|
|
2203
|
-
#
|
|
2204
|
-
# - a dense depth map, unprojected with the GT intrinsics (affine
|
|
2205
|
-
# gauge). Independent of the sparse-depth pointwise branch; gated by
|
|
2206
|
-
# --skip-points-3d.
|
|
2243
|
+
# error) against the sparse GT cloud. This is an atomic points_3d
|
|
2244
|
+
# evaluation and therefore requires an explicit predicted points_3d map;
|
|
2245
|
+
# a depth prediction is handled only by the sparse-depth branch above.
|
|
2207
2246
|
if (
|
|
2208
2247
|
gt_sparse_depth_path
|
|
2209
|
-
and
|
|
2248
|
+
and has_points_3d
|
|
2210
2249
|
and not args.skip_points_3d
|
|
2211
2250
|
):
|
|
2212
|
-
p3s_pred_is_depth = not has_points_3d
|
|
2213
2251
|
print(f"\n[POINTS_3D · SPARSE] Evaluating: '{ds_name}'")
|
|
2214
2252
|
print(f" GT sparse pointcloud: {gt_sparse_depth_path}")
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
intrinsics_split=intrinsics_split,
|
|
2236
|
-
camera_extrinsics_split=camera_extrinsics_split,
|
|
2237
|
-
lidar_extrinsics_split=lidar_extrinsics_split,
|
|
2238
|
-
segmentation_split=segmentation_split,
|
|
2239
|
-
)
|
|
2240
|
-
p3ds_meta = get_sparse_depth_metadata(points_3d_sparse_dataset)
|
|
2241
|
-
p3s_pred_is_radial = p3ds_meta["pred_radial_depth"]
|
|
2242
|
-
p3s_alignment_mode = args.depth_alignment
|
|
2243
|
-
p3s_input_hint = _prediction_depth_space_hint(pred_depth_key)
|
|
2244
|
-
print(f" pred_radial_depth: {p3s_pred_is_radial}")
|
|
2245
|
-
else:
|
|
2246
|
-
p3s_pred_path = dataset_config["points_3d"]["path"]
|
|
2247
|
-
p3s_pred_split = dataset_config["points_3d"].get("split")
|
|
2248
|
-
p3s_pred_entry = "points_3d"
|
|
2249
|
-
print(f" Pred point map: {p3s_pred_path}")
|
|
2250
|
-
points_3d_sparse_dataset = build_points_3d_sparse_eval_dataset(
|
|
2251
|
-
gt_sparse_depth_path=gt_sparse_depth_path,
|
|
2252
|
-
pred_points_3d_path=p3s_pred_path,
|
|
2253
|
-
intrinsics_path=intrinsics_path,
|
|
2254
|
-
camera_extrinsics_path=camera_extrinsics_path,
|
|
2255
|
-
lidar_extrinsics_path=lidar_extrinsics_path,
|
|
2256
|
-
segmentation_path=segmentation_path,
|
|
2257
|
-
segmentation_modality_key=segmentation_key or "segmentation",
|
|
2258
|
-
gt_sparse_depth_split=gt_sparse_depth_split,
|
|
2259
|
-
pred_points_3d_split=p3s_pred_split,
|
|
2260
|
-
intrinsics_split=intrinsics_split,
|
|
2261
|
-
camera_extrinsics_split=camera_extrinsics_split,
|
|
2262
|
-
lidar_extrinsics_split=lidar_extrinsics_split,
|
|
2263
|
-
segmentation_split=segmentation_split,
|
|
2264
|
-
)
|
|
2265
|
-
p3ds_meta = get_points_3d_metadata(points_3d_sparse_dataset)
|
|
2266
|
-
p3s_pred_is_radial = True
|
|
2267
|
-
p3s_alignment_mode = args.points_3d_alignment
|
|
2268
|
-
p3s_input_hint = None
|
|
2253
|
+
p3s_pred_path = dataset_config["points_3d"]["path"]
|
|
2254
|
+
p3s_pred_split = dataset_config["points_3d"].get("split")
|
|
2255
|
+
print(f" Pred point map: {p3s_pred_path}")
|
|
2256
|
+
points_3d_sparse_dataset = build_points_3d_sparse_eval_dataset(
|
|
2257
|
+
gt_sparse_depth_path=gt_sparse_depth_path,
|
|
2258
|
+
pred_points_3d_path=p3s_pred_path,
|
|
2259
|
+
intrinsics_path=intrinsics_path,
|
|
2260
|
+
camera_extrinsics_path=camera_extrinsics_path,
|
|
2261
|
+
lidar_extrinsics_path=lidar_extrinsics_path,
|
|
2262
|
+
segmentation_path=segmentation_path,
|
|
2263
|
+
segmentation_modality_key=segmentation_key or "segmentation",
|
|
2264
|
+
gt_sparse_depth_split=gt_sparse_depth_split,
|
|
2265
|
+
pred_points_3d_split=p3s_pred_split,
|
|
2266
|
+
intrinsics_split=intrinsics_split,
|
|
2267
|
+
camera_extrinsics_split=camera_extrinsics_split,
|
|
2268
|
+
lidar_extrinsics_split=lidar_extrinsics_split,
|
|
2269
|
+
segmentation_split=segmentation_split,
|
|
2270
|
+
)
|
|
2271
|
+
p3ds_meta = get_points_3d_metadata(points_3d_sparse_dataset)
|
|
2272
|
+
p3s_alignment_mode = args.points_3d_alignment
|
|
2269
2273
|
et_eval_datasets["points_3d_sparse"] = points_3d_sparse_dataset
|
|
2270
2274
|
print(f" Matched pairs: {len(points_3d_sparse_dataset)}")
|
|
2271
2275
|
|
|
2272
2276
|
points_3d_sparse_results = evaluate_points_3d_sparse_samples(
|
|
2273
2277
|
dataset=points_3d_sparse_dataset,
|
|
2274
|
-
pred_is_radial=
|
|
2278
|
+
pred_is_radial=True,
|
|
2275
2279
|
gt_name=gt.get("name", "GT"),
|
|
2276
2280
|
pred_name=ds_name,
|
|
2277
2281
|
num_workers=args.num_workers,
|
|
@@ -2279,8 +2283,8 @@ def main():
|
|
|
2279
2283
|
sanity_checker=sanity_checker,
|
|
2280
2284
|
sky_mask_enabled=args.mask_sky,
|
|
2281
2285
|
alignment_mode=p3s_alignment_mode,
|
|
2282
|
-
input_space_hint=
|
|
2283
|
-
pred_is_depth=
|
|
2286
|
+
input_space_hint=None,
|
|
2287
|
+
pred_is_depth=False,
|
|
2284
2288
|
)
|
|
2285
2289
|
|
|
2286
2290
|
if sanity_checker is not None:
|
|
@@ -2335,8 +2339,8 @@ def main():
|
|
|
2335
2339
|
"pred": {
|
|
2336
2340
|
"path": p3s_pred_path,
|
|
2337
2341
|
"split": p3s_pred_split,
|
|
2338
|
-
"entry":
|
|
2339
|
-
"representation": "
|
|
2342
|
+
"entry": "points_3d",
|
|
2343
|
+
"representation": "points_3d",
|
|
2340
2344
|
"dimensions": p3s_spatial.get("pred_dimensions"),
|
|
2341
2345
|
},
|
|
2342
2346
|
"calibration": {
|
|
@@ -614,6 +614,12 @@ def align_to_prediction(gt: np.ndarray, pred: np.ndarray) -> np.ndarray:
|
|
|
614
614
|
return result.astype(bool) if is_bool else result
|
|
615
615
|
|
|
616
616
|
|
|
617
|
+
def validate_sky_depth(sky_depth: Optional[float]) -> None:
|
|
618
|
+
"""Require a finite positive depth cap when sky-depth processing is enabled."""
|
|
619
|
+
if sky_depth is not None and (not np.isfinite(sky_depth) or sky_depth <= 0):
|
|
620
|
+
raise ValueError("sky_depth must be a finite positive value")
|
|
621
|
+
|
|
622
|
+
|
|
617
623
|
def compute_scale_and_shift(
|
|
618
624
|
pred: np.ndarray,
|
|
619
625
|
gt: np.ndarray,
|
|
@@ -760,11 +766,14 @@ def build_depth_eval_dataset(
|
|
|
760
766
|
segmentation_split: Optional[str] = None,
|
|
761
767
|
pred_depth_metadata_scope: Optional[str] = None,
|
|
762
768
|
segmentation_modality_key: str = "segmentation",
|
|
769
|
+
pred_sky_mask_path: Optional[str] = None,
|
|
770
|
+
pred_sky_mask_split: Optional[str] = None,
|
|
763
771
|
) -> MultiModalDataset:
|
|
764
772
|
"""Build a MultiModalDataset for depth evaluation.
|
|
765
773
|
|
|
766
774
|
The returned dataset yields samples with keys ``"gt"``, ``"pred"``,
|
|
767
|
-
and optionally ``"calibration"
|
|
775
|
+
and optionally ``"calibration"``, ``"segmentation"`` (GT), and
|
|
776
|
+
``"pred_sky_mask"`` (prediction, True = sky).
|
|
768
777
|
|
|
769
778
|
Loaders are resolved automatically from each dataset directory's
|
|
770
779
|
ds-crawler index metadata.
|
|
@@ -781,6 +790,9 @@ def build_depth_eval_dataset(
|
|
|
781
790
|
pred_depth_metadata_scope: Optional metadata scope for the prediction
|
|
782
791
|
depth modality, useful when loading depth-like outputs such as
|
|
783
792
|
``relative_depth`` or ``affine_depth`` through the depth loader.
|
|
793
|
+
pred_sky_mask_path: Optional predicted ``sky_mask`` dataset, paired
|
|
794
|
+
with depth by sample ID using its own loader metadata.
|
|
795
|
+
pred_sky_mask_split: Optional split for the predicted sky mask.
|
|
784
796
|
|
|
785
797
|
Returns:
|
|
786
798
|
A MultiModalDataset instance.
|
|
@@ -799,6 +811,13 @@ def build_depth_eval_dataset(
|
|
|
799
811
|
split=pred_depth_split,
|
|
800
812
|
),
|
|
801
813
|
}
|
|
814
|
+
if pred_sky_mask_path is not None:
|
|
815
|
+
modalities["pred_sky_mask"] = _modality(
|
|
816
|
+
path=pred_sky_mask_path,
|
|
817
|
+
modality_key="sky_mask",
|
|
818
|
+
used_as="output",
|
|
819
|
+
split=pred_sky_mask_split,
|
|
820
|
+
)
|
|
802
821
|
|
|
803
822
|
hierarchical = {}
|
|
804
823
|
if calibration_path is not None:
|
|
@@ -840,6 +859,8 @@ def build_sparse_depth_eval_dataset(
|
|
|
840
859
|
segmentation_split: Optional[str] = None,
|
|
841
860
|
pred_depth_metadata_scope: Optional[str] = None,
|
|
842
861
|
segmentation_modality_key: str = "segmentation",
|
|
862
|
+
pred_sky_mask_path: Optional[str] = None,
|
|
863
|
+
pred_sky_mask_split: Optional[str] = None,
|
|
843
864
|
) -> MultiModalDataset:
|
|
844
865
|
"""Build a MultiModalDataset for sparse pointcloud depth evaluation.
|
|
845
866
|
|
|
@@ -855,6 +876,8 @@ def build_sparse_depth_eval_dataset(
|
|
|
855
876
|
such as ``relative_depth`` or ``affine_depth`` while still loading it
|
|
856
877
|
as a dense depth map. Segmentation remains optional for sparse depth and is
|
|
857
878
|
only loaded by callers that request sky masking.
|
|
879
|
+
``pred_sky_mask_path`` optionally adds an ID-paired ``"pred_sky_mask"``
|
|
880
|
+
prediction (True = sky), with its own ``pred_sky_mask_split`` selector.
|
|
858
881
|
"""
|
|
859
882
|
modalities = {
|
|
860
883
|
"gt": _modality(
|
|
@@ -870,6 +893,13 @@ def build_sparse_depth_eval_dataset(
|
|
|
870
893
|
split=pred_depth_split,
|
|
871
894
|
),
|
|
872
895
|
}
|
|
896
|
+
if pred_sky_mask_path is not None:
|
|
897
|
+
modalities["pred_sky_mask"] = _modality(
|
|
898
|
+
path=pred_sky_mask_path,
|
|
899
|
+
modality_key="sky_mask",
|
|
900
|
+
used_as="output",
|
|
901
|
+
split=pred_sky_mask_split,
|
|
902
|
+
)
|
|
873
903
|
|
|
874
904
|
hierarchical = _sparse_projection_hierarchical(
|
|
875
905
|
intrinsics_path=intrinsics_path,
|
|
@@ -38,6 +38,7 @@ from .data import (
|
|
|
38
38
|
to_numpy_points_3d,
|
|
39
39
|
to_numpy_rgb,
|
|
40
40
|
unproject_depth_to_points,
|
|
41
|
+
validate_sky_depth,
|
|
41
42
|
)
|
|
42
43
|
from .metric_sets import resolve_metric_sets
|
|
43
44
|
from .metrics import (
|
|
@@ -504,6 +505,48 @@ def _get_sky_mask(sample: dict) -> Optional[np.ndarray]:
|
|
|
504
505
|
return ~sky # invert: True = non-sky = valid
|
|
505
506
|
|
|
506
507
|
|
|
508
|
+
def _get_prediction_sky_mask(
|
|
509
|
+
sample: dict, depth_pred: np.ndarray
|
|
510
|
+
) -> Optional[np.ndarray]:
|
|
511
|
+
"""Return the predicted sky mask on the depth grid (True = sky)."""
|
|
512
|
+
mask_data = sample.get("pred_sky_mask")
|
|
513
|
+
if mask_data is None:
|
|
514
|
+
return None
|
|
515
|
+
return align_to_prediction(to_numpy_mask(mask_data), depth_pred)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def _apply_sky_depth(
|
|
519
|
+
depth_gt: np.ndarray,
|
|
520
|
+
depth_pred_raw: np.ndarray,
|
|
521
|
+
depth_pred_aligned: np.ndarray,
|
|
522
|
+
sky_depth: Optional[float],
|
|
523
|
+
pred_sky_mask: Optional[np.ndarray],
|
|
524
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
525
|
+
"""Cap evaluation depths and fill predicted sky after conversion/alignment.
|
|
526
|
+
|
|
527
|
+
Preserve the shared prediction object when no alignment was needed, since
|
|
528
|
+
evaluators use its identity to avoid computing the same metrics twice.
|
|
529
|
+
NaNs and nonpositive values remain invalid unless filled by the sky mask;
|
|
530
|
+
positive infinity is truncated to the cap like any other larger depth.
|
|
531
|
+
"""
|
|
532
|
+
if sky_depth is None:
|
|
533
|
+
return depth_gt, depth_pred_raw, depth_pred_aligned
|
|
534
|
+
|
|
535
|
+
def _cap_prediction(depth):
|
|
536
|
+
capped = np.minimum(depth, sky_depth)
|
|
537
|
+
if pred_sky_mask is not None:
|
|
538
|
+
capped[pred_sky_mask] = sky_depth
|
|
539
|
+
return capped
|
|
540
|
+
|
|
541
|
+
aligned_is_raw = depth_pred_aligned is depth_pred_raw
|
|
542
|
+
depth_gt = np.minimum(depth_gt, sky_depth)
|
|
543
|
+
depth_pred_raw = _cap_prediction(depth_pred_raw)
|
|
544
|
+
depth_pred_aligned = (
|
|
545
|
+
depth_pred_raw if aligned_is_raw else _cap_prediction(depth_pred_aligned)
|
|
546
|
+
)
|
|
547
|
+
return depth_gt, depth_pred_raw, depth_pred_aligned
|
|
548
|
+
|
|
549
|
+
|
|
507
550
|
# Calibration extraction lives in euler_eval.calibration (imported above with
|
|
508
551
|
# private aliases that tests import from euler_eval.evaluate).
|
|
509
552
|
|
|
@@ -582,6 +625,7 @@ def evaluate_depth_samples(
|
|
|
582
625
|
alignment_mode: str = "auto_affine",
|
|
583
626
|
benchmark_depth_range: Optional[tuple[float, float]] = None,
|
|
584
627
|
input_space_hint: Optional[str] = None,
|
|
628
|
+
sky_depth: Optional[float] = None,
|
|
585
629
|
) -> dict:
|
|
586
630
|
"""Evaluate all depth metrics from a MultiModalDataset.
|
|
587
631
|
|
|
@@ -607,6 +651,11 @@ def evaluate_depth_samples(
|
|
|
607
651
|
input_space_hint: Optional declaration from the prediction config.
|
|
608
652
|
``relative`` or ``affine`` makes ``auto_affine`` run alignment
|
|
609
653
|
even when values are outside the normalized range.
|
|
654
|
+
sky_depth: Optional finite positive maximum evaluation depth in meters.
|
|
655
|
+
After conversion/alignment, cap GT and both prediction branches and
|
|
656
|
+
fill ``sample["pred_sky_mask"]`` pixels (True = sky) with this value.
|
|
657
|
+
Predicted sky is excluded from affine fitting, but remains scored
|
|
658
|
+
unless excluded by GT validity or ``sky_mask_enabled``.
|
|
610
659
|
|
|
611
660
|
Returns:
|
|
612
661
|
Dictionary containing depth aggregate/per-file metrics with:
|
|
@@ -614,6 +663,7 @@ def evaluate_depth_samples(
|
|
|
614
663
|
backward-compatible canonical ``depth``, and optionally
|
|
615
664
|
per-space ``depth_benchmark`` summaries.
|
|
616
665
|
"""
|
|
666
|
+
validate_sky_depth(sky_depth)
|
|
617
667
|
valid_alignment_modes = {"none", "auto_affine", "affine"}
|
|
618
668
|
if alignment_mode not in valid_alignment_modes:
|
|
619
669
|
raise ValueError(
|
|
@@ -1095,6 +1145,11 @@ def evaluate_depth_samples(
|
|
|
1095
1145
|
|
|
1096
1146
|
depth_gt = process_depth(depth_gt, is_radial, intrinsics_K)
|
|
1097
1147
|
depth_pred_raw = process_depth(depth_pred, is_radial, intrinsics_K)
|
|
1148
|
+
pred_sky_mask = (
|
|
1149
|
+
_get_prediction_sky_mask(sample, depth_pred)
|
|
1150
|
+
if sky_depth is not None
|
|
1151
|
+
else None
|
|
1152
|
+
)
|
|
1098
1153
|
|
|
1099
1154
|
if alignment_mode == "none":
|
|
1100
1155
|
depth_pred_aligned = depth_pred_raw
|
|
@@ -1114,6 +1169,8 @@ def evaluate_depth_samples(
|
|
|
1114
1169
|
)
|
|
1115
1170
|
if sky_valid is not None:
|
|
1116
1171
|
fit_mask = fit_mask & sky_valid
|
|
1172
|
+
if pred_sky_mask is not None:
|
|
1173
|
+
fit_mask &= ~pred_sky_mask
|
|
1117
1174
|
depth_pred_aligned, s, t = compute_scale_and_shift(
|
|
1118
1175
|
fit_source,
|
|
1119
1176
|
depth_gt,
|
|
@@ -1130,6 +1187,11 @@ def evaluate_depth_samples(
|
|
|
1130
1187
|
else:
|
|
1131
1188
|
depth_pred_aligned = depth_pred_raw
|
|
1132
1189
|
|
|
1190
|
+
depth_gt, depth_pred_raw, depth_pred_aligned = _apply_sky_depth(
|
|
1191
|
+
depth_gt, depth_pred_raw, depth_pred_aligned,
|
|
1192
|
+
sky_depth, pred_sky_mask,
|
|
1193
|
+
)
|
|
1194
|
+
|
|
1133
1195
|
if verbose and not logged_stats:
|
|
1134
1196
|
_log_sample_stats(depth_gt, depth_pred_aligned, "DEPTH")
|
|
1135
1197
|
logged_stats = True
|
|
@@ -1577,6 +1639,7 @@ def evaluate_sparse_depth_samples(
|
|
|
1577
1639
|
alignment_mode: str = "auto_affine",
|
|
1578
1640
|
benchmark_depth_range: Optional[tuple[float, float]] = None,
|
|
1579
1641
|
input_space_hint: Optional[str] = None,
|
|
1642
|
+
sky_depth: Optional[float] = None,
|
|
1580
1643
|
) -> dict:
|
|
1581
1644
|
"""Evaluate dense depth predictions against sparse pointcloud GT.
|
|
1582
1645
|
|
|
@@ -1584,7 +1647,10 @@ def evaluate_sparse_depth_samples(
|
|
|
1584
1647
|
dense prediction image plane, and metrics are computed only at projected
|
|
1585
1648
|
valid pixels. The emitted metric categories intentionally exclude dense
|
|
1586
1649
|
image/geometric metrics such as SSIM, LPIPS, FID, normals, and edge F1.
|
|
1650
|
+
``sky_depth`` caps projected GT and predictions and fills optional
|
|
1651
|
+
``sample["pred_sky_mask"]`` pixels, as in :func:`evaluate_depth_samples`.
|
|
1587
1652
|
"""
|
|
1653
|
+
validate_sky_depth(sky_depth)
|
|
1588
1654
|
valid_alignment_modes = {"none", "auto_affine", "affine"}
|
|
1589
1655
|
if alignment_mode not in valid_alignment_modes:
|
|
1590
1656
|
raise ValueError(
|
|
@@ -1838,6 +1904,11 @@ def evaluate_sparse_depth_samples(
|
|
|
1838
1904
|
depth_pred_raw = process_depth(
|
|
1839
1905
|
depth_pred, pred_is_radial, intrinsics_K
|
|
1840
1906
|
)
|
|
1907
|
+
pred_sky_mask = (
|
|
1908
|
+
_get_prediction_sky_mask(sample, depth_pred)
|
|
1909
|
+
if sky_depth is not None
|
|
1910
|
+
else None
|
|
1911
|
+
)
|
|
1841
1912
|
|
|
1842
1913
|
if alignment_mode == "none":
|
|
1843
1914
|
depth_pred_aligned = depth_pred_raw
|
|
@@ -1853,6 +1924,8 @@ def evaluate_sparse_depth_samples(
|
|
|
1853
1924
|
)
|
|
1854
1925
|
if sky_valid is not None:
|
|
1855
1926
|
fit_mask &= sky_valid
|
|
1927
|
+
if pred_sky_mask is not None:
|
|
1928
|
+
fit_mask &= ~pred_sky_mask
|
|
1856
1929
|
depth_pred_aligned, s, t = compute_scale_and_shift(
|
|
1857
1930
|
fit_source,
|
|
1858
1931
|
sparse_depth_gt,
|
|
@@ -1869,6 +1942,11 @@ def evaluate_sparse_depth_samples(
|
|
|
1869
1942
|
else:
|
|
1870
1943
|
depth_pred_aligned = depth_pred_raw
|
|
1871
1944
|
|
|
1945
|
+
sparse_depth_gt, depth_pred_raw, depth_pred_aligned = _apply_sky_depth(
|
|
1946
|
+
sparse_depth_gt, depth_pred_raw, depth_pred_aligned,
|
|
1947
|
+
sky_depth, pred_sky_mask,
|
|
1948
|
+
)
|
|
1949
|
+
|
|
1872
1950
|
if verbose and not logged_stats:
|
|
1873
1951
|
_log_sample_stats(sparse_depth_gt, depth_pred_aligned, "SPARSE DEPTH")
|
|
1874
1952
|
logged_stats = True
|
|
@@ -3498,6 +3576,7 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3498
3576
|
input_space_hint: Optional[str] = None,
|
|
3499
3577
|
max_cloud_points: int = POINTS3D_DEFAULT_MAX_POINTS,
|
|
3500
3578
|
pred_is_depth: bool = True,
|
|
3579
|
+
sky_depth: Optional[float] = None,
|
|
3501
3580
|
) -> dict:
|
|
3502
3581
|
"""Evaluate a depth **or** ``points_3d`` prediction against sparse GT.
|
|
3503
3582
|
|
|
@@ -3555,6 +3634,9 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3555
3634
|
max_cloud_points: Per-cloud subsample cap for the cloud-distance query.
|
|
3556
3635
|
pred_is_depth: Whether the prediction is a dense depth map (unprojected)
|
|
3557
3636
|
or a native ``points_3d`` map (scored directly).
|
|
3637
|
+
sky_depth: Optional depth cap and predicted-sky fill value, supported
|
|
3638
|
+
for depth predictions. GT points are capped radially, preserving
|
|
3639
|
+
their directions, to match the sparse-depth evaluation range.
|
|
3558
3640
|
|
|
3559
3641
|
Returns:
|
|
3560
3642
|
Dict shaped like :func:`evaluate_points_3d_samples`:
|
|
@@ -3562,6 +3644,9 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3562
3644
|
``per_file_metrics``, ``dataset_info``, ``space_info`` and
|
|
3563
3645
|
``spatial_info``.
|
|
3564
3646
|
"""
|
|
3647
|
+
validate_sky_depth(sky_depth)
|
|
3648
|
+
if sky_depth is not None and not pred_is_depth:
|
|
3649
|
+
raise ValueError("sky_depth is only supported for depth predictions")
|
|
3565
3650
|
if pred_is_depth:
|
|
3566
3651
|
valid_alignment_modes = {"none", "auto_affine", "affine"}
|
|
3567
3652
|
valid_input_space_hints = {None, "relative", "affine"}
|
|
@@ -3614,6 +3699,8 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3614
3699
|
dataset_max_depth,
|
|
3615
3700
|
float(np.max(finite_depths)),
|
|
3616
3701
|
)
|
|
3702
|
+
if sky_depth is not None:
|
|
3703
|
+
dataset_max_depth = min(dataset_max_depth, sky_depth)
|
|
3617
3704
|
f_a_max_threshold = dataset_max_depth / 20.0
|
|
3618
3705
|
|
|
3619
3706
|
resolved_domain: Optional[str] = fov_domain
|
|
@@ -3884,6 +3971,11 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3884
3971
|
depth_pred_raw = process_depth(
|
|
3885
3972
|
depth_pred, pred_is_radial, intrinsics_K
|
|
3886
3973
|
)
|
|
3974
|
+
pred_sky_mask = (
|
|
3975
|
+
_get_prediction_sky_mask(sample, depth_pred)
|
|
3976
|
+
if sky_depth is not None
|
|
3977
|
+
else None
|
|
3978
|
+
)
|
|
3887
3979
|
if alignment_mode == "none":
|
|
3888
3980
|
depth_pred_aligned = depth_pred_raw
|
|
3889
3981
|
else:
|
|
@@ -3904,6 +3996,8 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3904
3996
|
)
|
|
3905
3997
|
if sky_valid is not None:
|
|
3906
3998
|
fit_mask &= sky_valid
|
|
3999
|
+
if pred_sky_mask is not None:
|
|
4000
|
+
fit_mask &= ~pred_sky_mask
|
|
3907
4001
|
depth_pred_aligned, s_fit, t_fit = compute_scale_and_shift(
|
|
3908
4002
|
fit_source,
|
|
3909
4003
|
gt_radial,
|
|
@@ -3920,6 +4014,19 @@ def evaluate_points_3d_sparse_samples(
|
|
|
3920
4014
|
else:
|
|
3921
4015
|
depth_pred_aligned = depth_pred_raw
|
|
3922
4016
|
|
|
4017
|
+
if sky_depth is not None:
|
|
4018
|
+
# Keep actual GT ray directions, including subpixel
|
|
4019
|
+
# offsets, while limiting each point's radial depth.
|
|
4020
|
+
gt_scale = np.ones_like(gt_radial)
|
|
4021
|
+
beyond_cap = gt_radial > sky_depth
|
|
4022
|
+
gt_scale[beyond_cap] = sky_depth / gt_radial[beyond_cap]
|
|
4023
|
+
gt_point_map = gt_point_map * gt_scale[..., None]
|
|
4024
|
+
gt_cloud = gt_point_map[gt_valid]
|
|
4025
|
+
gt_radial, depth_pred_raw, depth_pred_aligned = _apply_sky_depth(
|
|
4026
|
+
gt_radial, depth_pred_raw, depth_pred_aligned,
|
|
4027
|
+
sky_depth, pred_sky_mask,
|
|
4028
|
+
)
|
|
4029
|
+
|
|
3923
4030
|
if verbose and not logged_stats:
|
|
3924
4031
|
_log_sample_stats(gt_radial, depth_pred_raw, "SPARSE POINTS_3D")
|
|
3925
4032
|
logged_stats = True
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-eval
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.28.0
|
|
4
4
|
Summary: Evaluation toolkit for depth, RGB, ray and 3D point-map predictions
|
|
5
5
|
Author-email: Daniel Rothenpieler <rothenpielerdaniel@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -158,10 +158,10 @@ straight out of the archive. Full schema: [Configuration](docs/configuration.md)
|
|
|
158
158
|
| Modality | Config key | Scored against | Headline metrics |
|
|
159
159
|
|---|---|---|---|
|
|
160
160
|
| **Depth** | `depth`, `relative_depth`, `affine_depth` | dense GT depth | `absrel`…`delta3`, PSNR/SSIM/LPIPS/FID/KID, surface-normal consistency, depth-edge F1 |
|
|
161
|
-
| **Sparse depth** | `depth` + `gt.sparse_depth` | a LiDAR-style point cloud, projected into the prediction plane | pointwise depth metrics at projected points
|
|
161
|
+
| **Sparse depth** | `depth` + `gt.sparse_depth` | a LiDAR-style point cloud, projected into the prediction plane | pointwise depth metrics at projected points |
|
|
162
162
|
| **RGB** | `rgb` | GT RGB | PSNR, SSIM, LPIPS, FID, SCE, edge F1, tail errors, HF energy ratio, depth-binned photometric error; optional NIQE/FADE dehazing metrics |
|
|
163
163
|
| **Rays** | `rays` | GT ray direction map | ρ_A (angular-accuracy AUC), angular error, threshold percentages |
|
|
164
|
-
| **Points-3D** | `points_3d` | GT point map,
|
|
164
|
+
| **Points-3D** | `points_3d` | GT point map, GT depth unprojected on the fly, or a sparse point cloud | 3D EPE/RMSE/δ, radial-vs-lateral decomposition, true-3D normals and edge F1, Chamfer / F-score |
|
|
165
165
|
|
|
166
166
|
A run evaluates whichever modalities are configured on both sides; a depth-only
|
|
167
167
|
prediction is a perfectly ordinary run. The full inventory, with the key each
|