AI3D-360: guardrail rail-vs-support split — real-segment validation
Feature
The guardrail detector now separates the rail beam (B/W-profile band,
0.35–0.85 m) from its supporting posts. Each accepted rail run gets a
corridor-scoped low-band evidence pass (0.10–0.50 m above road), an autocorrelation
cadence estimate snapped to the Swiss/German catalog {1.33, 2.00, 4.00} m, and a
guardrail_support companion instance — a new exported
class in guardrails.json, its own XML <Feature>, the overlays
(violet line, one dot per detected post), and point_masks.npz (support points
re-labelled per point). Validated on real Abschnitt 4/5 segments; verdict:
working, one real defect found on real data and fixed
(station quantization, see Segment 118).
Rail instances carry post_spacing_m (snapped), post_spacing_raw_m,
post_spacing_snapped, post_count, post_confidence and
post_gap_spans (each span flagged occluded when it overlaps an occlusion
interval already bridged on the rail — gaps mean unobserved-or-missing, never
“defect”). Everything sits behind three config flags
(enable_post_cadence, enable_support_class,
enable_component_masks, all default on); with all three off, every output is
byte-identical to the pre-feature detector.
| Commit | What |
|---|---|
942f58e | Post cadence + guardrail_support class (instances, masks, overlays, config) |
216e410 | Supports exported as their own XML Type="guardrail_support" Feature; evidence-dump lever |
9bf5baf | Fix: continuous RoadSpine.project_fine station for the cadence passes (1.0 m grid artifact) |
Segment 107 — clean 2.00 m cadence on all four rails
w_beam rails (G00–G04), violet = the four
guardrail_support companions (S05–S08) with one dot per detected post.Segment 118 — the quantization artifact, before and after
The first real-segment run reported an unphysical 1.0 m spacing on two rails.
The dumped evidence histograms showed 100% of the low-band mass in one residue class modulo
1.0 m: RoadSpine.project snaps stations to its ~1 m sample grid, which the 1 m-binned
main pipeline never notices but which folds a 0.10 m cadence histogram onto the grid — and
aliases genuine 1.33 m post trains to 4.0 m. Fixed by project_fine (along-tangent
refinement), used only by the new passes so pre-feature outputs stay byte-identical.
Segment 135 — weak evidence is rejected, not invented
Cadence results (after fix)
| Segment | Parent rail | Spacing | Raw | Snapped | Posts | Confidence | Gap spans |
|---|---|---|---|---|---|---|---|
| 107 | G00 | 2.00 m | 1.998 | yes | 25 | 1.000 | 0 |
| 107 | G02 | 2.00 m | 2.001 | yes | 25 | 0.983 | 0 |
| 107 | G03 | 2.00 m | 2.000 | yes | 24 | 0.878 | 1 |
| 107 | G04 | 2.00 m | 1.997 | yes | 25 | 0.521 | 0 |
| 118 | G00 | 2.00 m | 2.000 | yes | 26 | 0.939 | 0 |
| 118 | G01 | 1.33 m | 1.330 | yes | 38 | 0.860 | 0 |
| 118 | G02 | 1.33 m | 1.323 | yes | 38 | 0.739 | 0 |
| 118 | G03 | 2.00 m | 2.003 | yes | 25 | 0.994 | 0 |
| 135 | G00 | 2.00 m | 1.999 | yes | 25 | 0.984 | 0 |
| 135 | G01 | 2.00 m | 2.004 | yes | 26 | 0.514 | 0 |
| 135 | G02–G10 (8 rails) | no cadence — weak/far-field low-band evidence, correctly rejected | |||||
Verification
- pass 259 unit tests, incl. synthetic cadence (30% deleted posts), sub-mask precision on synthetic truth, station-quantization regressions, config/JSON parity.
- pass Flags-off invariance on real segment 107: rail JSON exactly
equal after stripping
post_*; mask rows a strict subset with agreeinginstance_id; XML equal after removing the support Feature. - pass
point_masks.npzschema unchanged (supports ride the existinginstance_typetable; e.g. segment 107: 855,960w_beam+ 41,745guardrail_supportpoints). - pass XML: separate
Type="guardrail_support"Feature withsegment_NNN_guardrail_support_NNpolylines through the Nexus exporter.
Notes & open items
- tuning Height cut lines (0.35 / 0.50 m) are literature-derived config values; behaved well on 107/118/135, left untouched until a downstream consumer needs otherwise.
- perf The evidence pass is O(runs × points): ~4 min on 4-rail segments, ~32 min on segment 135 (19 instances). Optimizable if it matters.
- Support
mean_height_mis the band midpoint (0.3), not measured; support height profiles are empty by design. - JSON
point_countand mask row counts are different quantities (pre-existing); zone-recovered rails own no occupancy cells and thus no mask rows (pre-existing). - Branch
t3code/separate-v-profile-support-classes, v0.3.1 + AI3D-360 commits; wrap-up (version bump, Nexus, push) pending.