ProjectSidewalk / ProjectSidewalk/RampNet

Flat-ground distance carries a ~11% range-proportional scale error, not just scatter — multi-view self-consistency measures it and DA3 can anchor it

Open
#101 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
7
Forks
1
Avg merge
4d 11h
Merged PRs (30d)
7

Description

The measurement

Multi-view association in the auto-labeler (sidewalk-auto-labeler#27) fuses detections of the same physical ramp seen from several panos. That makes a new check possible: the same ramp, raycast from cameras at different distances, should land in the same place. It does not.

For every fused site, take each member's signed along-ray residual — how far that view's ground point sits beyond (or short of) the fused position, measured along its own ray — and regress it on that member's range. Demeaned within each site (fixed effects, so per-site offsets cancel), pooled across sites with ≥3 refit members spanning ≥4 m of range:

city source sites members slope (m per m)
paterson GSV 4,433 19,588 +0.1159 ± 0.0021
gainesville GSV 1,774 7,033 +0.1179 ± 0.0038
bend GSV 9,388 42,240 +0.1082 ± 0.0013
richmond Mapillary 890 7,040 +0.1275 ± 0.0058
sao_paulo GSV 1,877 8,156 +0.0572 ± 0.0034

All 50–90σ. The discrepancy is not scatter — it is proportional to range, the signature of a scale error in d = camera_height / tan(depression), at roughly 11% almost everywhere.

At 20 m that is a ~2.3 m radial displacement, and because a street's cameras mostly sit along one line, it does not average out — it pushes detections consistently away from the roadway.

This is the same effect §0 of detection_recall_analysis.md already saw

That doc reports flat-ground geometry and DA3 metric depth agreeing to within 6.5–8.5%, and notes geometry placing four Richmond ramps above the horizon. Those were read as agreement plus rig noise. The multi-view result says the residual has structure: it is a proportional scale error, not a spread. A scale error is a one-constant fix; noise is not.

Two independent methods — an external monocular depth model, and pure self-consistency across views — now point the same way, and neither shares the other's failure modes.

What it is not

The obvious explanation is that the assumed camera height is too high (+0.116 implies ~2.33 m against the 2.5 m this repo assumes and the 2.6 m the labeler's geo.py assumes — worth reconciling in its own right). That hypothesis fails its own test. Re-fusing the labeler's runs over 2.10–2.60 m does lower raw within-site scatter at ~2.33 m, but lowering the assumed height shrinks every range proportionally, so raw metres shrink for free. Normalize scatter by the assumed height and 2.60 m is monotonically the best value tried, on both a GSV and a Mapillary city. So this is not simply the wrong constant.

The decisive experiment, using tooling that already exists here

The multi-view regression proves the disagreement is range-proportional but cannot say which end is right — it is anchored to a weighted mean of the same biased rays. scripts/analysis/depth_extract_da3.py can anchor it:

Regress DA3 metric depth on flat-ground distance for benchmark detections and look at the slope, not the correlation.

  • Slope ≠ 1 → the geometry is biased. Fixable as a calibration; the distance buckets in detection_recall_analysis.md §1 and precision_by_distance.py are stretched, and the apparent-size relation W/d × (4096/2π) inherits it directly.
  • Slope ≈ 1, multi-view trend persists → the geometry is fine and the peak placement drifts: the heatmap's argmax moves relative to the true ground-contact point as a ramp shrinks with distance. That is a model property, and it would sit with #83 (points → extent) — a size head or mask gives a bottom edge to raycast instead of a blob centre.

Splitting those two is cheap and needs no new data.

Why it is worth doing

  • Distance-conditioned results. Recall by distance (0.842 / 0.879 / 0.812 / 0.564 across the buckets) is reported against an axis that may be stretched ~11%; bucket edges move.
  • Position accuracy downstream. Auto-labeler world positions inherit it, and it is the largest single systematic we can currently name — median agreement with GT is ~0.8–1.6 m, so a 2 m bias at 20 m is not a rounding error.
  • Mensuration (#86, #83). Any metric quantity read off the ground plane — ramp width, dual-ramp separation, running slope — is multiplied by the same scale error. Calibrating it is a prerequisite, not a refinement.

Note the Mapillary/GSV split does not separate the hypotheses: richmond (Mapillary, varied rigs, SfM poses) shows the largest slope while sharing no camera geometry with GSV, which argues against a single rig constant and toward something shared — the model, or the flat-ground assumption itself. São Paulo, the hilliest split, is the outlier at half the slope, which is the opposite of what pure terrain noise would predict and deserves its own look.

Measurement scripts are in the auto-labeler scratchpad (heightbias.py, heightsweep.py); the method above is complete enough to reproduce from sites.jsonl alone.

🤖 Generated with Claude Code (claude-opus-5[1m])

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with scripts/analysis/depth_extract_da3.py and the measurement scripts heightbias.py and heightsweep.py, using sites.jsonl and the benchmark detections. Compare DA3 metric depth with flat-ground distance and inspect the slope. Done means determining whether the slope supports a geometry calibration or points to peak-placement drift, then documenting the result’s impact on detection_recall_analysis.md §1 and precision_by_distance.py.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
computer-vision, machine-learning
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.