Tree separation test — segment_085 annotated Tree.e57
Summary
Input: the human-annotated class-5 5 Tree.e57 (207k points, RGB) from
…/260812_full_sweep/branch_000/segment_085/reCap export_classfied_v2, with 2 Terén.e57 as ground.
The splitter (tree_instances.split_tree_cluster, default config) produced 20 tree instances,
but only 3 are stem-seeded; the other 17 come from the crown-apex fallback.
verdict The annotated "Tree" class is 99 % one continuous canopy blob (35 m radius) whose median height above ground is 2.4 m (p95 5.2 m). Real crowns with trunks exist only on the east/upper side; the rest is a low, sparse thicket that the apex fallback tiles into ~5–10 m instances with no tree behind them. Split is geometrically plausible where trees exist, arbitrary elsewhere.
Images
Top-down, world XY (EPSG as in the E57, metres). Click/zoom for detail — each image is ~2400 px wide.
tree_instance_id; grey = abstain (unreachable / low evidence / too small);
X = seed with true-scale stem circle; label nS = stem seed, nA = crown-apex seed.
Orbit video
44 s, 1600×900: 12 s overview orbit + four 8 s close-ups (east stem-seeded trees 14S/17S/16A · south apex-tiled thicket 7A/10A/11S · NW crowns 4A/6A/8A · west 0A–3A). Instance colours as above, ground dark grey.
On N: 02_Modelling\05_Rink\02_AI 3D modeling\02_OUT\260716_videos\260827_ReCap_segment_085_tree_instances\260827_segment_085_tree_instances_orbit.mp4 (78 MB, + preview and top-down PNG alongside). Renderer: out_trees/annot085/orbit.py.
Numbers
| step | result |
|---|---|
| Tree class points | 206 969 (RGB present, ExG usable) |
| Blobs (3-D DBSCAN eps 1.0 m, min 8) | 9 blobs + 97 noise pts; blob 0 = 205 645 pts (99 %), footprint radius ≈ 35 m, max height 8.8 m |
| Splitter verdict, blob 0 | merged → 19 instances (3 stem, 16 apex); 180 289 pts assigned |
| Other blobs | 1 × single (523 pts, 5.3 m); 3 × uncertain, 0 seeds (183 / 393 / 63 pts) |
| Points assigned | 180 812 / 206 969 (87 %) |
| Abstentions | 19 137 unreachable · 6 402 low evidence · 393 no stem seed · 128 too small |
| Height above DTM | p5 0.8 m · median 2.4 m · p95 5.2 m · max 7.6 m |
How to read it
- good Stem seeds
11S,14S,17Ssit where the height map shows 5–7 m crowns — those are real trees with visible trunks. - weak Apex seeds in the low western/southern part (
7A,10A,15A,19A,0A–3A) split a continuous 2–4 m thicket into tiles; boundaries there are Voronoi-like, not crown boundaries. - weak Large grey (abstain) regions along the SW edge: too sparse / no path to a seed.
- By the AI3D-373 rules (tree = detector tree, medium vegetation = tall green not detected as tree) most of this annotated class would be medium vegetation, where per-instance splitting is not meaningful.
Method
- Read E57 with
pye57→ XYZ + RGB; ExG = (2g − r − b)/(r + g + b) viascripts/tree_instance_split.compute_exg. - Cluster into "detections": 3-D DBSCAN (eps 1.0 m, min_samples 8) — stand-in for the detector's cluster step.
- Per blob:
z_ground= 5th percentile of Terén-class z within blob footprint + 3 m; callsplit_tree_cluster(xyz, z_ground, exg, DetectorConfig()); offset labels to global ids. - Render with
tree_instance_render.instance_colorspalette; DTM for the height panel = 2 m cell min-z of the ground class.
uv run python out_trees/annot085/run_split.py 1.0 # → /tmp/tree085/{split.npz,split_summary.json,trees_topdown.png}
uv run python out_trees/annot085/render2.py # 3-panel PNG
Sources kept in out_trees/annot085/ (git-ignored) and /tmp/tree085/; page assets in docs/pages/tree-split-085-20260827_assets/.
Next (not run)
- Make the apex fallback more conservative on scrub: raise
ti_apex_min_height_m(2 → ~4 m) and/orti_apex_min_prominence_m; sweep and re-render. - Let the
_band_shapehedge verdict fire on the low continuous thicket so it lands as one hedge/medium-vegetation region instead of tiles. - Compare against the detector's own tree detections for segment_085 (recall check vs this annotation).