Skip to content

Plant trees from aerial imagery and ship both vision detectors - #120

Merged
vanlueckn merged 1 commit into
mainfrom
t3code/ai-tree-detection-placement
Sep 2, 2026
Merged

Plant trees from aerial imagery and ship both vision detectors#120
vanlueckn merged 1 commit into
mainfrom
t3code/ai-tree-detection-placement

Conversation

@vanlueckn

Copy link
Copy Markdown
Collaborator

Summary

  • Tree placement from imagery: a model class marked kind: Tree in ai.ron plants finds as ordinary rows in the line's tree list (via TreeSource) instead of objects bolted to the track graph — selectable, deletable, and undoable exactly like hand-planted trees (vision::canopy, route-editor/src/ai.rs).
  • Measured crowns drive size: the species is drawn from those whose crown is within 1.5× of the measured span, then scaled (clamped to 0.6–1.5) so the tree matches the crown; all 84 mods/trees objects gained a footprint measured off the built crown_LOD0 mesh by the updated tools/trees/import_mantissa.py.
  • Conifer/broadleaf guess: where the model only knows "Tree", vision::canopy classifies crowns via two ratio-based features (brightness spread and red/blue warmth), thresholds calibrated on real provider imagery; both must agree.
  • Species override in the dialog: "As detected" or a named stand (nadelwald, laubwald, …) which plants like the forest brush; also available headless via --stand.
  • Second output layout Head::Retina: torchvision RetinaNet emits logits/offsets per anchor with no boxes; the anchor grid is rebuilt in Rust and validated against torchvision's numbers (including banker's-rounding edge cases).
  • Both detectors now ship in models/ (Git LFS): yolov8n-obb.onnx (12.7 MB, AGPL-3.0, Ultralytics/DOTA) and deepforest-tree.onnx (129 MB, MIT, DeepForest/NEON). Licence implications documented in models/LICENSES.md, THIRD_PARTY_LICENSES.md, and the README; deleting the AGPL file degrades gracefully.
  • Model registry changes: span field for classes where the factor-of-two size rule is wrong (crowns range 3–25 m); /models/ removed from .gitignore, LFS tracking added in .gitattributes; tools/vision/export_models.py reproduces both conversions.
  • Duplicate suppression reworked: occupancy test is now a grid (ai::Occupied) instead of a list, so tens of thousands of trees don't freeze the editor; tree de-duplication uses ⅓-crown spacing (configurable "Keep trees apart").
  • i18n: new keys (ai-place-trees, ai-species, ai-tree-spacing, …) added to both en and de locales.
  • Docs updated: README (trees section, shipping table), MODS.md, PLAN.md, STATUS.md, tools/vision/README.md.

Testing

  • cargo test --workspace: 1136 existing tests plus new crates/vision/tests/shipped.rs (136 lines) covering the shipped detectors — including Retina anchor-grid validation against torchvision reference numbers.
  • Retina decode verified against DeepForest's own test image: Python reference finds 55 crowns, this pipeline 50 at confidence 0.3, shared boxes agree to ~1 px (~0.1 m).
  • cargo test -p i18n confirms en/de key parity for the new strings.
  • Canopy threshold calibration measured on provider imagery (contrast 0.10 broadleaf vs 0.22/0.13 conifer); noted in module docs as resolution-dependent (needs ≥3 m crowns to be meaningful).
  • Headless run (--detect-run --stand nadelwald) writing trees into the route file: not verified in this summary — run locally if needed.
  • Second-run idempotency over the same wood (grid occupancy + tree spacing): not run here.
  • LFS pull on an existing clone (git lfs pull) and editor behaviour with yolov8n-obb.onnx deleted (graceful "not installed" report): not run.
  • Editor UI flow (dialog, progress, undo, select/delete of planted trees): manual check recommended on a real route; not run.

- ship yolov8n-obb (AGPL-3.0) and deepforest-tree (MIT) in models/ via Git LFS, converted by tools/vision/export_models.py
- add Head::Retina so the DeepForest anchor grid is rebuilt in Rust, tested against torchvision
- tree classes (kind: Tree) become rows in the line's tree list, grown to the measured crown within 0.6-1.5
- conifer guess from crown contrast and warmth (canopy.rs), overridable via Species/stand in the dialog
- state a footprint for all 84 tree objects, measured by the importer
- grid-based occupancy test and third-crown spacing so a second run is a no-op
@vanlueckn
vanlueckn merged commit 5737d61 into main Sep 2, 2026
3 checks passed
@vanlueckn
vanlueckn deleted the t3code/ai-tree-detection-placement branch September 2, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant