Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions tools/raycloudtools.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<tool id="3dtrees_raycloudtools" name="3Dtrees: RayCloudTools" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="25.1" license="BSD-3-Clause">
<description>Tree instance segmentation</description>
<macros>
<token name="@TOOL_VERSION@">1.1.1</token>
<token name="@VERSION_SUFFIX@">0</token>
</macros>
<requirements>
<container type="docker">
ghcr.io/3dtrees-earth/3dtrees_rct:@TOOL_VERSION@
</container>
</requirements>

<command detect_errors="exit_code"><![CDATA[
mkdir 'in' &&
mkdir 'out' &&
ln -s '$input' 'in/$input.element_identifier' &&
python3 -u /src/run.py
--dataset-path 'in/$input.element_identifier'
--output-dir 'out'
--gradient '$gradient'
--max-diameter '$max_diameter'
--crop-length '$crop_length'
--distance-limit '$distance_limit'
--height-min '$height_min'
--girth-height-ratio '$girth_height_ratio'
--global-taper '$global_taper'
--global-taper-factor '$global_taper_factor'
--gravity-factor '$gravity_factor'
#if $branch_segmentation:
--branch-segmentation
#end if
#if $treeinfo:
--treeinfo
#end if
#if $branch_data:
--branch_data

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Underscore in --branch_data flag mismatches parameter definition

High Severity

The command passes --branch_data (underscore) to run.py, but the parameter is declared with argument="--branch-data" (hyphen). Every other multi-word flag in the command uses hyphens consistently. If the Python script's argparse expects --branch-data, the underscore variant will be unrecognized and cause a runtime error when a user enables the branch data option.

Additional Locations (1)
Fix in Cursor Fix in Web

#end if
]]>
</command>

<inputs>
<param name="input" type="data" format="laz" label="Input Dataset (.laz)"
help="Input file to process"/>
<!-- Add your specific parameters from parameters.py -->
<!-- rayextract terrain -->
<param argument="--gradient" type="float" min="0.001" max="1000" value="1" label="Gradient" help="Gradient threshold for terrain extraction"/>
<!-- rayextract trees -->
<param argument="--max-diameter" type="float" min="0.01" max="100" value="0.9" label="Maximum diameter" help="maximum trunk diameter in segmenting trees (m)"/>
<param argument="--crop-length" type="float" min="0.01" max="100" value="1" label="Crop length" help="Crops branches up to this distance from tip (m)."/>
<param argument="--distance-limit" type="float" min="0.01" max="10" value="1" label="Distance limit" help="Maximum distance between neighbour points in a tree (m)"/>
<param argument="--height-min" type="float" min="0.01" max="1000" value="2" label="Minimum tree height" help="Minimum height counted as a tree (m)"/>
<param argument="--girth-height-ratio" type="float" min="0.001" max="0.5" value="0.12" label="Girth height ratio" help="Amount up tree's height to estimate trunk girth"/>
<param argument="--global-taper" type="float" min="0" max="1" value="0.024" label="Global taper" help="Force taper value (diameter per length) for trees under global_taper_factor of max tree height - use 0 to estimate global taper from the data"/>
<param argument="--global-taper-factor" type="float" min="0" max="1" value="0.3" label="Global taper factor" help="1 estimates same taper for whole scan, 0 is per-tree tapering, values between 0 and 1 produce soft cutoff at this amount of max tree height"/>
<param argument="--gravity-factor" type="float" min="0" max="1" value="0.3" label="Gravity factor" help="Larger values preference vertical trees"/>
<param argument="--branch-segmentation" type="boolean" checked="false" label="Branch segmentation" help="Segments per branch segment - assigns IDs per branch segment instead of per tree instance"/>
<!-- treeinfo -->
<param argument="--treeinfo" type="boolean" checked="false" label="Treeinfo" help="Calculate tree attributes - dbh, height, crown radius, volume, ..."/>
<param argument="--branch-data" type="boolean" checked="false" label="Branch data" help="Calculate branch attributes - branch number, segment_length, branch order number, extension and position in branch integers per-segment"/>
</inputs>

<outputs>
<!-- collection with terrain, segmented point cloud, and treefile -->
<collection name="raycloudtools_outputs_default" type="list" label="RayCloudTools">
<!--to exclude tree meshes pattern="(?P&lt;designation&gt;.*_segmented|.*_trees|^(?!.*trees).*_mesh)\.(?P&lt;ext&gt;laz|txt|(?&lt;=_mesh\.)ply)"-->
<discover_datasets pattern="(?P&lt;designation&gt;.*_segmented|.*_trees|.*_mesh)\.(?P&lt;ext&gt;laz|txt|(?&lt;=_mesh\.)ply)" directory="out" ext="$ext"/>
<filter>not treeinfo</filter>
</collection>
<!-- collection with terrain, segmented point cloud, and treefile with tree attributes -->
<collection name="raycloudtools_outputs_treeinfo" type="list" label="RayCloudTools (treeinfo)">
<!-- to exclude tree meshes pattern="(?P&lt;designation&gt;.*_segmented|.*_trees_info|^(?!.*trees).*_mesh)\.(?P&lt;ext&gt;laz|txt|(?&lt;=_mesh\.)ply)"-->
<discover_datasets pattern="(?P&lt;designation&gt;.*_segmented|.*_trees_info|.*_mesh)\.(?P&lt;ext&gt;laz|txt|(?&lt;=_mesh\.)ply)" directory="out" ext="$ext"/>
<filter>treeinfo</filter>
</collection>
</outputs>

<tests>
<test expect_num_outputs="1">
<param name="input" value="Example_Tree_RCT.laz"/>
<output_collection name="raycloudtools_outputs_default" count="4" type="list">
<element name="Example_Tree_RCT_mesh" file="Example_Tree_RCT_mesh.ply" compare="contains"/>
<element name="Example_Tree_RCT_segmented" file="Example_Tree_RCT_segmented.laz" compare="contains"/>
<element name="Example_Tree_RCT_trees" file="Example_Tree_RCT_trees.txt" compare="contains"/>
<element name="Example_Tree_RCT_trees_mesh" file="Example_Tree_RCT_trees_mesh.ply" compare="contains"/>
</output_collection>
</test>
<test expect_num_outputs="1">
<param name="input" value="Example_Tree_RCT.laz"/>
<param name="treeinfo" value="true"/>
<output_collection name="raycloudtools_outputs_treeinfo" count="4" type="list">
<element name="Example_Tree_RCT_mesh" file="Example_Tree_RCT_mesh.ply" compare="contains"/>
<element name="Example_Tree_RCT_segmented" file="Example_Tree_RCT_segmented.laz" compare="contains"/>
<element name="Example_Tree_RCT_trees_info" file="Example_Tree_RCT_trees_info.txt" compare="contains"/>
<element name="Example_Tree_RCT_trees_mesh" file="Example_Tree_RCT_trees_mesh.ply" compare="contains"/>
</output_collection>
</test>
</tests>

<help format="markdown">
**What it does**

This tool performs graph-based tree instance segmentation on LiDAR point clouds using the **RayExtract** algorithm (Devereux et al., 2026) implemented as part of **RayCloudTools** (Lowe &amp; Stepanas, 2021).
It is platform-agnostic and works across airborne (ULS), terrestrial (TLS), and mobile (MLS) laser scanning data, as long as trees are well-represented by points along the entire tree length.

-----

**Processing Steps**

- Convert input point cloud to LAZ 1.2
- Import point cloud as ray cloud
- Extract terrain
- Extract trees
- Convert point color (segmentation result) to instance IDs
- Add instance IDs back to input point cloud

-----

**Output**

Original LAZ point cloud + instance IDs in extra dimension 'PredInstance_RCT'.

***Tip:** We recommend using the '3DTrees: Tile and Merge' or '3DTrees: Smart Tile' tool to process large point clouds (workflow: tile → segment → merge)!*

-----

**Third-Party Components**

You agree to comply with the licence terms for these components as part of accessing the tool.

**RayCloudTools:** Copyright (c) 2020, Commonwealth Scientific and Industrial Research Organisation (CSIRO) ABN 41 687 119 230 | [CSIRO-Open Source Software License (variation of the BSD / MIT License)](https://github.com/csiro-robotics/raycloudtools);
**PDAL:** Copyright (c) 2025, Hobu, Inc. (howard@hobu.co) | [pdal License (BSD)](https://github.com/PDAL/PDAL?tab=License-1-ov-file#readme);
**NumPy:** Copyright (c) 2005-2025, NumPy Developers | [numpy License (BSD)](https://github.com/numpy/numpy?tab=License-1-ov-file#readme);
**LasPy:** Copyright (c) 2012, Grant Brown, grant.brown73 at gmail.com, Copyright (c) 2012, Howard Butler, hobu.inc at gmail.com, Copyright (c) 2020, Thomas Montaigu, thomas.montaigu@laposte.net | [laspy License](https://github.com/laspy/laspy?tab=License-1-ov-file#readme);
**Open3D:** Copyright (c) 2018-2023 www.open3d.org | [Open3D License (MIT)](https://github.com/isl-org/Open3D?tab=License-1-ov-file#readme).
</help>
<creator>
<person name="Hannah Greven" email="hannah.greven@hnee.de"/>
<organization name="3Dtrees-Team, University of Freiburg" url="https://github.com/3dTrees-earth"/>
</creator>
<citations>
<citation type="doi">10.1016/j.rse.2025.115162</citation>
<citation type="doi">10.1109/ACCESS.2021.3084954</citation>
<citation type="bibtex">
@misc{3dtrees_raycloudtools, title = {3Dtrees: RayCloudTools}, author = {3Dtrees-Project}, year = {2025}}
</citation>
</citations>
</tool>