euler-eval 2.28.0__tar.gz → 2.30.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.30.0/MANIFEST.in +3 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/PKG-INFO +2 -1
- euler_eval-2.30.0/docs/README.md +58 -0
- euler_eval-2.30.0/docs/alignment.md +91 -0
- euler_eval-2.30.0/docs/cli.md +150 -0
- euler_eval-2.30.0/docs/configuration.md +269 -0
- euler_eval-2.30.0/docs/distributions.md +296 -0
- euler_eval-2.30.0/docs/feature-request-unified-evaluation-framework.md +381 -0
- euler_eval-2.30.0/docs/metrics.md +168 -0
- euler_eval-2.30.0/docs/output.md +160 -0
- euler_eval-2.30.0/docs/validation.md +109 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/cli.py +128 -16
- euler_eval-2.30.0/euler_eval/distribution_contract.py +183 -0
- euler_eval-2.30.0/euler_eval/distributions.py +167 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/evaluate.py +223 -25
- euler_eval-2.30.0/euler_eval/schemas/distribution-v1.schema.json +113 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval.egg-info/PKG-INFO +2 -1
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval.egg-info/SOURCES.txt +32 -1
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval.egg-info/requires.txt +1 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/pyproject.toml +3 -2
- euler_eval-2.30.0/scripts/generate_distribution_fixtures.py +184 -0
- euler_eval-2.30.0/tests/__init__.py +0 -0
- euler_eval-2.30.0/tests/conftest.py +123 -0
- euler_eval-2.30.0/tests/distribution_contract_utils.py +40 -0
- euler_eval-2.30.0/tests/fixtures/distributions/README.md +42 -0
- euler_eval-2.30.0/tests/fixtures/distributions/counts-depth.eval.json +324 -0
- euler_eval-2.30.0/tests/fixtures/distributions/counts-points3d.eval.json +324 -0
- euler_eval-2.30.0/tests/fixtures/distributions/counts-sparsedepth.eval.json +322 -0
- euler_eval-2.30.0/tests/fixtures/distributions/future-sum-by-depth.eval.json +392 -0
- euler_eval-2.30.0/tests/fixtures/distributions/histogram-only.eval.json +157 -0
- euler_eval-2.30.0/tests/fixtures/distributions/per-file-only.eval.json +274 -0
- euler_eval-2.30.0/tests/fixtures/distributions/scalar-only.eval.json +74 -0
- euler_eval-2.30.0/tests/mock_files/calibration_output.json +19 -0
- euler_eval-2.30.0/tests/mock_files/depth_output.json +32 -0
- euler_eval-2.30.0/tests/mock_files/rgb_output.json +32 -0
- euler_eval-2.30.0/tests/mock_files/segmentation_output.json +32 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_depth_alignment_output.py +20 -0
- euler_eval-2.30.0/tests/test_distribution_contract.py +231 -0
- euler_eval-2.30.0/tests/test_distributions.py +764 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_evaluate_helpers.py +28 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/LICENSE +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/README.md +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/THIRD_PARTY_NOTICES.md +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/__init__.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/calibration.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/config_paths.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/data.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metric_sets.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/__init__.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/_natural_scene_models.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/absrel.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/daniel_error.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/depth_binned_error.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/depth_standard.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/fade.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/fid_kid.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/high_freq_energy.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/lpips_metric.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/niqe.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/normal_consistency.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/points3d_cloud.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/points3d_decomposition.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/points3d_distance.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/points3d_geometry.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/psnr.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/rgb_lpips.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/rho_a.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/rmse.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/ssim.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/tail_errors.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/metrics/utils.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/sanity_checker.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/utils/hierarchy_parser.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval/validation.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval.egg-info/dependency_links.txt +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval.egg-info/entry_points.txt +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/euler_eval.egg-info/top_level.txt +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/init_cache.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/setup.cfg +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_alignment.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_cli_device.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_cli_sparse_outputs.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_config.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_data.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_data_builders.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_depth_standard.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_domain_metrics.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_init_cache.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_integration.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_meta_output.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_metrics_utils.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_normal_consistency.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_points_3d.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_points_3d_sparse.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_rgb_fid_output.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_rho_a.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_save_results.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.0}/tests/test_sparse_depth.py +0 -0
- {euler_eval-2.28.0 → euler_eval-2.30.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.30.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
|
|
@@ -42,6 +42,7 @@ Provides-Extra: fid
|
|
|
42
42
|
Requires-Dist: clean-fid>=0.1.35; extra == "fid"
|
|
43
43
|
Provides-Extra: dev
|
|
44
44
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
45
|
+
Requires-Dist: jsonschema>=4.18; extra == "dev"
|
|
45
46
|
Requires-Dist: pytest-cov>=3.0.0; extra == "dev"
|
|
46
47
|
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
47
48
|
Requires-Dist: ruff>=0.2; extra == "dev"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# euler-eval documentation
|
|
2
|
+
|
|
3
|
+
| Guide | Covers |
|
|
4
|
+
|---|---|
|
|
5
|
+
| [Configuration](configuration.md) | The config file, `gt` and `datasets` sections, paths and selectors, sparse-depth and points-3d ground truth, euler-train logging |
|
|
6
|
+
| [CLI reference](cli.md) | Every flag, worked examples, device selection, offline cache warmup |
|
|
7
|
+
| [Spaces & alignment](alignment.md) | Why `native` and `metric` exist, depth affine fitting, points-3d gauge alignment, benchmark depth bins |
|
|
8
|
+
| [Metrics](metrics.md) | The full metric inventory per modality, with the key each one is written under |
|
|
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 |
|
|
11
|
+
| [In-training validation](validation.md) | The programmatic API for scoring in-memory predictions during training |
|
|
12
|
+
|
|
13
|
+
## Proposed features
|
|
14
|
+
|
|
15
|
+
- [Unified evaluation framework](feature-request-unified-evaluation-framework.md):
|
|
16
|
+
a shared evaluation lifecycle with explicit modality-specific preparation,
|
|
17
|
+
metric dependencies, populations, aggregation and output compatibility.
|
|
18
|
+
|
|
19
|
+
## Concepts in one page
|
|
20
|
+
|
|
21
|
+
**A dataset is an indexed root, not a folder of files.** Every path in the
|
|
22
|
+
config points at a root — a directory or a `.zip` — carrying
|
|
23
|
+
[ds-crawler](https://github.com/d-rothen/ds-crawler) metadata under
|
|
24
|
+
`.ds_crawler/`. That metadata is what makes a path self-describing: it names the
|
|
25
|
+
loader to use, whether depth is radial or planar, what the value range is, and
|
|
26
|
+
which columns of a point cloud are `x,y,z`.
|
|
27
|
+
|
|
28
|
+
**Ground truth and predictions are paired by ID, not by order.**
|
|
29
|
+
[euler-loading](https://github.com/d-rothen/euler-loading) intersects file IDs
|
|
30
|
+
across modalities, so sample *i* holds the GT depth, the predicted depth and the
|
|
31
|
+
RGB frame that genuinely belong together. Files present on one side only are
|
|
32
|
+
left out of the pairing rather than silently misaligned. Calibration and pose
|
|
33
|
+
data are matched hierarchically instead — one intrinsics file can serve every
|
|
34
|
+
sample beneath it in the tree.
|
|
35
|
+
|
|
36
|
+
**Predictions are scored in a space, and there can be two.** A metric model is
|
|
37
|
+
compared to GT directly. A relative or free-frame model first has its unknown
|
|
38
|
+
degrees of freedom fitted away — scale and shift for depth, a similarity
|
|
39
|
+
transform for point maps. euler-eval reports the raw comparison as `native` and
|
|
40
|
+
the fitted one as `metric`, so a scale-recovery failure never masquerades as a
|
|
41
|
+
geometry failure. See [Spaces & alignment](alignment.md).
|
|
42
|
+
|
|
43
|
+
**Per-image scores are reduced three ways.** `image_mean` and `image_median`
|
|
44
|
+
average per-image values across the dataset; `pixel_pool` pools every valid
|
|
45
|
+
pixel first and reduces once. They answer different questions — a few huge
|
|
46
|
+
images dominate `pixel_pool` but not `image_mean` — so all three are reported.
|
|
47
|
+
|
|
48
|
+
**Metric names are structured, not free-form.** Keys are built with
|
|
49
|
+
[euler-metric-naming](https://github.com/d-rothen/euler-metric-naming), so each
|
|
50
|
+
`eval.json` carries a `metricSet` envelope declaring its namespace and axes, and
|
|
51
|
+
consumers such as euler-train and euler-view can decompose a key like
|
|
52
|
+
`depth.eval.metric.standard.image_mean.absrel` structurally rather than by
|
|
53
|
+
string-splitting.
|
|
54
|
+
|
|
55
|
+
**Nothing is computed twice, and nothing is required.** Each modality is
|
|
56
|
+
evaluated only when both GT and prediction sides are configured (and not
|
|
57
|
+
skipped), and results are written per modality — so a depth-only prediction is a
|
|
58
|
+
perfectly valid run.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Spaces & alignment
|
|
2
|
+
|
|
3
|
+
Not every prediction is directly comparable to metric ground truth. A monocular
|
|
4
|
+
depth model may output values that are only correct up to a scale and a shift; a
|
|
5
|
+
point-map model may reconstruct the scene in its own frame entirely. Scoring
|
|
6
|
+
such a prediction as-is measures the missing calibration, not the geometry.
|
|
7
|
+
|
|
8
|
+
euler-eval handles this by fitting away exactly the unknown degrees of freedom
|
|
9
|
+
and reporting **both** results:
|
|
10
|
+
|
|
11
|
+
| Space | Meaning |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `native` | The prediction as the model emitted it, compared to GT directly |
|
|
14
|
+
| `metric` | The prediction after the unknown gauge has been fitted to GT |
|
|
15
|
+
|
|
16
|
+
`native` diagnoses whether the model is metric at all; `metric` isolates
|
|
17
|
+
geometry quality. A canonical alias (`depth`, `points_3d`) points at `metric`
|
|
18
|
+
when it exists, else `native`, so downstream tooling can read one key without
|
|
19
|
+
knowing how the run was configured — see [Results & output](output.md).
|
|
20
|
+
|
|
21
|
+
## Depth alignment
|
|
22
|
+
|
|
23
|
+
Relative depth predictions are aligned to metric GT by fitting a global affine
|
|
24
|
+
map `d_aligned = s · d_pred + t` by least squares over valid pixels.
|
|
25
|
+
`--depth-alignment` controls when the fit runs:
|
|
26
|
+
|
|
27
|
+
| Mode | Behaviour |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `none` | Never fit; score the prediction as-is (already-metric models) |
|
|
30
|
+
| `auto_affine` *(default)* | Fit only when the first prediction looks normalized (roughly `[-1, 1]`) |
|
|
31
|
+
| `affine` | Always fit |
|
|
32
|
+
|
|
33
|
+
The fit uses pixels where GT and prediction are finite and GT > 0. With
|
|
34
|
+
`--mask-sky`, sky pixels are excluded and the fit is trimmed to `gt ≤ P95(gt)`
|
|
35
|
+
so residual sky outliers do not dominate.
|
|
36
|
+
|
|
37
|
+
Declaring the prediction with the `relative_depth` or `affine_depth` config key
|
|
38
|
+
(instead of `depth`) tells the evaluator the model is not metric, so
|
|
39
|
+
`auto_affine` fits even when the values happen to fall outside the normalized
|
|
40
|
+
range — see [Configuration](configuration.md#datasets-section).
|
|
41
|
+
|
|
42
|
+
## Points-3D gauge alignment
|
|
43
|
+
|
|
44
|
+
Point maps from different model families live in different frames, so
|
|
45
|
+
`points_3d` resolves an unknown **similarity gauge** — the 3D generalization of
|
|
46
|
+
depth's scale-and-shift — before the `metric`-space comparison.
|
|
47
|
+
`--points-3d-alignment` selects it:
|
|
48
|
+
|
|
49
|
+
| Mode | Fits | Typical model |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `none` | nothing | Metric, predict-your-own-camera models |
|
|
52
|
+
| `scale` | a single global scalar | Scale-ambiguous but frame-correct predictions |
|
|
53
|
+
| `similarity` | a 7-DoF Umeyama transform `s·R·p + t` over known per-pixel correspondences | Relative / free-frame models |
|
|
54
|
+
| `auto` *(default)* | `similarity` for declared-relative predictions, else nothing | Mixed comparisons |
|
|
55
|
+
|
|
56
|
+
The angular `error_decomposition` ray metrics and `rho_a` are computed on the
|
|
57
|
+
**native** point-map directions — the camera-faithful frame — because rotating
|
|
58
|
+
the cloud into GT would erase exactly the camera error they measure.
|
|
59
|
+
Radial/lateral and Euclidean metrics are reported per space.
|
|
60
|
+
|
|
61
|
+
## Benchmark depth bins
|
|
62
|
+
|
|
63
|
+
`--benchmark-depth-range MIN MAX` filters valid GT depth pixels to `[MIN, MAX]`,
|
|
64
|
+
then splits them into three equal-width intervals in **square-root** depth
|
|
65
|
+
space, which keeps the near field from being compressed into a single bin:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
sqrt_min = sqrt(MIN); sqrt_max = sqrt(MAX); step = (sqrt_max - sqrt_min) / 3
|
|
69
|
+
near = [MIN, (sqrt_min + step)^2)
|
|
70
|
+
mid = [(sqrt_min + step)^2, (sqrt_min + 2·step)^2)
|
|
71
|
+
far = [(sqrt_min + 2·step)^2, MAX]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For `--benchmark-depth-range 0.01 80.0` this yields `near=[0.01, 9.29)`,
|
|
75
|
+
`mid=[9.29, 35.95)`, `far=[35.95, 80.0]`, plus an `all` bin over the full range.
|
|
76
|
+
|
|
77
|
+
Benchmark bins are **additive**: the regular metrics are still computed and
|
|
78
|
+
written exactly as before, with the binned values added under a `bin` axis
|
|
79
|
+
(`…standard.image_mean.near.absrel`) and the resolved boundaries recorded in the
|
|
80
|
+
`metricSet` metadata. RGB metrics are binned too, using GT depth to decide which
|
|
81
|
+
pixels fall in which bin.
|
|
82
|
+
|
|
83
|
+
The same binning is available programmatically through
|
|
84
|
+
`benchmark_depth_range=(MIN, MAX)` — see
|
|
85
|
+
[In-training validation](validation.md).
|
|
86
|
+
|
|
87
|
+
With `--distributions`, default depth dataset/per-file histograms use the
|
|
88
|
+
benchmark `all` population, with optional sky-depth capping applied before GT
|
|
89
|
+
range selection. Their counts match the explicit `all` histogram, while the
|
|
90
|
+
unbinned scalar summaries retain their existing population. See
|
|
91
|
+
[Error distributions](distributions.md#benchmark-depth-range-and-sky-depth).
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# CLI reference
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
euler-eval <config> [options]
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
The config is the only positional argument — a JSON file describing the ground
|
|
8
|
+
truth and the prediction datasets to score against it, documented in
|
|
9
|
+
[Configuration](configuration.md). Invalid JSON or a config that fails
|
|
10
|
+
validation exits with status `1` before any dataset is opened.
|
|
11
|
+
|
|
12
|
+
## Options
|
|
13
|
+
|
|
14
|
+
| Flag | Type | Default | Description |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| `--device` | `{auto,cuda,cpu}` | `auto` | Compute device (`auto` prefers CUDA when available) |
|
|
17
|
+
| `--batch-size` | `int` | `16` | Batch size for metrics that support batching |
|
|
18
|
+
| `--num-workers` | `int` | `4` | Number of data-loading workers |
|
|
19
|
+
| `--verbose`, `-v` | flag | off | Enable verbose output |
|
|
20
|
+
| `--domain` | `{dehazing}` | none | Add a domain-specific metric set to the core metrics; repeatable |
|
|
21
|
+
| `--skip-depth` | flag | off | Skip depth evaluation |
|
|
22
|
+
| `--skip-rgb` | flag | off | Skip RGB evaluation |
|
|
23
|
+
| `--skip-rays` | flag | off | Skip rays (spherical direction map) evaluation |
|
|
24
|
+
| `--skip-points-3d` | flag | off | Skip points_3d (per-pixel 3D point map) evaluation |
|
|
25
|
+
| `--mask-sky` | flag | off | Mask sky regions from metrics using GT segmentation |
|
|
26
|
+
| `--sky-depth` | `float` | none | Cap GT and predicted depths in meters and fill predicted `sky_mask` pixels with this value; must be finite and positive |
|
|
27
|
+
| `--no-sanity-check` | flag | off | Disable sanity checking of metric configurations |
|
|
28
|
+
| `--metrics-config` | `str` | auto-detect | Path to `metrics_config.json` for sanity checking |
|
|
29
|
+
| `--depth-alignment` | `{none,auto_affine,affine}` | `auto_affine` | Depth calibration mode ([details](alignment.md#depth-alignment)) |
|
|
30
|
+
| `--points-3d-alignment` | `{none,scale,similarity,auto}` | `auto` | points_3d gauge alignment ([details](alignment.md#points-3d-gauge-alignment)) |
|
|
31
|
+
| `--rgb-fid-backend` | `{builtin,clean-fid}` | `builtin` | RGB FID backend; `clean-fid` requires the `[fid]` extra |
|
|
32
|
+
| `--benchmark-depth-range` | `float float` | none | Depth range `[MIN, MAX]` (m) for near/mid/far benchmark bins ([details](alignment.md#benchmark-depth-bins)) |
|
|
33
|
+
| `--distributions` | flag | off | Enable per-sample and pixel-pool RMSE error histograms for depth and point maps ([details](distributions.md)) |
|
|
34
|
+
| `--no-distributions` | flag | off | Disable histograms, overriding config settings |
|
|
35
|
+
| `--distribution-bins` | `int` | `50` | Total histogram bins, including tails; minimum 3 |
|
|
36
|
+
| `--distribution-scale` | `{log,linear}` | `log` | Spacing of finite histogram bins |
|
|
37
|
+
| `--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 |
|
|
38
|
+
|
|
39
|
+
Histogram settings can also be specified in the config's `distributions`
|
|
40
|
+
section. A bin, scale or range flag enables histograms and overrides that
|
|
41
|
+
config field; `--no-distributions` disables them regardless.
|
|
42
|
+
|
|
43
|
+
For depth, `--benchmark-depth-range` also restricts the default dataset/per-file
|
|
44
|
+
histograms to the benchmark's inclusive GT range. `--sky-depth` caps GT and
|
|
45
|
+
predictions before this selection and error computation. See the
|
|
46
|
+
[population rules](distributions.md#benchmark-depth-range-and-sky-depth).
|
|
47
|
+
|
|
48
|
+
## Examples
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Default settings (auto-selects CUDA when available)
|
|
52
|
+
euler-eval config.json --batch-size 32
|
|
53
|
+
|
|
54
|
+
# Sky masking (requires gt.segmentation)
|
|
55
|
+
euler-eval config.json --mask-sky -v
|
|
56
|
+
|
|
57
|
+
# Cap depth at 100 m and fill predicted sky at 100 m (optional datasets[].sky_mask)
|
|
58
|
+
euler-eval config.json --sky-depth 100
|
|
59
|
+
|
|
60
|
+
# Only depth evaluation
|
|
61
|
+
euler-eval config.json --skip-rgb --skip-rays --skip-points-3d
|
|
62
|
+
|
|
63
|
+
# Force affine scale+shift alignment on all depth predictions
|
|
64
|
+
euler-eval config.json --depth-alignment affine
|
|
65
|
+
|
|
66
|
+
# Use clean-fid for RGB FID
|
|
67
|
+
euler-eval config.json --rgb-fid-backend clean-fid
|
|
68
|
+
|
|
69
|
+
# Keep all core metrics and add no-reference dehazing metrics (NIQE + FADE)
|
|
70
|
+
euler-eval config.json --domain dehazing
|
|
71
|
+
|
|
72
|
+
# Benchmark depth/RGB metrics within a depth range (near/mid/far bins)
|
|
73
|
+
euler-eval config.json --benchmark-depth-range 0.01 80.0
|
|
74
|
+
|
|
75
|
+
# Per-image and pooled RMSE error histograms with shared logarithmic bins
|
|
76
|
+
euler-eval config.json --distributions --distribution-bins 64
|
|
77
|
+
|
|
78
|
+
# Dense depth against sparse pointcloud GT (pointwise sparse-depth metrics)
|
|
79
|
+
euler-eval example_sparse_depth_config.json --skip-rgb --skip-rays
|
|
80
|
+
|
|
81
|
+
# Per-pixel 3D point maps (predict-your-own-camera models)
|
|
82
|
+
euler-eval example_points_3d_config.json --skip-depth --skip-rgb --skip-rays
|
|
83
|
+
|
|
84
|
+
# Align relative point maps to GT with a similarity (Umeyama) gauge
|
|
85
|
+
euler-eval example_points_3d_config.json --points-3d-alignment similarity
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Metric domains
|
|
89
|
+
|
|
90
|
+
The default metric set is named `core` and is always enabled. `--domain` adds
|
|
91
|
+
metrics suited to a particular evaluation domain without removing or changing
|
|
92
|
+
the core results. The flag is repeatable so future domains can be composed in a
|
|
93
|
+
single run.
|
|
94
|
+
|
|
95
|
+
`--domain dehazing` adds NIQE and FADE under `rgb.eval.dehazing`. Both are
|
|
96
|
+
no-reference metrics: they score each predicted RGB image, do not use the paired
|
|
97
|
+
GT image, and are averaged across valid images for the dataset result. They use
|
|
98
|
+
the full prediction even with `--mask-sky`, because filling masked pixels would
|
|
99
|
+
change the natural-scene statistics being measured. See [Metrics](metrics.md#dehazing-domain).
|
|
100
|
+
|
|
101
|
+
## What a run prints
|
|
102
|
+
|
|
103
|
+
Before any dataset is opened, the run prints its own provenance — package
|
|
104
|
+
version, Python, torch and CUDA versions — which is also what gets recorded in
|
|
105
|
+
`meta` and, when configured, in the euler-train run. It then echoes the resolved
|
|
106
|
+
device, alignment mode, selected metric sets, FID backend and benchmark range,
|
|
107
|
+
followed by one block
|
|
108
|
+
per prediction dataset and modality with the GT and prediction paths, the
|
|
109
|
+
resolved modality metadata (such as `radial_depth`), and the number of matched
|
|
110
|
+
pairs.
|
|
111
|
+
|
|
112
|
+
A matched-pair count that is much lower than expected is the first sign that GT
|
|
113
|
+
and predictions are not indexed consistently — see
|
|
114
|
+
[Loader resolution & dataset metadata](configuration.md#loader-resolution--dataset-metadata).
|
|
115
|
+
|
|
116
|
+
## Device selection
|
|
117
|
+
|
|
118
|
+
`--device auto` resolves to CUDA when `torch.cuda.is_available()`, otherwise
|
|
119
|
+
CPU. Requesting `--device cuda` on a machine without CUDA prints a warning and
|
|
120
|
+
falls back to CPU rather than failing.
|
|
121
|
+
|
|
122
|
+
On CUDA, the run enables cuDNN benchmarking and TF32 matmuls — throughput knobs
|
|
123
|
+
that do not change which metrics are computed.
|
|
124
|
+
|
|
125
|
+
`--batch-size` applies to the batched image-quality metrics (PSNR, SSIM, LPIPS,
|
|
126
|
+
FID/KID); `--num-workers` is passed to the underlying dataloaders. Sparse-depth
|
|
127
|
+
and points-3d evaluation is CPU/NumPy work, so `--num-workers` matters more than
|
|
128
|
+
`--batch-size` there.
|
|
129
|
+
|
|
130
|
+
## Offline cache warmup
|
|
131
|
+
|
|
132
|
+
Compute nodes without network access need the model weights pre-fetched. Run the
|
|
133
|
+
cache warmup helper on a machine that does have network access, pointing the
|
|
134
|
+
cache environment variables at a shared location:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
HF_HOME=/shared/cache/hf \
|
|
138
|
+
TORCH_HOME=/shared/cache/hf/torch \
|
|
139
|
+
CLEANFID_CACHE_DIR=/shared/cache/clean-fid \
|
|
140
|
+
euler-eval.init
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
This pre-downloads the torchvision AlexNet and Inception v3 weights (used by
|
|
144
|
+
LPIPS and the builtin FID/KID), the LPIPS AlexNet weights, and the clean-fid
|
|
145
|
+
Inception checkpoint if `clean-fid` is installed. `TORCH_HOME` is derived from
|
|
146
|
+
`HF_HOME` when it is not set explicitly, so pointing `HF_HOME` at the shared
|
|
147
|
+
cache is usually enough.
|
|
148
|
+
|
|
149
|
+
Set the same variables for the evaluation run itself so the cached weights are
|
|
150
|
+
found.
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
A run is described by one JSON file: the ground truth, the prediction datasets
|
|
4
|
+
to score against it, and optional experiment logging.
|
|
5
|
+
|
|
6
|
+
```json
|
|
7
|
+
{
|
|
8
|
+
"euler_train": { "dir": "runs/my_project" },
|
|
9
|
+
"gt": {
|
|
10
|
+
"rgb": { "path": "/data/gt/rgb" },
|
|
11
|
+
"depth": { "path": "/data/gt/depth" },
|
|
12
|
+
"rays": { "path": "/data/gt/rays" },
|
|
13
|
+
"segmentation": { "path": "/data/gt/segmentation" },
|
|
14
|
+
"calibration": { "path": "/data/gt/calibration" }
|
|
15
|
+
},
|
|
16
|
+
"datasets": [
|
|
17
|
+
{
|
|
18
|
+
"name": "model_a",
|
|
19
|
+
"rgb": { "path": "/data/model_a/rgb" },
|
|
20
|
+
"depth": { "path": "/data/model_a/depth" },
|
|
21
|
+
"rays": { "path": "/data/model_a/rays" },
|
|
22
|
+
"output_file": "/path/to/output/model_a_eval.json"
|
|
23
|
+
},
|
|
24
|
+
{ "name": "model_b_depth_only", "depth": { "path": "/data/model_b/depth" } }
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Runnable starting points live in the repository root:
|
|
30
|
+
[`example_config.json`](../example_config.json),
|
|
31
|
+
[`example_sparse_depth_config.json`](../example_sparse_depth_config.json), and
|
|
32
|
+
[`example_points_3d_config.json`](../example_points_3d_config.json).
|
|
33
|
+
|
|
34
|
+
The config is validated before any work starts: a missing `gt` section, an empty
|
|
35
|
+
`datasets` array, a dataset without a `name` or without a single prediction
|
|
36
|
+
modality, and any path that does not exist all fail immediately with a message
|
|
37
|
+
naming the offending field.
|
|
38
|
+
|
|
39
|
+
The optional top-level [`distributions`](distributions.md#bin-settings) section
|
|
40
|
+
enables per-sample and pooled RMSE histograms. Use `true` for defaults or an
|
|
41
|
+
object with `n_bins`, `scale`, `min_error` and `max_error`; CLI histogram settings
|
|
42
|
+
override the corresponding fields. Omitted or `false` leaves histograms disabled.
|
|
43
|
+
|
|
44
|
+
## Paths and splits
|
|
45
|
+
|
|
46
|
+
Every modality entry is an object with a `path`, and optionally a `split`:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{ "path": "/data/gt/depth", "split": "test" }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
euler-loading inline selectors work directly in `path` as well, which is often
|
|
53
|
+
shorter:
|
|
54
|
+
|
|
55
|
+
| Form | Meaning |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `/data/muses` | Directory root, canonical index |
|
|
58
|
+
| `/data/muses.zip` | Zip archive, read without extraction |
|
|
59
|
+
| `/data/muses.zip:test` | The `test` split of that archive |
|
|
60
|
+
| `/data/muses.zip:test#scope=rgb` | The `test` split, reading `.ds_crawler/rgb/` metadata |
|
|
61
|
+
|
|
62
|
+
## `gt` section
|
|
63
|
+
|
|
64
|
+
At least one of `rgb`, `depth`, `sparse_depth`, `rays`, or `points_3d` is
|
|
65
|
+
required.
|
|
66
|
+
|
|
67
|
+
| Field | Required | Description |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `gt.rgb.path` | no\* | GT RGB dataset |
|
|
70
|
+
| `gt.depth.path` | no\* | GT dense depth dataset |
|
|
71
|
+
| `gt.sparse_depth.path` | no\* | Sparse pointcloud GT, `(N,C)` points whose first columns are `x,y,z` in metres |
|
|
72
|
+
| `gt.rays.path` | no\* | GT ray direction map dataset |
|
|
73
|
+
| `gt.points_3d.path` | no\* | GT per-pixel 3D point map `(H,W,3)` in camera-frame metres |
|
|
74
|
+
| `gt.segmentation.path` | no | GT segmentation (needed for `--mask-sky`) |
|
|
75
|
+
| `gt.calibration.path` | no | Calibration data (camera intrinsics); enables true camera-frame [surface normals](metrics.md#surface-normals-and-calibration) |
|
|
76
|
+
| `gt.intrinsics.path` | with `gt.sparse_depth` | Camera intrinsics for pointcloud projection |
|
|
77
|
+
| `gt.camera_extrinsics.path` | with `gt.sparse_depth` | Source-to-camera extrinsics (e.g. MUSES `lidar2rgb`) |
|
|
78
|
+
| `gt.lidar_extrinsics.path` | no | Optional lidar pose in a shared frame; composed with `gt.camera_extrinsics` |
|
|
79
|
+
| `gt.name` | no | Display name for ground truth (default `"GT"`) |
|
|
80
|
+
|
|
81
|
+
\* At least one of the five modality entries must be present.
|
|
82
|
+
|
|
83
|
+
## `datasets` section
|
|
84
|
+
|
|
85
|
+
Each entry needs a `name` and at least one prediction modality. Use only **one**
|
|
86
|
+
dense depth-like entry (`depth`, `relative_depth`, or `affine_depth`) per
|
|
87
|
+
dataset — configuring two is an error, because the space the prediction lives in
|
|
88
|
+
would be ambiguous.
|
|
89
|
+
|
|
90
|
+
| Field | Required | Description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `name` | yes | Display name for this prediction dataset |
|
|
93
|
+
| `rgb.path` | no\* | Predicted RGB dataset |
|
|
94
|
+
| `depth.path` | no\* | Predicted dense metric depth; also used against sparse pointcloud GT |
|
|
95
|
+
| `relative_depth.path` | no\* | Predicted dense relative depth (scale/shift alignment supported) |
|
|
96
|
+
| `affine_depth.path` | no\* | Predicted dense affine depth (scale/shift alignment supported) |
|
|
97
|
+
| `sky_mask.path` | no | Auxiliary predicted sky mask for a dense depth entry; used with `--sky-depth` |
|
|
98
|
+
| `rays.path` | no\* | Predicted ray direction map dataset |
|
|
99
|
+
| `points_3d.path` | no\* | Predicted per-pixel 3D point map `(H,W,3)` |
|
|
100
|
+
| `output_file` | no | Custom results path (default: `eval.json` in the first modality path) |
|
|
101
|
+
|
|
102
|
+
\* At least one prediction modality must be present.
|
|
103
|
+
|
|
104
|
+
Which entry you use is also a *declaration*: `relative_depth` and `affine_depth`
|
|
105
|
+
tell the evaluator the prediction is not metric, which is what
|
|
106
|
+
`--depth-alignment auto_affine` and `--points-3d-alignment auto` key off. See
|
|
107
|
+
[Spaces & alignment](alignment.md).
|
|
108
|
+
|
|
109
|
+
### Predicted sky depth
|
|
110
|
+
|
|
111
|
+
Add a `sky_mask` entry alongside `depth`, `relative_depth`, or `affine_depth`
|
|
112
|
+
and run with `--sky-depth 100` to evaluate predicted sky at 100 meters:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"name": "model_with_sky",
|
|
117
|
+
"depth": { "path": "/data/model/depth" },
|
|
118
|
+
"sky_mask": { "path": "/data/model/sky_mask", "split": "test" }
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The sky mask is paired with GT and predicted depth by sample ID and hierarchy.
|
|
123
|
+
It supports the same archive, split, and `#scope=` selectors as depth, defaulting
|
|
124
|
+
to the `sky_mask` metadata scope. Its loader must return a boolean mask with
|
|
125
|
+
**True meaning sky**. For example, `generic_dense_depth.sky_mask` uses the RGB
|
|
126
|
+
sky color in the mask dataset's `meta.sky_mask` (`[R, G, B]`) and returns a
|
|
127
|
+
`(1, H, W)` tensor. Masks at another resolution follow the depth grid's crop
|
|
128
|
+
rule or use nearest-neighbor resizing.
|
|
129
|
+
|
|
130
|
+
`--sky-depth` applies to dense and sparse depth evaluation. GT and both native
|
|
131
|
+
and aligned prediction branches are capped after depth conversion and affine
|
|
132
|
+
fitting; predicted sky pixels are then set to the cap. Predicted sky pixels are
|
|
133
|
+
excluded from the affine fit. Benchmark bins use the capped GT depth.
|
|
134
|
+
|
|
135
|
+
The cap also works without a predicted mask. Positive infinity is capped;
|
|
136
|
+
NaNs and nonpositive depths remain invalid, except that masked prediction
|
|
137
|
+
pixels are filled even if their original depth is invalid. Sparse GT still
|
|
138
|
+
contributes only at projected points. Predicted sky stays in the scores where
|
|
139
|
+
GT is valid; `--mask-sky` separately excludes pixels using GT segmentation and
|
|
140
|
+
can be combined with `--sky-depth`.
|
|
141
|
+
|
|
142
|
+
Without `--sky-depth`, the predicted mask is not loaded and depth evaluation
|
|
143
|
+
uses the usual uncapped values. The effective cap and mask source are recorded
|
|
144
|
+
in `eval.json` under `meta.eval_params.sky_depth` and `meta.pred.sky_mask`.
|
|
145
|
+
|
|
146
|
+
## Sparse depth (pointcloud GT)
|
|
147
|
+
|
|
148
|
+
Use `gt.sparse_depth` instead of `gt.depth` to evaluate a dense depth prediction
|
|
149
|
+
against a sparse pointcloud, e.g. raw LiDAR returns.
|
|
150
|
+
|
|
151
|
+
The evaluator projects the sparse GT cloud into the prediction plane using
|
|
152
|
+
`gt.intrinsics` and `gt.camera_extrinsics`, then computes pointwise depth
|
|
153
|
+
metrics only at projected valid pixels. The resulting depth `eval.json` is an
|
|
154
|
+
atomic `sparsedepth.eval` metric set; a depth prediction is not also unprojected
|
|
155
|
+
and evaluated as `points_3d`.
|
|
156
|
+
|
|
157
|
+
An explicit `datasets[].points_3d` prediction can be evaluated separately
|
|
158
|
+
against the same sparse cloud. That evaluation uses the points-3D similarity
|
|
159
|
+
gauge, writes an atomic `points3d.eval` metric set beside the point-map
|
|
160
|
+
prediction, and is controlled by `--skip-points-3d`. If a dataset provides both
|
|
161
|
+
depth and `points_3d`, each prediction modality gets its own `eval.json` at its
|
|
162
|
+
own path.
|
|
163
|
+
|
|
164
|
+
Sparse depth does not require segmentation GT. `gt.segmentation` is loaded only
|
|
165
|
+
when `--mask-sky` is set, and then excludes sky pixels from projected-point
|
|
166
|
+
metrics and from scale/shift fitting.
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"gt": {
|
|
171
|
+
"name": "MUSES sparse GT",
|
|
172
|
+
"sparse_depth": { "path": "/data/muses.zip:test#scope=lidar" },
|
|
173
|
+
"intrinsics": { "path": "/data/muses.zip:test#scope=intrinsics" },
|
|
174
|
+
"camera_extrinsics": { "path": "/data/muses.zip:test#scope=extrinsics" }
|
|
175
|
+
},
|
|
176
|
+
"datasets": [
|
|
177
|
+
{ "name": "model_a", "depth": { "path": "/data/model_a/dense_depth:test" } }
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Points-3D ground truth sources
|
|
183
|
+
|
|
184
|
+
A `points_3d` prediction is compared against a GT point map from one of two
|
|
185
|
+
sources:
|
|
186
|
+
|
|
187
|
+
1. **Explicit** — `gt.points_3d.path` (a stored `(H,W,3)` map).
|
|
188
|
+
2. **Synthesized from depth** — if `gt.points_3d` is absent but `gt.depth.path`
|
|
189
|
+
and intrinsics (`gt.intrinsics` or `gt.calibration`) are present, GT depth is
|
|
190
|
+
unprojected on the fly. Whether the GT depth is radial or planar is read from
|
|
191
|
+
its metadata (`radial_depth`).
|
|
192
|
+
|
|
193
|
+
## `euler_train` section (optional)
|
|
194
|
+
|
|
195
|
+
When present, results are logged to an
|
|
196
|
+
[euler-train](https://github.com/d-rothen/euler-train) run, which requires the
|
|
197
|
+
`[logging]` extra. `euler_train.dir` is either a project directory (a new run is
|
|
198
|
+
created and finished on completion) or a full path to an existing run directory
|
|
199
|
+
(the run is resumed and detached afterwards, leaving it active). `dir` is the
|
|
200
|
+
only supported key.
|
|
201
|
+
|
|
202
|
+
Each prediction dataset is registered as an evaluation named after its config
|
|
203
|
+
`name`, first as `running` and then with its metrics attached, alongside package
|
|
204
|
+
provenance (euler-eval version, Python, torch, CUDA).
|
|
205
|
+
|
|
206
|
+
## Loader resolution & dataset metadata
|
|
207
|
+
|
|
208
|
+
Loaders are resolved automatically by euler-loading from each dataset's
|
|
209
|
+
ds-crawler index metadata — no manual loader selection is needed. Each dataset
|
|
210
|
+
directory declares its loader via the `euler_loading.loader` and
|
|
211
|
+
`euler_loading.function` fields of its index. Modality metadata
|
|
212
|
+
(`radial_depth`, `rgb_range`, sparse point columns, coordinate units) is read
|
|
213
|
+
automatically; depth and point-cloud coordinates are assumed to already be in
|
|
214
|
+
metres.
|
|
215
|
+
|
|
216
|
+
Each dataset root or archive must contain ds-crawler metadata under
|
|
217
|
+
`.ds_crawler/` (`dataset-head.json`, `ds-crawler.json`, `index.json`). When one
|
|
218
|
+
physical root holds several logical modalities, the artifacts may be scoped
|
|
219
|
+
under `.ds_crawler/<modality>/` with a `.ds_crawler/scopes.json` manifest,
|
|
220
|
+
letting a path like `/data/muses.zip:test` load `.ds_crawler/rgb/index.json`,
|
|
221
|
+
`.ds_crawler/depth/index.json`, and so on from the same archive. GT and
|
|
222
|
+
prediction datasets are matched by hierarchy path and file ID.
|
|
223
|
+
|
|
224
|
+
### Multiple modalities from one archive
|
|
225
|
+
|
|
226
|
+
Give every modality the same archive root and let the scope select the metadata.
|
|
227
|
+
The scope defaults to the configuration key name, so the common case is compact:
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"gt": {
|
|
232
|
+
"rgb": { "path": "/data/capture.zip:test" },
|
|
233
|
+
"depth": { "path": "/data/capture.zip:test" },
|
|
234
|
+
"intrinsics": { "path": "/data/capture.zip:test" },
|
|
235
|
+
"camera_extrinsics": { "path": "/data/capture.zip:test" }
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Use `#scope=<scope>` when an artifact scope is not named exactly like the config
|
|
241
|
+
key, e.g. `"sparse_depth": { "path": "/data/capture.zip:test#scope=lidar" }`.
|
|
242
|
+
|
|
243
|
+
Regular modalities (`rgb`, `depth`, `rays`, `points_3d`, `sparse_depth`)
|
|
244
|
+
participate in file-ID intersection; calibration and pose data (`intrinsics`,
|
|
245
|
+
`calibration`, `camera_extrinsics`, `lidar_extrinsics`, segmentation) are loaded
|
|
246
|
+
hierarchically and do not.
|
|
247
|
+
|
|
248
|
+
## `metrics_config.json`
|
|
249
|
+
|
|
250
|
+
Controls the thresholds used by sanity checking. When `--metrics-config` is not
|
|
251
|
+
given, the tool auto-detects `metrics_config.json` at the project root and falls
|
|
252
|
+
back to built-in defaults if there is none.
|
|
253
|
+
|
|
254
|
+
The file is grouped by modality, and each metric block carries its thresholds
|
|
255
|
+
plus a `description` explaining what the check is for:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"depth": {
|
|
260
|
+
"expected_range": { "min": 0.0, "max": 100.0 },
|
|
261
|
+
"absrel": { "warn_if_median_exceeds": 1.0, "warn_if_p90_exceeds": 2.0 },
|
|
262
|
+
"silog": { "warn_if_exceeds": 0.5 }
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
See [`metrics_config.json`](../metrics_config.json) for the full set of options,
|
|
268
|
+
and [Results & output](output.md#sanity-check-report) for what the checks
|
|
269
|
+
produce.
|