Fix/no split single tree#49
Closed
tim-devereux wants to merge 4 commits into
Closed
Conversation
NMS on the root-density grid was finding multiple peaks within one tree's crown, causing a single large tree to be output as 8-15 separate trees. raysegment.cpp: - Clamp all four grid-index computations to [0, dims-1] to fix out-of-bounds Eigen assertions on boundary points (ceil vs floor mismatch in grid sizing). - After NMS, merge all root clusters into one when (a) the canopy cells form a single connected BFS region and (b) the canopy footprint is consistent with a single tree crown (canopy_area / max_height^2 < 1.5). Forests with multiple canopy components, or whose combined footprint exceeds the single-tree threshold, are left unmerged. raytrees.cpp: - At trunk level, pass add_offshoots=false to bifurcate() so that when a merged single-tree root cluster has multiple sub-paths, only the dominant trunk path is kept and no new tree sections are spawned.
When raysegment merges multiple NMS root clusters into one (single-tree case), raytrees found multiple spatial sub-clusters at the trunk level. With add_offshoots=false those sub-clusters were silently dropped, leaving most of the tree's points unassigned. With the original add_offshoots=true they spawned new root sections (extra trees). Fix: in bifurcate(), when par == -1 (trunk level), set the new section's parent to sec_ (the current trunk) instead of inheriting -1, and register it in sections_[sec_].children. This makes trunk-level sub-clusters branches of the same tree rather than new roots, so all points are retained in one complete reconstruction. Forest behaviour is unchanged: each forest tree has its own root cluster, so trunk-level bifurcation never fires for them.
tests/validate_trees.py validates rayextract trees output quality:
- Tree count (must match --expected-trees)
- Point retention (segmented output vs input count)
- Height completeness (mesh zmax >= 85% of cloud zmax)
- XY spatial coverage (mesh footprint vs cloud footprint)
- Coverage: fraction of sampled input points within 1/2/4 m of the
nearest mesh vertex (primary check: >= 70% within 2 m)
- Phantom branch detection: mesh vertices far from all input points
Usage:
python3 tests/validate_trees.py \
--binary build/bin/rayextract \
--cloud test_data/split_trees/1.ply \
--mesh test_data/split_trees/1_mesh.ply \
[--no-run] # skip extraction, check existing outputs
Exit 0 on pass, 1 on failure. Pure Python stdlib, no dependencies.
…ing writes Patch the LAS 1.2 legacy point count field (offset 107) on disk after closing, since laszip_close_writer overwrites it when the count was unknown at open time.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.