AI3D-382 · before / after gallery

7 Sep 2026 · BEFORE = the detector as it stood before this ticket (packaged defaults, every new knob OFF) · AFTER = the shipped recommended config configs/a1nr_returns_recommended.json · data Abschnitt_1_no_angle_filter_returns · full summary page · PR #10

All numbers below are measured on the six validation segments 003 / 022 / 023 / 087 / 093 / 094, which were never used while tuning, plus the human-annotated ground truth on 085. Every image is a click away from full resolution; arrow keys / A D step through the images of one section.

gate metricBEFOREAFTERread
canopy recall above 10 m0.0180.769the upper canopy was simply not painted before
canopy recall 4–10 m0.7500.903positive on 6/6 segments
foliage-cell recall, segment-wide0.4940.860unmasked remainder 16.1 M → 4.5 M points
hard-structure cells inside tree paint11126hard points −75 %; down on 6/6
signs / delineators4 / 885 / 88+1 real sign, 0 signs and 0 delineators lost
085 GT precision0.4890.543veg-tolerant 0.741 → 0.853
085 GT recall (annotator class “tree”)0.7550.755unchanged — every precision gain cost zero true tree
runtime, worst segment308 s447 s+45 %, still 37 % of the 20 min budget

How to read the renders

Every close-up is one spot in the raw point cloud, always four panels wide, top row an oblique elevation view, bottom row the same points seen from above:

  1. true RGB — what is actually there.
  2. number_of_returns — the new signal: grey = single return (hard surface), orange = 2, red = 3+. Foliage is orange/red, guardrail and asphalt are grey.
  3. BEFORE — the detector's point masks with the packaged defaults.
  4. AFTER — the same masks with the recommended config.

unmasked tree medium_vegetation sign / delineator / pole guardrail other

Panels 3 and 4 use the identical viewpoint, extent, sub-sample and colour table, so anything that changes between them is a real change in the output. The dashed blue line marks 10 m — the height where the old candidate slab stopped. The title line of each render gives the exact position and the tree-painted point count before → after.

1. Whole segments, top-down

The entire segment at a glance

Four panels: true RGB, BEFORE, AFTER, and a DELTA panel where bright green = tree paint added, red = tree paint removed, dark green = painted in both. 1.6 M points shown per panel, rotated so the carriageway runs across the page.

023 (validation) — tree paint 19.3 % → 29.2 % of all points. BEFORE the tree row is a patchy green fringe; AFTER it is a solid canopy. The DELTA panel shows the two red lines along the road edges: that is the guardrail beam, painted tree before and unpainted now. 023 hard cells 10 → 0.
ov_023
093 (validation) — tree paint 18.0 % → 22.0 %. The long razor-straight red line in DELTA is a 41 m guardrail run that BEFORE drew as a continuous green stripe on the verge. The crowns on the lower verge fill in. 093 hard cells 26 → 1.
ov_093
085 — the segment with human ground truth. Tree paint 25.8 % → 39.1 %. BEFORE draws two continuous green guardrail lines down both road edges; AFTER both are gone (red in DELTA) while the tree walls on both sides gain their upper canopy. GT guardrail points painted tree 25 772 → 6 276 (−76 %).
ov_085

2. The main win — canopy recall above 10 m (0.018 → 0.769)

The old candidate slab stopped at 10 m

The v6 tree path built its candidates in a 0.3–10 m slab, tuned on scan-angle-filtered data where tree tops were largely absent. On the new data the crowns are there, they were simply never painted. The canopy extension walks upward from the slab, accepting each 1 m column cell whose points are multi-return foliage (mrf ≥ 0.20, mr3 ≥ 0.02).

023 tall tree row (−2878.5, −1843), r = 28 m, crowns to 25.5 m. BEFORE the green stops dead at the dashed 10 m line and the whole upper half of the crown is grey; AFTER the crown is painted to its top. Tree-painted points in this window 2 255 253 → 4 049 674. Segment 023 canopy recall > 10 m 0.029 → 0.920.
canopy_023_row
093 verge crowns (3054.0, 1428.5), r = 22 m, tops at 17.8 m. Same pattern: grey caps above 10 m BEFORE, fully painted AFTER, and the green guardrail line along the road edge disappears at the same time. Segment 093 canopy recall > 10 m 0.007 → 0.898.
canopy_093_row
085 tree wall (2314.2, 1228.1), r = 25 m, top at 30.2 m — the segment with human GT. The whole upper canopy fills in and the guardrail line at the road edge goes. On the 085 human ground truth, recall stayed at 0.755 and not one GT tree point was lost across the whole ticket, while precision went 0.489 → 0.543 and veg-tolerant precision 0.741 → 0.853.
canopy_085_conifer

Pooled over the six validation segments: > 10 m 0.0175 → 0.7693, 4–10 m 0.7503 → 0.9031, segment-wide foliage cells 0.4942 → 0.8601 — positive on every one of the six.

3. Hard structure that used to be painted as tree

Billboards, lane markings, vehicle streaks and road slivers

A 1 m cell inside a tree instance holding ≥ 300 points with a multi-return fraction below 0.05 is flat hard structure, not foliage. Those cells lose their paint, and if what survives is small and structure-like the whole detection is dropped. Guarded by a canopy-column test so trunk bases and understorey survive.

066 carriageway (695.5, 327.5), r = 16 m — the case that named the problem. The bright green stripes BEFORE are moving vehicles smeared along the lane plus lane markings, admitted into the tree paint by the 0.3–10 m slab. AFTER the carriageway is clean while the shrub bank bottom-right keeps and extends its paint. Tree paint in the window 1 025 971 → 800 994.
streaks_066
093 (3041.20, 1399.58) — a flat panel / road marking under a gantry, standing on the carriageway, 19 594 points, ml 0.910, mrf(h>1 m) = 0.048. BEFORE it is a green slab in mid-road; AFTER the whole detection is gone: 19 594 → 0 tree points. One of the 9 tree detections removed on the validation split — all nine were rendered and all nine were road, mast or barrier.
g_treerej_093_3041
022 (−2940.73, −1989.41), r = 10 m — a 4 m all-single-return needle rising out of the carriageway (mast or vehicle plume, mrf 0.006). BEFORE it is a green spike over the road; AFTER it is gone. This is the cluster behind 022 going from 30 hard cells to 1. Meanwhile the crown bottom-right is painted much more completely (window total 365 817 → 569 646).
g_blobH_022
022 (−2918.52, −1940.71) — a road-surface streak beside the rail, 6 812 points, ml 0.953. Both the streak and the green line on the rail go away, while the crown on the left gains its whole upper canopy: 170 215 → 296 416 tree points in the window. Removal and recall in the same frame.
g_treerej_022_2919

Validation split: hard cells 111 → 26, hard points 137 009 → 34 057 (−75 %), hard fraction of the tree paint 0.00363 → 0.00068. 9 tree detections dropped, 9/9 road / mast / barrier, 0 vegetation.

4. Guardrail inside the foliage

Point-level unpaint using the seg3d guardrail masks

A w-beam that runs through a hedge sits inside the same tree instance as the hedge, so no per-cluster rule can reach it. The new hook removes tree paint from points that the seg3d guardrail model already claims (guardrail_mask_unpaint_enabled, masks from rail_halfpost.models_dir). It is a paint-only edit: not one detection changed. The knob defaults OFF, so a run without seg3d masks is unaffected.

087 (2475.00, 1352.05), r = 25 m — the largest block of tree paint removed anywhere on the validation split: 295 539 points over 93 × 35 m, elevation p50 0.57 m, mrf 0.048. BEFORE a continuous bright green line runs down both road edges; AFTER exactly that line is gone and nothing else. The crowns above are identical, and denser.
g_blob1_087
022 (−2949.91, −1971.05), r = 18 m — the rail runs along the foot of the tree bank, so its paint was part of the crown instance: 119 351 points, 24 × 26 m, mrf 0.079. The straight green line at the road edge goes; the crown above is preserved and extended (2 107 571 → 2 622 845 tree points in the window).
g_blob3_022
085 (2289.72, 1229.92), r = 14 m — two full guardrail runs painted as tree BEFORE (231 534 tree points in the window), reduced to a broken residual AFTER (132 063). The residual is where the seg3d model’s own mask stops, not where our rule stops. 085 GT guardrail paint 25 772 → 6 276, hard FP 46 519 → 26 965.
rail_085_e03

7 of the 7 largest unpainted blobs on the validation split were guardrail beam or single-return artefact. None was vegetation. The rail half-post CSVs are md5-identical on all six segments — the rail detection path itself is untouched.

5. Signs

One ghost killed, one real sign found, one plate cleaned

Two changes touch the sign path: sign_post.min_points_per_m = 100 rejects airborne “signs” with no post (sparse_sign), and the returns stripper drops multi-return foliage from sign candidates before the shape features so a plate buried in a crown is still recognisable. Magenta points are drawn oversized here so the small ones are visible.

018 (−3279.90, −2193.30), r = 3.5 m — two ghost signs killed. BEFORE the detector emits two sign_post_with_plate detections of 82 and 91 points at h = 1.8 m: 173 magenta points floating in mid-air over bare asphalt, with no post and nothing underneath. AFTER: nothing. Real signs run 1 014–2 951 points per metre, these two ran 45–51 — a 20× margin.
ghost_018_sign_zoom
023 (−2906.34, −1913.61) — the +1 sign on the validation split. A genuine ~2.5 m board / cabinet on the verge in front of the tree wall, 5 206 points, ml 0.469. BEFORE nothing is painted there at all; AFTER the magenta covers exactly the panel and its post, with no foliage tail. Sign-painted points 0 → 5 206.
g_sign_added_023
022 (−2940.90, −1958.55) — a plate cleaned by the returns stripper. A real round plate on a slim post beside the rail, detected by both configs, but BEFORE the mask is a ragged blob that swallows the foliage behind it; AFTER it is a clean lollipop: plate + post. Sign paint 4 719 → 3 637, ml confidence 0.589 → 0.659, mrf of the mask 0.203 → 0.144.
g_sign_022_shrunk

Validation split: signs 4 → 5, delineators 88 → 88, 0 signs and 0 delineators removed on any of the six segments, half-post CSVs md5-identical, cluster-verdict churn on the sign path 22 / 3 964 = 0.55 %.

6. Honest panel — what did not improve

Unchanged failures and the one real cost

These are the same before and after, or slightly worse after. None of them is a regression introduced by this ticket — the first three are pre-existing behaviour that the new knobs deliberately do not touch, because fixing them needs a product decision or a different discriminator, not another unpaint rule.

Attached shrubs and grass, unchanged. 023 truth spot lowrej_023_c3_s2 (−2860.99, −1920.11): a dry grass / reed bank on an embankment, labelled not_tree by two judges, painted as tree by both configs (100 278 → 100 782 points, i.e. no change). This class is ~67 % of the residual false positives on the 085 ground truth and is a definition question, not a bug: does vegetation attached under a tree count as tree?
hedge_023_c3s2
Lamp / camera mast as a trunk, unchanged. 003 (−3329, −3671): the largest residual hard cell on the validation split, 20 082 points, mrf 0.033 — a vertical mast painted tree over its full height in both configs. It is vertical, single-return and column-shaped, so the hard-blob rule’s canopy-column guard protects it. It needs a pole-vs-trunk discriminator, which is its own ticket. (The conifers around it do gain their upper canopy.)
g_hardcell_003
Gantry column as a trunk, unchanged. 003 (−3320.76, −3679.37): the road sliver in the middle of the frame is correctly rejected (31 212 → 22 702 tree points), but the gantry column at the right edge stays tree-painted in both panels — same failure class as the mast above.
g_treerej_003_3321
The one measurable cost. 087 truth spot lowrej_087_c3_s0 (2456.99, 1312.86) is the only one of the 50 truth spots that loses paint: 436 623 → 425 309 (−2.6 %). The render shows why — the entire loss is the guardrail bar crossing the top of the circle. The crown itself is pixel-identical. 47/50 spots gain paint, 2 are unchanged, this one loses 2.6 %.
g_spot087_c3_lost
The guardrail mask also shaves real foliage. 085 (2282, 1219), r = 8 m: a real hedge grows through and behind the rail, so the sliver of bush foliage that lies inside the seg3d mask goes with the beam — 3 500 GT low/medium_veg points, 0.6 % of the segment’s vegetation paint. The bush is still detected and still painted; only the rail-embedded sliver thins. Escape hatch if it ever bites: guardrail_mask_unpaint_classes = ["w_beam"] plus mask erosion.
plus mask erosion." target="_blank" rel="noopener" title="open full resolution">rail_in_hedge_085

Also unchanged and deliberately so: mega-instances. On 085 a single tree instance covers 102 × 75 m and holds every true positive and the road and rail inside it. Splitting it is seg3d’s job, not this detector’s.

Full accounting of costs, open items and the decisions Miro needs to make: AI3D-382 summary · guardrail pass detail: pass 9 report.