euler-eval 2.31.0__tar.gz → 2.32.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.31.0/euler_eval.egg-info → euler_eval-2.32.0}/PKG-INFO +5 -3
- {euler_eval-2.31.0 → euler_eval-2.32.0}/README.md +4 -2
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/README.md +1 -1
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/cli.md +4 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/configuration.md +6 -5
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/output.md +133 -10
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/cli.py +237 -24
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/config_paths.py +55 -0
- euler_eval-2.32.0/euler_eval/protocol.py +145 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0/euler_eval.egg-info}/PKG-INFO +5 -3
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval.egg-info/SOURCES.txt +3 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/pyproject.toml +1 -1
- euler_eval-2.32.0/tests/eval_output.py +16 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_cli_sparse_outputs.py +20 -7
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_depth_alignment_output.py +2 -1
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_mask_sky_pairing.py +2 -2
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_mask_sky_prediction.py +2 -2
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_points_3d_sparse.py +8 -8
- euler_eval-2.32.0/tests/test_protocol.py +398 -0
- euler_eval-2.32.0/tests/test_save_results.py +513 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_sky_iou_cli.py +3 -2
- euler_eval-2.31.0/tests/test_save_results.py +0 -301
- {euler_eval-2.31.0 → euler_eval-2.32.0}/LICENSE +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/MANIFEST.in +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/alignment.md +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/distributions.md +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/feature-request-unified-evaluation-framework.md +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/metrics.md +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/docs/validation.md +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/THIRD_PARTY_NOTICES.md +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/__init__.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/calibration.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/data.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/distribution_contract.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/distributions.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/evaluate.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metric_sets.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/__init__.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/_natural_scene_models.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/absrel.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/daniel_error.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/depth_binned_error.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/depth_standard.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/fade.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/fid_kid.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/high_freq_energy.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/lpips_metric.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/niqe.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/normal_consistency.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/points3d_cloud.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/points3d_decomposition.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/points3d_distance.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/points3d_geometry.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/psnr.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/rgb_lpips.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/rho_a.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/rmse.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/sky_iou.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/ssim.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/tail_errors.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/metrics/utils.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/sanity_checker.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/schemas/distribution-v1.schema.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/utils/hierarchy_parser.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval/validation.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval.egg-info/dependency_links.txt +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval.egg-info/entry_points.txt +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval.egg-info/requires.txt +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/euler_eval.egg-info/top_level.txt +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/init_cache.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/scripts/generate_distribution_fixtures.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/setup.cfg +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/__init__.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/conftest.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/distribution_contract_utils.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/README.md +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/counts-depth.eval.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/counts-points3d.eval.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/counts-sparsedepth.eval.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/future-sum-by-depth.eval.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/histogram-only.eval.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/per-file-only.eval.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/fixtures/distributions/scalar-only.eval.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/mock_files/calibration_output.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/mock_files/depth_output.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/mock_files/rgb_output.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/mock_files/segmentation_output.json +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_alignment.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_cli_device.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_config.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_data.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_data_builders.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_depth_standard.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_distribution_contract.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_distributions.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_domain_metrics.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_evaluate_helpers.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_init_cache.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_integration.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_meta_output.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_metrics_utils.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_normal_consistency.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_points_3d.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_rgb_fid_output.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_rho_a.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_sky_iou.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.0}/tests/test_sparse_depth.py +0 -0
- {euler_eval-2.31.0 → euler_eval-2.32.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.32.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
|
|
@@ -133,8 +133,10 @@ euler-eval config.json --batch-size 32
|
|
|
133
133
|
|
|
134
134
|
Ground truth and prediction files are matched by ID rather than by directory
|
|
135
135
|
order, so an incomplete prediction set scores the frames it does have instead of
|
|
136
|
-
silently comparing the wrong pairs. Results are written
|
|
137
|
-
|
|
136
|
+
silently comparing the wrong pairs. Results are written into each prediction
|
|
137
|
+
dataset, under `.eval/` beside its `.ds_crawler/` metadata — e.g.
|
|
138
|
+
`/data/model_a/depth/.eval/eval.json`, or `.eval/<scope>/eval.json` for a scoped
|
|
139
|
+
dataset ([details](docs/output.md#where-results-land)):
|
|
138
140
|
|
|
139
141
|
```json
|
|
140
142
|
{
|
|
@@ -83,8 +83,10 @@ euler-eval config.json --batch-size 32
|
|
|
83
83
|
|
|
84
84
|
Ground truth and prediction files are matched by ID rather than by directory
|
|
85
85
|
order, so an incomplete prediction set scores the frames it does have instead of
|
|
86
|
-
silently comparing the wrong pairs. Results are written
|
|
87
|
-
|
|
86
|
+
silently comparing the wrong pairs. Results are written into each prediction
|
|
87
|
+
dataset, under `.eval/` beside its `.ds_crawler/` metadata — e.g.
|
|
88
|
+
`/data/model_a/depth/.eval/eval.json`, or `.eval/<scope>/eval.json` for a scoped
|
|
89
|
+
dataset ([details](docs/output.md#where-results-land)):
|
|
88
90
|
|
|
89
91
|
```json
|
|
90
92
|
{
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| [Spaces & alignment](alignment.md) | Why `native` and `metric` exist, depth affine fitting, points-3d gauge alignment, benchmark depth bins |
|
|
8
8
|
| [Metrics](metrics.md) | The full metric inventory per modality, with the key each one is written under |
|
|
9
9
|
| [Error distributions](distributions.md) | Optional per-sample and pooled RMSE histograms, bin settings, axes and JSON layout |
|
|
10
|
-
| [Results & output](output.md) | Where files land, the anatomy of `eval.json`, per-file metrics, the sanity-check report |
|
|
10
|
+
| [Results & output](output.md) | Where files land, the anatomy of `eval.json`, comparing evaluations, per-file metrics, the sanity-check report |
|
|
11
11
|
| [In-training validation](validation.md) | The programmatic API for scoring in-memory predictions during training |
|
|
12
12
|
|
|
13
13
|
## Proposed features
|
|
@@ -37,6 +37,7 @@ validation exits with status `1` before any dataset is opened.
|
|
|
37
37
|
| `--distribution-bins` | `int` | `50` | Total histogram bins, including tails; minimum 3 |
|
|
38
38
|
| `--distribution-scale` | `{log,linear}` | `log` | Spacing of finite histogram bins |
|
|
39
39
|
| `--distribution-range` | `float float` | `0.001 100` | Finite error range `[MIN, MAX)` in evaluated space units; zero/small-error and overflow bins retain the tails |
|
|
40
|
+
| `--eval-name` | `str` | `eval` | Name this evaluation: results are written as `<name>.json` in each prediction dataset's `.eval/` folder, so differently named runs sit side by side; a dataset's `output_file` still wins ([details](output.md#where-results-land)) |
|
|
40
41
|
|
|
41
42
|
Histogram settings can also be specified in the config's `distributions`
|
|
42
43
|
section. A bin, scale or range flag enables histograms and overrides that
|
|
@@ -69,6 +70,9 @@ euler-eval config.json --sky-iou --sky-depth 100
|
|
|
69
70
|
# Only depth evaluation
|
|
70
71
|
euler-eval config.json --skip-rgb --skip-rays --skip-points-3d
|
|
71
72
|
|
|
73
|
+
# Keep a sky-masked run beside the default results: .eval/[<scope>/]no_sky.json
|
|
74
|
+
euler-eval config.json --mask-sky --eval-name no_sky
|
|
75
|
+
|
|
72
76
|
# Force affine scale+shift alignment on all depth predictions
|
|
73
77
|
euler-eval config.json --depth-alignment affine
|
|
74
78
|
|
|
@@ -127,7 +127,7 @@ would be ambiguous.
|
|
|
127
127
|
| `sky_mask.path` | no | Auxiliary predicted sky mask for a dense depth entry; used with `--sky-depth`, `--mask-sky-prediction` and `--sky-iou` |
|
|
128
128
|
| `rays.path` | no\* | Predicted ray direction map dataset |
|
|
129
129
|
| `points_3d.path` | no\* | Predicted per-pixel 3D point map `(H,W,3)` |
|
|
130
|
-
| `output_file` | no | Custom results path (default:
|
|
130
|
+
| `output_file` | no | Custom results path for every modality of this entry, replacing the `.eval/` layout and `--eval-name` (default: `.eval/[<scope>/][split_<split>/]eval.json` in each prediction modality's dataset root; see [where results land](output.md#where-results-land)) |
|
|
131
131
|
|
|
132
132
|
\* At least one prediction modality must be present.
|
|
133
133
|
|
|
@@ -214,10 +214,11 @@ and evaluated as `points_3d`.
|
|
|
214
214
|
|
|
215
215
|
An explicit `datasets[].points_3d` prediction can be evaluated separately
|
|
216
216
|
against the same sparse cloud. That evaluation uses the points-3D similarity
|
|
217
|
-
gauge, writes an atomic `points3d.eval` metric set
|
|
218
|
-
prediction, and is controlled by `--skip-points-3d`. If a dataset
|
|
219
|
-
depth and `points_3d`, each prediction modality gets its own
|
|
220
|
-
|
|
217
|
+
gauge, writes an atomic `points3d.eval` metric set to the point-map
|
|
218
|
+
prediction's results file, and is controlled by `--skip-points-3d`. If a dataset
|
|
219
|
+
provides both depth and `points_3d`, each prediction modality gets its own
|
|
220
|
+
results file, also when both live in one archive under separate scopes (see
|
|
221
|
+
[where results land](output.md#where-results-land)).
|
|
221
222
|
|
|
222
223
|
Sparse depth does not require segmentation GT. `gt.segmentation` is loaded only
|
|
223
224
|
when `--mask-sky` or `--sky-iou` is set. `--mask-sky` excludes sky pixels from
|
|
@@ -2,20 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
## Where results land
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
the dataset whose depth path is `/data/model_a/depth`, and so on. If that path
|
|
8
|
-
passes through a `.zip`, the JSON is written *into* the archive rather than
|
|
9
|
-
beside it, so zip-backed datasets stay self-contained.
|
|
5
|
+
Results are written **per modality, per prediction dataset**, into a `.eval/`
|
|
6
|
+
folder at the prediction dataset's root, beside its `.ds_crawler/` metadata:
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
```text
|
|
9
|
+
/data/model_a/ # a datasets[].<modality>.path
|
|
10
|
+
.ds_crawler/
|
|
11
|
+
depth/ rgb/ # ds-crawler metadata scopes
|
|
12
|
+
.eval/
|
|
13
|
+
depth/
|
|
14
|
+
eval.json # depth results
|
|
15
|
+
no_sky.json # depth results of --eval-name no_sky
|
|
16
|
+
split_test/eval.json # depth results for "/data/model_a:test"
|
|
17
|
+
rgb/
|
|
18
|
+
eval.json # rgb results
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The folder below `.eval/` mirrors how the prediction was loaded:
|
|
22
|
+
|
|
23
|
+
| Prediction | Results file |
|
|
24
|
+
|---|---|
|
|
25
|
+
| Metadata scope with its own `.ds_crawler/<scope>/` | `.eval/<scope>/<name>.json` |
|
|
26
|
+
| Root-level `.ds_crawler/` metadata (no scope) | `.eval/<name>.json` |
|
|
27
|
+
| A split is selected (`:test` or `split`) | `split_<split>/` is added before the file name |
|
|
28
|
+
|
|
29
|
+
The scope is the path's `#scope=` selector, otherwise the config key (`depth`,
|
|
30
|
+
`relative_depth`, `rgb`, `points_3d`, …). As in euler-loading, a scope without
|
|
31
|
+
metadata of its own falls back to the root-level `.ds_crawler/`, and so do its
|
|
32
|
+
results. This way modalities and splits that share one dataset root or archive
|
|
33
|
+
each get their own file. If the root is a `.zip`, `.eval/` is written *into* the
|
|
34
|
+
archive (inside its top-level folder when the archive wraps everything in one
|
|
35
|
+
named after it), so zip-backed datasets stay self-contained.
|
|
36
|
+
|
|
37
|
+
`<name>` is `eval` unless the run is named with `--eval-name`:
|
|
38
|
+
`--mask-sky --eval-name no_sky` writes `no_sky.json` next to an earlier
|
|
39
|
+
`eval.json` instead of replacing it. Names use letters, digits, `.`, `-` and
|
|
40
|
+
`_`; `.json` is appended.
|
|
41
|
+
|
|
42
|
+
`output_file` in a dataset entry overrides all of this. It is one path for the
|
|
43
|
+
whole dataset entry: every modality evaluated for that entry is written to it,
|
|
44
|
+
and the last one written replaces the others, so use it for single-modality
|
|
45
|
+
entries.
|
|
46
|
+
|
|
47
|
+
Earlier releases wrote `eval.json` directly at the dataset root (inside the
|
|
48
|
+
archive for zips). Readers such as euler-view look in `.eval/<scope>/`, then
|
|
49
|
+
`.eval/`, then fall back to that legacy location.
|
|
14
50
|
|
|
15
51
|
Each `eval.json` is atomic and declares one metric namespace. With
|
|
16
52
|
`gt.sparse_depth`, a depth-family prediction writes only `sparsedepth.eval`; an
|
|
17
|
-
explicit `points_3d` prediction writes only `points3d.eval`
|
|
18
|
-
map. A depth prediction does not implicitly produce a second points-3D metric
|
|
53
|
+
explicit `points_3d` prediction writes only `points3d.eval` to the point
|
|
54
|
+
map's own results file. A depth prediction does not implicitly produce a second points-3D metric
|
|
19
55
|
set.
|
|
20
56
|
|
|
21
57
|
## Anatomy of `eval.json`
|
|
@@ -37,6 +73,10 @@ set.
|
|
|
37
73
|
"axes": { "space": { "…": "…" }, "category": { "…": "…" } },
|
|
38
74
|
"metricDescriptions": { "absrel": { "…": "…" } }
|
|
39
75
|
},
|
|
76
|
+
"protocol": {
|
|
77
|
+
"schemaVersion": "1.0",
|
|
78
|
+
"parameters": { "reference.gt.dataset": "muses", "method.depth_alignment": "auto_affine", "…": "…" }
|
|
79
|
+
},
|
|
40
80
|
"dataset_info": { "num_pairs": 500, "gt_name": "GT", "pred_name": "model_a" },
|
|
41
81
|
"meta": {
|
|
42
82
|
"version": "2.25.0",
|
|
@@ -56,6 +96,7 @@ set.
|
|
|
56
96
|
| Block | What it is for |
|
|
57
97
|
|---|---|
|
|
58
98
|
| `metricSet` | The euler-metric-naming envelope: producer, namespace, axis declarations and per-metric descriptions (unit, direction, bounds), plus how the spaces were resolved |
|
|
99
|
+
| `protocol` | The comparison keys: every setting that changes metric values, as a flat map ([Comparing evaluations](#comparing-evaluations)) |
|
|
59
100
|
| `dataset_info` | How many pairs were actually matched, and the display names of both sides |
|
|
60
101
|
| `meta` | Full provenance: package version, device, both source paths and their resolved dimensions, modality metadata, and the effective evaluation flags |
|
|
61
102
|
| *metric tree* | The metrics themselves, under the modality root (`depth`, `rgb`, `rays`, `sparsedepth`, `points3d`) |
|
|
@@ -137,6 +178,88 @@ because these keys have no depth space. `metricDescriptions` gains `iou`,
|
|
|
137
178
|
`precision` and `recall` (higher is better, bounds `[0, 1]`). Every other key
|
|
138
179
|
decomposes exactly as before.
|
|
139
180
|
|
|
181
|
+
## Comparing evaluations
|
|
182
|
+
|
|
183
|
+
`protocol.parameters` says how an evaluation was set up, as one flat map of
|
|
184
|
+
dotted keys. Its keys are the comparison keys: two evaluations of the same
|
|
185
|
+
modality were set up the same way when their maps are equal, and the keys whose
|
|
186
|
+
values differ say where. Nothing else in the file needs to be compared for that;
|
|
187
|
+
`meta` stays the full record of the run, paths and device included.
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
"protocol": {
|
|
191
|
+
"schemaVersion": "1.0",
|
|
192
|
+
"parameters": {
|
|
193
|
+
"reference.gt.modality": "sparse_depth",
|
|
194
|
+
"reference.gt.dataset": "seeingthroughfog",
|
|
195
|
+
"reference.gt.scope": "sparse_depth",
|
|
196
|
+
"reference.gt.split": "test",
|
|
197
|
+
"reference.intrinsics.dataset": "seeingthroughfog",
|
|
198
|
+
"reference.intrinsics.scope": "intrinsics",
|
|
199
|
+
"reference.intrinsics.split": "test",
|
|
200
|
+
"reference.camera_extrinsics.dataset": "seeingthroughfog",
|
|
201
|
+
"reference.camera_extrinsics.scope": "camera_extrinsics",
|
|
202
|
+
"reference.camera_extrinsics.split": "test",
|
|
203
|
+
"reference.lidar_extrinsics.dataset": null,
|
|
204
|
+
"reference.lidar_extrinsics.scope": null,
|
|
205
|
+
"reference.lidar_extrinsics.split": null,
|
|
206
|
+
"reference.segmentation.dataset": null,
|
|
207
|
+
"reference.segmentation.scope": null,
|
|
208
|
+
"reference.segmentation.split": null,
|
|
209
|
+
"population.samples": 943,
|
|
210
|
+
"population.gt_sky_masking": false,
|
|
211
|
+
"population.pred_sky_masking": false,
|
|
212
|
+
"population.evaluated_resolution": [1024, 1920],
|
|
213
|
+
"population.benchmark_depth_range_m": [0.01, 80.0],
|
|
214
|
+
"method.metrics_revision": 1,
|
|
215
|
+
"method.depth_alignment": "auto_affine",
|
|
216
|
+
"method.sky_depth_m": null
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The first segment of a key is its section:
|
|
222
|
+
|
|
223
|
+
| Section | Holds |
|
|
224
|
+
|---|---|
|
|
225
|
+
| `reference` | The GT the prediction is scored against (`gt`, with its config key as `modality`) and every other GT input the modality reads, each identified by `dataset` (the `dataset.id` of its `dataset-head.json`), metadata `scope` and `split` — not by file path, so the same data on another machine matches |
|
|
226
|
+
| `population` | Which samples and pixels were scored: the matched `samples`, sky masking, the grid the metrics were computed on and benchmark depth bins |
|
|
227
|
+
| `method` | How they were scored: alignment modes, the sky-depth cap, how GT and prediction resolutions were reconciled, the FID backend and `metrics_revision` |
|
|
228
|
+
|
|
229
|
+
What is recorded, per modality:
|
|
230
|
+
|
|
231
|
+
| Modality | `reference` inputs besides `gt` | `population` | `method` |
|
|
232
|
+
|---|---|---|---|
|
|
233
|
+
| `depth` | `calibration`, `segmentation` | `samples`, `gt_sky_masking`, `pred_sky_masking`, `evaluated_resolution`, `benchmark_depth_range_m` | `depth_alignment`, `sky_depth_m`, `spatial_alignment` |
|
|
234
|
+
| `sparsedepth` | `intrinsics`, `camera_extrinsics`, `lidar_extrinsics`, `segmentation` | as `depth` | `depth_alignment`, `sky_depth_m` |
|
|
235
|
+
| `rgb` | `depth`, `calibration`, `segmentation` | `samples`, `gt_sky_masking`, `evaluated_resolution`, `benchmark_depth_range_m` | `fid_backend`, `spatial_alignment` |
|
|
236
|
+
| `rays` | `calibration` | `samples`, `evaluated_resolution` | `spatial_alignment` |
|
|
237
|
+
| `points3d` (dense) | `intrinsics`, `calibration`, `segmentation` | `samples`, `gt_sky_masking`, `evaluated_resolution` | `points_3d_alignment`, `spatial_alignment` |
|
|
238
|
+
| `points3d` (sparse GT) | `intrinsics`, `camera_extrinsics`, `lidar_extrinsics`, `segmentation` | `samples`, `gt_sky_masking`, `evaluated_resolution` | `points_3d_alignment` |
|
|
239
|
+
|
|
240
|
+
Every modality also has `method.metrics_revision`.
|
|
241
|
+
|
|
242
|
+
Rules that keep comparisons a plain map comparison:
|
|
243
|
+
|
|
244
|
+
- Only settings that change the value of a metric both files contain are
|
|
245
|
+
parameters. `--domain`, `--sky-iou` and histogram settings only add metrics
|
|
246
|
+
(histograms describe their bins in the distribution registry); device, batch
|
|
247
|
+
size, workers, paths and `--eval-name` do not change values.
|
|
248
|
+
- Every key of a modality is always written, `null` or `false` when off, so a
|
|
249
|
+
key missing from one side means "not recorded", never "off". Compare the union
|
|
250
|
+
of both key sets.
|
|
251
|
+
- Values are scalars or lists of scalars, never objects.
|
|
252
|
+
- `method.metrics_revision` changes only when a release changes metric values
|
|
253
|
+
for identical inputs and settings, which the [changelog](../CHANGELOG.md)
|
|
254
|
+
then says. Different revisions are not comparable even when every other
|
|
255
|
+
key matches.
|
|
256
|
+
- Settings are recorded, not what they caused. With `--mask-sky-prediction`,
|
|
257
|
+
`population.pred_sky_masking` is `true` for every prediction, while
|
|
258
|
+
`meta.pred_sky_masking` records how much each model's own sky removed;
|
|
259
|
+
`metricSet.metadata` records whether an alignment was actually applied.
|
|
260
|
+
- Renaming or removing a key bumps the major `schemaVersion`; adding one bumps
|
|
261
|
+
the minor version.
|
|
262
|
+
|
|
140
263
|
## Spaces and canonical aliases
|
|
141
264
|
|
|
142
265
|
Depth-like and points-3d results are nested by space:
|
|
@@ -11,16 +11,19 @@ import importlib.metadata
|
|
|
11
11
|
import json
|
|
12
12
|
import math
|
|
13
13
|
import platform
|
|
14
|
+
import re
|
|
14
15
|
import sys
|
|
15
16
|
import zipfile
|
|
16
17
|
from dataclasses import replace
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
|
|
19
20
|
import torch
|
|
21
|
+
from ds_crawler.zip_utils import get_zip_root_prefix
|
|
20
22
|
|
|
21
23
|
from .config_paths import (
|
|
22
24
|
GT_SEGMENTATION_KEYS,
|
|
23
25
|
normalize_modality_path,
|
|
26
|
+
resolve_dataset_location,
|
|
24
27
|
resolve_gt_segmentation_path,
|
|
25
28
|
)
|
|
26
29
|
from .data import (
|
|
@@ -53,6 +56,7 @@ from .metric_sets import (
|
|
|
53
56
|
resolve_metric_sets,
|
|
54
57
|
selected_domain_categories,
|
|
55
58
|
)
|
|
59
|
+
from .protocol import build_protocol, evaluated_resolution, reference_identities
|
|
56
60
|
from .sanity_checker import SanityChecker
|
|
57
61
|
|
|
58
62
|
try:
|
|
@@ -1151,10 +1155,82 @@ def _save_json_to_zip(zip_path: Path, internal_name: str, data: dict) -> None:
|
|
|
1151
1155
|
zf.writestr(internal_name, json_bytes)
|
|
1152
1156
|
|
|
1153
1157
|
|
|
1158
|
+
EVAL_DIR = ".eval"
|
|
1159
|
+
DEFAULT_EVAL_NAME = "eval"
|
|
1160
|
+
_EVAL_NAME_PATTERN = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]*$")
|
|
1161
|
+
|
|
1162
|
+
|
|
1163
|
+
def validate_eval_name(value: str) -> str:
|
|
1164
|
+
"""Validate an evaluation name and return it without a ``.json`` suffix.
|
|
1165
|
+
|
|
1166
|
+
The name becomes the results file name (``<name>.json``) below each
|
|
1167
|
+
prediction dataset's ``.eval/`` folder, so it is one portable path
|
|
1168
|
+
segment, like a ds-crawler split or scope name.
|
|
1169
|
+
|
|
1170
|
+
Raises:
|
|
1171
|
+
ValueError: When *value* is not a plain name.
|
|
1172
|
+
"""
|
|
1173
|
+
name = value.strip()
|
|
1174
|
+
if name.endswith(".json"):
|
|
1175
|
+
name = name[: -len(".json")]
|
|
1176
|
+
if not _EVAL_NAME_PATTERN.match(name):
|
|
1177
|
+
raise ValueError(
|
|
1178
|
+
f"{value!r} is not a valid evaluation name: use letters, digits, "
|
|
1179
|
+
"'.', '-' or '_', starting with a letter or digit (e.g. 'no_sky'); "
|
|
1180
|
+
"'.json' is appended."
|
|
1181
|
+
)
|
|
1182
|
+
return name
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
def default_eval_path(
|
|
1186
|
+
modality_path: str | Path,
|
|
1187
|
+
*,
|
|
1188
|
+
modality_key: str,
|
|
1189
|
+
split: str | None = None,
|
|
1190
|
+
eval_name: str = DEFAULT_EVAL_NAME,
|
|
1191
|
+
) -> Path:
|
|
1192
|
+
"""Return where a prediction modality's results land by default.
|
|
1193
|
+
|
|
1194
|
+
Results go to a dataset-level ``.eval/`` folder beside ``.ds_crawler/``:
|
|
1195
|
+
``.eval/<scope>/`` when the modality's metadata scope (the ``#scope=``
|
|
1196
|
+
selector, else the config key) has its own ``.ds_crawler/<scope>/``
|
|
1197
|
+
metadata, otherwise ``.eval/`` itself, matching how euler-loading falls
|
|
1198
|
+
back to root-level metadata. A selected split adds ``split_<split>/``.
|
|
1199
|
+
"""
|
|
1200
|
+
root, scope, split = resolve_dataset_location(
|
|
1201
|
+
modality_path, modality_key=modality_key, split=split
|
|
1202
|
+
)
|
|
1203
|
+
eval_dir = root / EVAL_DIR
|
|
1204
|
+
if scope is not None:
|
|
1205
|
+
eval_dir = eval_dir / scope
|
|
1206
|
+
if split is not None:
|
|
1207
|
+
eval_dir = eval_dir / f"split_{split}"
|
|
1208
|
+
return eval_dir / f"{eval_name}.json"
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
def _zip_internal_name(zip_path: Path, internal_name: str) -> str:
|
|
1212
|
+
"""Place *internal_name* inside a zip's wrapper folder, if it has one.
|
|
1213
|
+
|
|
1214
|
+
ds-crawler treats a single top-level folder named after the archive
|
|
1215
|
+
(``model.zip`` -> ``model/``) as the dataset root. Writing beside that
|
|
1216
|
+
folder would end the single-root layout and hide ``.ds_crawler/``.
|
|
1217
|
+
"""
|
|
1218
|
+
prefix = get_zip_root_prefix(zip_path)
|
|
1219
|
+
if (
|
|
1220
|
+
prefix
|
|
1221
|
+
and prefix.rstrip("/") == zip_path.stem
|
|
1222
|
+
and not internal_name.startswith(prefix)
|
|
1223
|
+
):
|
|
1224
|
+
return prefix + internal_name
|
|
1225
|
+
return internal_name
|
|
1226
|
+
|
|
1227
|
+
|
|
1154
1228
|
def save_results(
|
|
1155
1229
|
results: dict,
|
|
1156
1230
|
dataset_config: dict,
|
|
1157
1231
|
modality: str | None = None,
|
|
1232
|
+
*,
|
|
1233
|
+
eval_name: str = DEFAULT_EVAL_NAME,
|
|
1158
1234
|
) -> Path:
|
|
1159
1235
|
"""Save results to output file.
|
|
1160
1236
|
|
|
@@ -1168,6 +1244,10 @@ def save_results(
|
|
|
1168
1244
|
modality: When set, save to this specific modality's path
|
|
1169
1245
|
(e.g. ``"depth"`` or ``"rgb"``). Falls back to the first
|
|
1170
1246
|
available modality path when *None*.
|
|
1247
|
+
eval_name: Evaluation name (``--eval-name``); results are written
|
|
1248
|
+
as ``<eval_name>.json`` in the dataset's ``.eval/`` layout, see
|
|
1249
|
+
:func:`default_eval_path`. A dataset's explicit ``output_file``
|
|
1250
|
+
takes precedence over the whole layout.
|
|
1171
1251
|
|
|
1172
1252
|
Returns:
|
|
1173
1253
|
Path where results were saved.
|
|
@@ -1177,38 +1257,38 @@ def save_results(
|
|
|
1177
1257
|
selected_modality = modality
|
|
1178
1258
|
if selected_modality == "depth" and "depth" not in dataset_config:
|
|
1179
1259
|
selected_modality, _ = _prediction_depth_entry(dataset_config)
|
|
1180
|
-
if (
|
|
1260
|
+
if not (
|
|
1181
1261
|
selected_modality is not None
|
|
1182
1262
|
and selected_modality in dataset_config
|
|
1183
1263
|
and "path" in dataset_config[selected_modality]
|
|
1184
1264
|
):
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1265
|
+
# Default: save alongside first available modality path
|
|
1266
|
+
selected_modality = next(
|
|
1267
|
+
(
|
|
1268
|
+
mod
|
|
1269
|
+
for mod in (*_PRED_DEPTH_KEYS, "rgb", "rays")
|
|
1270
|
+
if mod in dataset_config and "path" in dataset_config[mod]
|
|
1271
|
+
),
|
|
1272
|
+
None,
|
|
1273
|
+
)
|
|
1274
|
+
if selected_modality is not None:
|
|
1275
|
+
entry = dataset_config[selected_modality]
|
|
1276
|
+
output_file = default_eval_path(
|
|
1277
|
+
entry["path"],
|
|
1278
|
+
modality_key=selected_modality,
|
|
1279
|
+
split=entry.get("split"),
|
|
1280
|
+
eval_name=eval_name,
|
|
1191
1281
|
)
|
|
1192
1282
|
else:
|
|
1193
|
-
|
|
1194
|
-
for mod in (*_PRED_DEPTH_KEYS, "rgb", "rays"):
|
|
1195
|
-
if mod in dataset_config and "path" in dataset_config[mod]:
|
|
1196
|
-
output_file = (
|
|
1197
|
-
normalize_modality_path(
|
|
1198
|
-
dataset_config[mod]["path"],
|
|
1199
|
-
split=dataset_config[mod].get("split"),
|
|
1200
|
-
)
|
|
1201
|
-
/ "eval.json"
|
|
1202
|
-
)
|
|
1203
|
-
break
|
|
1204
|
-
if output_file is None:
|
|
1205
|
-
output_file = Path("eval.json")
|
|
1283
|
+
output_file = Path(f"{eval_name}.json")
|
|
1206
1284
|
else:
|
|
1207
1285
|
output_file = Path(output_file)
|
|
1208
1286
|
|
|
1209
1287
|
zip_path, internal_name = _find_zip_ancestor(output_file)
|
|
1210
1288
|
if zip_path is not None and internal_name:
|
|
1211
|
-
_save_json_to_zip(
|
|
1289
|
+
_save_json_to_zip(
|
|
1290
|
+
zip_path, _zip_internal_name(zip_path, internal_name), results
|
|
1291
|
+
)
|
|
1212
1292
|
else:
|
|
1213
1293
|
output_file.parent.mkdir(parents=True, exist_ok=True)
|
|
1214
1294
|
with open(output_file, "w") as f:
|
|
@@ -1513,12 +1593,27 @@ def main():
|
|
|
1513
1593
|
"--distribution-range", type=float, nargs=2, default=None, metavar=("MIN", "MAX"),
|
|
1514
1594
|
help="Finite histogram range in evaluated space units (default: 0.001 100); tails are included",
|
|
1515
1595
|
)
|
|
1596
|
+
parser.add_argument(
|
|
1597
|
+
"--eval-name",
|
|
1598
|
+
default=DEFAULT_EVAL_NAME,
|
|
1599
|
+
metavar="NAME",
|
|
1600
|
+
help=(
|
|
1601
|
+
"Name this evaluation: results are written as NAME.json in each "
|
|
1602
|
+
"prediction dataset's .eval/ folder, so differently named runs "
|
|
1603
|
+
"sit side by side (default: %(default)s). A dataset's "
|
|
1604
|
+
"output_file still takes precedence."
|
|
1605
|
+
),
|
|
1606
|
+
)
|
|
1516
1607
|
|
|
1517
1608
|
args = parser.parse_args()
|
|
1518
1609
|
try:
|
|
1519
1610
|
validate_sky_depth(args.sky_depth)
|
|
1520
1611
|
except ValueError as e:
|
|
1521
1612
|
parser.error(f"--sky-depth: {e}")
|
|
1613
|
+
try:
|
|
1614
|
+
args.eval_name = validate_eval_name(args.eval_name)
|
|
1615
|
+
except ValueError as e:
|
|
1616
|
+
parser.error(f"--eval-name: {e}")
|
|
1522
1617
|
|
|
1523
1618
|
selected_metric_sets = resolve_metric_sets(args.domains)
|
|
1524
1619
|
|
|
@@ -1629,6 +1724,10 @@ def main():
|
|
|
1629
1724
|
print("-" * 60)
|
|
1630
1725
|
|
|
1631
1726
|
gt = config["gt"]
|
|
1727
|
+
protocol_identities = reference_identities(gt)
|
|
1728
|
+
protocol_benchmark_range = (
|
|
1729
|
+
list(args.benchmark_depth_range) if args.benchmark_depth_range else None
|
|
1730
|
+
)
|
|
1632
1731
|
gt_depth_path = gt.get("depth", {}).get("path")
|
|
1633
1732
|
gt_sparse_depth_path = gt.get("sparse_depth", {}).get("path")
|
|
1634
1733
|
gt_rgb_path = gt.get("rgb", {}).get("path")
|
|
@@ -1825,6 +1924,23 @@ def main():
|
|
|
1825
1924
|
"canonical_space": space_info.get("canonical_space", "metric"),
|
|
1826
1925
|
},
|
|
1827
1926
|
),
|
|
1927
|
+
"protocol": build_protocol(
|
|
1928
|
+
protocol_identities,
|
|
1929
|
+
gt="depth",
|
|
1930
|
+
inputs=("calibration", "segmentation"),
|
|
1931
|
+
population={
|
|
1932
|
+
"samples": depth_dataset_info.get("num_pairs"),
|
|
1933
|
+
"gt_sky_masking": bool(args.mask_sky),
|
|
1934
|
+
"pred_sky_masking": bool(args.mask_sky_prediction),
|
|
1935
|
+
"evaluated_resolution": evaluated_resolution(depth_spatial),
|
|
1936
|
+
"benchmark_depth_range_m": protocol_benchmark_range,
|
|
1937
|
+
},
|
|
1938
|
+
method={
|
|
1939
|
+
"depth_alignment": args.depth_alignment,
|
|
1940
|
+
"sky_depth_m": args.sky_depth,
|
|
1941
|
+
"spatial_alignment": depth_spatial.get("method", "none"),
|
|
1942
|
+
},
|
|
1943
|
+
),
|
|
1828
1944
|
"dataset_info": depth_dataset_info,
|
|
1829
1945
|
"meta": _clean_metric_tree({
|
|
1830
1946
|
"version": _get_version(),
|
|
@@ -2063,6 +2179,29 @@ def main():
|
|
|
2063
2179
|
"canonical_space": space_info.get("canonical_space", "metric"),
|
|
2064
2180
|
},
|
|
2065
2181
|
),
|
|
2182
|
+
"protocol": build_protocol(
|
|
2183
|
+
protocol_identities,
|
|
2184
|
+
gt="sparse_depth",
|
|
2185
|
+
inputs=(
|
|
2186
|
+
"intrinsics",
|
|
2187
|
+
"camera_extrinsics",
|
|
2188
|
+
"lidar_extrinsics",
|
|
2189
|
+
"segmentation",
|
|
2190
|
+
),
|
|
2191
|
+
population={
|
|
2192
|
+
"samples": sparse_depth_dataset_info.get("num_pairs"),
|
|
2193
|
+
"gt_sky_masking": bool(args.mask_sky),
|
|
2194
|
+
"pred_sky_masking": bool(args.mask_sky_prediction),
|
|
2195
|
+
"evaluated_resolution": evaluated_resolution(
|
|
2196
|
+
sparse_depth_spatial
|
|
2197
|
+
),
|
|
2198
|
+
"benchmark_depth_range_m": protocol_benchmark_range,
|
|
2199
|
+
},
|
|
2200
|
+
method={
|
|
2201
|
+
"depth_alignment": args.depth_alignment,
|
|
2202
|
+
"sky_depth_m": args.sky_depth,
|
|
2203
|
+
},
|
|
2204
|
+
),
|
|
2066
2205
|
"dataset_info": sparse_depth_dataset_info,
|
|
2067
2206
|
"meta": _clean_metric_tree({
|
|
2068
2207
|
"version": _get_version(),
|
|
@@ -2294,6 +2433,21 @@ def main():
|
|
|
2294
2433
|
]
|
|
2295
2434
|
},
|
|
2296
2435
|
),
|
|
2436
|
+
"protocol": build_protocol(
|
|
2437
|
+
protocol_identities,
|
|
2438
|
+
gt="rgb",
|
|
2439
|
+
inputs=("depth", "calibration", "segmentation"),
|
|
2440
|
+
population={
|
|
2441
|
+
"samples": rgb_dataset_info.get("num_pairs"),
|
|
2442
|
+
"gt_sky_masking": bool(args.mask_sky),
|
|
2443
|
+
"evaluated_resolution": evaluated_resolution(rgb_spatial),
|
|
2444
|
+
"benchmark_depth_range_m": protocol_benchmark_range,
|
|
2445
|
+
},
|
|
2446
|
+
method={
|
|
2447
|
+
"fid_backend": args.rgb_fid_backend,
|
|
2448
|
+
"spatial_alignment": rgb_spatial.get("method", "none"),
|
|
2449
|
+
},
|
|
2450
|
+
),
|
|
2297
2451
|
"dataset_info": rgb_dataset_info,
|
|
2298
2452
|
"meta": _clean_metric_tree({
|
|
2299
2453
|
"version": _get_version(),
|
|
@@ -2427,6 +2581,18 @@ def main():
|
|
|
2427
2581
|
"threshold_deg": rays_dataset_info.get("threshold_deg"),
|
|
2428
2582
|
},
|
|
2429
2583
|
),
|
|
2584
|
+
"protocol": build_protocol(
|
|
2585
|
+
protocol_identities,
|
|
2586
|
+
gt="rays",
|
|
2587
|
+
inputs=("calibration",),
|
|
2588
|
+
population={
|
|
2589
|
+
"samples": rays_dataset_info.get("num_pairs"),
|
|
2590
|
+
"evaluated_resolution": evaluated_resolution(rays_spatial),
|
|
2591
|
+
},
|
|
2592
|
+
method={
|
|
2593
|
+
"spatial_alignment": rays_spatial.get("method", "none"),
|
|
2594
|
+
},
|
|
2595
|
+
),
|
|
2430
2596
|
"dataset_info": rays_dataset_info,
|
|
2431
2597
|
"meta": _clean_metric_tree({
|
|
2432
2598
|
"version": _get_version(),
|
|
@@ -2588,6 +2754,20 @@ def main():
|
|
|
2588
2754
|
"threshold_deg": p3_dataset_info.get("threshold_deg"),
|
|
2589
2755
|
},
|
|
2590
2756
|
),
|
|
2757
|
+
"protocol": build_protocol(
|
|
2758
|
+
protocol_identities,
|
|
2759
|
+
gt="depth" if p3d_gt_is_depth else "points_3d",
|
|
2760
|
+
inputs=("intrinsics", "calibration", "segmentation"),
|
|
2761
|
+
population={
|
|
2762
|
+
"samples": p3_dataset_info.get("num_pairs"),
|
|
2763
|
+
"gt_sky_masking": bool(args.mask_sky),
|
|
2764
|
+
"evaluated_resolution": evaluated_resolution(p3_spatial),
|
|
2765
|
+
},
|
|
2766
|
+
method={
|
|
2767
|
+
"points_3d_alignment": args.points_3d_alignment,
|
|
2768
|
+
"spatial_alignment": p3_spatial.get("method", "none"),
|
|
2769
|
+
},
|
|
2770
|
+
),
|
|
2591
2771
|
"dataset_info": p3_dataset_info,
|
|
2592
2772
|
"meta": _clean_metric_tree({
|
|
2593
2773
|
"version": _get_version(),
|
|
@@ -2767,6 +2947,24 @@ def main():
|
|
|
2767
2947
|
"threshold_deg": p3s_dataset_info.get("threshold_deg"),
|
|
2768
2948
|
},
|
|
2769
2949
|
),
|
|
2950
|
+
"protocol": build_protocol(
|
|
2951
|
+
protocol_identities,
|
|
2952
|
+
gt="sparse_depth",
|
|
2953
|
+
inputs=(
|
|
2954
|
+
"intrinsics",
|
|
2955
|
+
"camera_extrinsics",
|
|
2956
|
+
"lidar_extrinsics",
|
|
2957
|
+
"segmentation",
|
|
2958
|
+
),
|
|
2959
|
+
population={
|
|
2960
|
+
"samples": p3s_dataset_info.get("num_pairs"),
|
|
2961
|
+
"gt_sky_masking": bool(args.mask_sky),
|
|
2962
|
+
"evaluated_resolution": evaluated_resolution(p3s_spatial),
|
|
2963
|
+
},
|
|
2964
|
+
method={
|
|
2965
|
+
"points_3d_alignment": p3s_alignment_mode,
|
|
2966
|
+
},
|
|
2967
|
+
),
|
|
2770
2968
|
"dataset_info": p3s_dataset_info,
|
|
2771
2969
|
"meta": _clean_metric_tree({
|
|
2772
2970
|
"version": _get_version(),
|
|
@@ -2845,6 +3043,7 @@ def main():
|
|
|
2845
3043
|
depth_save,
|
|
2846
3044
|
dataset_config,
|
|
2847
3045
|
modality=pred_depth_key or "depth",
|
|
3046
|
+
eval_name=args.eval_name,
|
|
2848
3047
|
)
|
|
2849
3048
|
depth_label = (
|
|
2850
3049
|
"Sparse depth"
|
|
@@ -2853,14 +3052,27 @@ def main():
|
|
|
2853
3052
|
)
|
|
2854
3053
|
print(f"\n {depth_label} results saved to: {depth_out}")
|
|
2855
3054
|
if rgb_save:
|
|
2856
|
-
rgb_out = save_results(
|
|
3055
|
+
rgb_out = save_results(
|
|
3056
|
+
rgb_save,
|
|
3057
|
+
dataset_config,
|
|
3058
|
+
modality="rgb",
|
|
3059
|
+
eval_name=args.eval_name,
|
|
3060
|
+
)
|
|
2857
3061
|
print(f"\n RGB results saved to: {rgb_out}")
|
|
2858
3062
|
if rays_save:
|
|
2859
|
-
rays_out = save_results(
|
|
3063
|
+
rays_out = save_results(
|
|
3064
|
+
rays_save,
|
|
3065
|
+
dataset_config,
|
|
3066
|
+
modality="rays",
|
|
3067
|
+
eval_name=args.eval_name,
|
|
3068
|
+
)
|
|
2860
3069
|
print(f"\n Rays results saved to: {rays_out}")
|
|
2861
3070
|
if points_3d_save:
|
|
2862
3071
|
points_3d_out = save_results(
|
|
2863
|
-
points_3d_save,
|
|
3072
|
+
points_3d_save,
|
|
3073
|
+
dataset_config,
|
|
3074
|
+
modality="points_3d",
|
|
3075
|
+
eval_name=args.eval_name,
|
|
2864
3076
|
)
|
|
2865
3077
|
print(f"\n Points-3D results saved to: {points_3d_out}")
|
|
2866
3078
|
if points_3d_sparse_save:
|
|
@@ -2868,6 +3080,7 @@ def main():
|
|
|
2868
3080
|
points_3d_sparse_save,
|
|
2869
3081
|
dataset_config,
|
|
2870
3082
|
modality="points_3d",
|
|
3083
|
+
eval_name=args.eval_name,
|
|
2871
3084
|
)
|
|
2872
3085
|
print(
|
|
2873
3086
|
f"\n Points-3D (sparse GT) results saved to: {points_3d_sparse_out}"
|