This repository contains two related tools:
mask.py: multi-mask extraction from one large target point cloudsegfix_trees.py: per-tree segmentation correction for RayCloudTools outputs using masks from the same site
Install the package from the repository root:
python -m pip install .For editable development install:
python -m pip install -e .Optional extras:
python -m pip install .[plot]
python -m pip install .[all]This package installs two console scripts:
point-masking-mask-> runsmask.pypoint-masking-segfix-> runssegfix_trees.py
If you only need the core dependencies, the following are still required:
python -m pip install numpy scipy plyfile tqdm
python -m pip install "laspy[lazrs]"Use mask.py when you have:
- a folder of mask files named as
{tree_id}_{stem_id}or{tree_id} - a target point cloud (single file or folder) to assign against masks
- a need to produce mask-wise outputs with explicit IDs
- Parses IDs from mask filenames:
{tree_id}_{stem_id}-> uses both values{tree_id}-> defaultsstem_id=1
- Validates ID ranges:
tree_id:1..19999stem_id:1..26
- Groups duplicate mask IDs and treats them as one unique mask.
- Uses nearest-distance search (KD-tree) as the primary inclusion method.
- By default writes both:
- LAS/LAZ outputs per unique mask with extra dimensions
tree_idandstem_id - PLY outputs per unique mask with fields
(x, y, z, tree_id, stem_id)
- LAS/LAZ outputs per unique mask with extra dimensions
- Optional QC/debug plotting (
--debug) after assignment:- per-mask 3-view figures (
*_views.png): top, front, aerial qc_overview_2x2.pngfrom sampled masks- persistent selection state in
qc_plots/debug_selection.jsonfor reproducible debug comparisons
- per-mask 3-view figures (
--ids-only: write only LAS/LAZ withtree_idandstem_id--ply-only: write only PLY outputs
--hull-fillenables a secondary inclusion pass for unmatched points.- Nearest-distance assignment remains primary; hull fill only adds missed points.
- Hull support points are built from voxelized z-slices using the extreme XY point rule.
- Related flags:
--distance(also used as hull support spacing base)--vox-mul(default3, voxel size multiplier)--hull-eps(default0.05, near-hull tolerance)
python mask.py \
--mask-folder ./masks \
--target ./plot_cloud.laz \
--distance 0.5 \
--output ./masked_output \
--chunk-size 500000python mask.py \
--mask-folder ./masks \
--target ./plot_cloud.ply \
--distance 0.5 \
--ply-only \
--hull-fill \
--vox-mul 3 \
--hull-eps 0.05Current default is to produce both LAS/LAZ (with ID extras) and PLY per-mask outputs. This can be changed later in mask.py by adjusting write_las / write_ply default selection logic in main().
Use segfix_trees.py when you have RayCloudTools automated segmentation outputs split per tree and want to correct them using an existing mask set from the same site.
- Inputs are target tree files (one tree per file) and mask files.
- Candidate masks are selected only by overlapping bounding boxes.
- For each target point, the script assigns to the closest overlapping mask.
- Confidence is radius-based:
- matched: closest distance <=
--distance - uncertain: closest distance >
--distance
- matched: closest distance <=
- Outputs are written per mask tree:
{mask}_matched.ply{mask}_uncertain.ply
- If a target tree has no overlapping masks, the original target file is copied through unchanged.
This guarantees points are not dropped during assignment for overlap cases: each point is routed to one closest overlapping mask, then split into matched vs uncertain by radius.
python segfix_trees.py \
./target_trees \
-m ./site_masks \
-o ./segfix_output \
--distance 0.5 \
--chunk-size 500000 \
--workers 4 \
--save-target-filenamecurrent_id_map.csv: target ID to filename mapping (legacy filename, target-based columns:target_id,target_filename)link_report.csv: selected mask, overlap count, matched/uncertain totals per target treemerge_report.csv: matched/uncertain totals per mask tree with contributing target IDs