changeset 0:53ee54da7150 draft default tip

planemo upload for repository https://github.com/bgruening/galaxytools/tree/master/tools/3dtrees_smart_tile commit fe65e773176a1e35cb4ba32ce9e038e95e780d4c
author bgruening
date Tue, 27 Jan 2026 13:22:53 +0000
parents
children
files smart_tile.xml test-data/mikro.laz test-data/mikro_preview.png test-data/mikro_res1.laz test-data/mikro_segmented.laz
diffstat 5 files changed, 257 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smart_tile.xml	Tue Jan 27 13:22:53 2026 +0000
@@ -0,0 +1,257 @@
+<tool id="3dtrees_smart_tile" name="3DTrees: SmartTile" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="24.2">
+    <description>Subsampling, tiling, merging and matching of (multiple) point clouds</description>
+    <macros>
+        <token name="@TOOL_VERSION@">1.0.0</token>
+        <token name="@VERSION_SUFFIX@">0</token>
+    </macros>
+    <requirements>
+        <container type="docker">ghcr.io/3dtrees-earth/3dtrees_smart_tile:@TOOL_VERSION@</container>
+    </requirements>
+    <command detect_errors="exit_code"><![CDATA[
+        ## Create output directory
+        mkdir -p output_dir &&
+
+        ## Task-specific input setup and command execution
+        #if $operation.task == 'tile':
+            ## Create input directory and symlink files
+            mkdir -p input_dir &&
+            #for $f in $operation.input_files:
+                ln -s '$f' input_dir/'${f.element_identifier}.laz' &&
+            #end for
+
+            ## Run tile task
+            python -u /src/run.py
+                --task tile
+                --input-dir input_dir
+                --output-dir output_dir
+                --tile-length '$operation.tile_length'
+                --tile-buffer '$operation.tile_buffer'
+                #if $operation.tiling_threshold:
+                    --tiling-threshold '$operation.tiling_threshold'
+                #end if
+                --resolution-1 '$operation.resolution_1'
+                --resolution-2 '$operation.resolution_2'
+                --skip-dimension-reduction '$operation.skip_dimension_reduction'
+                --num-spatial-chunks \${GALAXY_SLOTS:-4}
+                --workers '$operation.workers'
+                --threads \${GALAXY_SLOTS:-4}
+
+        #elif $operation.task == 'merge':
+            ## Create input directories and symlink files
+            mkdir -p input_segmented &&
+            #for $f in $operation.input_segmented:
+                ln -s '$f' input_segmented/'${f.element_identifier}.laz' &&
+            #end for
+
+            mkdir -p input_res1 &&
+            #for $f in $operation.input_res1:
+                ln -s '$f' input_res1/'${f.element_identifier}.laz' &&
+            #end for
+
+            #if $operation.input_original:
+                mkdir -p input_original &&
+                #for $f in $operation.input_original:
+                    ln -s '$f' input_original/'${f.element_identifier}.laz' &&
+                #end for
+            #end if
+
+            ## Run merge task
+            python -u /src/run.py
+                --task merge
+                --subsampled-segmented-folder input_segmented
+                --subsampled-target-folder input_res1
+                #if $operation.input_original:
+                    --original-input-dir input_original
+                #end if
+                --output-tiles-folder output_dir/output_tiles
+                --buffer '$operation.buffer'
+                --overlap-threshold '$operation.overlap_threshold'
+                --max-centroid-distance '$operation.max_centroid_distance'
+                --correspondence-tolerance '$operation.correspondence_tolerance'
+                --max-volume-for-merge '$operation.max_volume_for_merge'
+                --min-cluster-size '$operation.min_cluster_size'
+                --border-zone-width '$operation.border_zone_width'
+                $operation.disable_matching
+                --workers 2
+        #end if
+    ]]></command>
+    <inputs>
+            <conditional name="operation">
+            <param name="task" type="select" label="Task">
+                <option value="tile">Tile</option>
+                <option value="merge">Merge</option>
+            </param>
+            <when value="tile">
+                <param name="input_files" type="data" format="laz,las" multiple="true" label="Input LAZ/LAS files" help="Collection of point cloud files to tile and subsample"/>
+                <param argument="--tile-length" type="integer" min="1" max="10000" value="300" label="Tile Length" help="Size of tiles in meters (default: 300m)"/>
+                <param argument="--tile-buffer" type="integer" min="1" max="10000" value="20" label="Tile Buffer" help="Overlap/buffer between tiles in meters (default: 20m)"/>
+                <param argument="--tiling-threshold" type="float" min="0.1" max="50000" value="10000" optional="true" label="Tiling Threshold (MB)" help="File size threshold in MB. If input folder has single file below this size, skip tiling (optional)"/>
+                <param argument="--resolution-1" type="float" min="0.001" max="1.0" value="0.01" label="Resolution 1 (m)" help="First subsampling resolution in meters (default: 0.02 = 2cm)"/>
+                <param argument="--resolution-2" type="float" min="0.001" max="1.0" value="0.1" label="Resolution 2 (m)" help="Second subsampling resolution in meters (default: 0.1 = 10cm)"/>
+                <param argument="--skip-dimension-reduction" type="boolean" truevalue="--skip-dimension-reduction" falsevalue="" checked="true" label="Skip Dimension Reduction" help="Keep all point dimensions instead of reducing to XYZ-only. Set to False only for raw pre-segmentation data (default: True)"/>
+                <param argument="--workers" type="hidden" min="1" max="10" value="2" label="Workers" help="Number of workers for parallel processing (default: 2)"/>
+            </when>
+            <when value="merge">
+                <param name="input_segmented" type="data" format="laz" multiple="true" label="Segmented files (e.g.10cm)" help="Collection of subsampled LAZ files with predictions (PredInstance/PredSemantic dimensions)"/>
+                <param name="input_res1" type="data" format="laz" multiple="true" label="Subsampled target files (e.g. 1cm)" help="Collection of subsampled LAZ files at target resolution (for remapping)"/>
+                <param name="input_original" type="data" format="laz,las" multiple="true" optional="true" label="Original input files (optional)" help="Optional collection of original input LAZ files for final remap to original resolution"/>
+                <param argument="--buffer" type="float" min="0" max="100" value="30.0" label="Buffer Distance (m)" help="Buffer distance for filtering in meters (default: 10.0m)"/>
+                <param argument="--overlap-threshold" type="float" min="0" max="1" value="0.3" label="Overlap Threshold" help="Overlap ratio threshold for instance matching (0.3 = 30%)"/>
+                <param argument="--max-centroid-distance" type="float" min="0" max="100" value="3.0" label="Max Centroid Distance (m)" help="Maximum centroid distance to merge instances in meters (default: 3.0m)"/>
+                <param argument="--max-volume-for-merge" type="float" min="0" max="100" value="4.0" label="Max Volume for Merge (m³)" help="Max convex hull volume for small instance merging in m³ (default: 4.0m³)"/>
+                <param argument="--min-cluster-size" type="integer" min="1" max="10000" value="300" label="Minimum Cluster Size" help="Minimum cluster size in points for reassignment (default: 300)"/>
+                <param argument="--border-zone-width" type="float" min="0" max="100" value="10.0" label="Border Zone Width (m)" help="Width of border zone beyond buffer for instance matching in meters (default: 10.0m)"/>
+                <param argument="--correspondence-tolerance" type="float" min="0" max="1" value="0.05" label="Correspondence Tolerance (m)" help="Max distance for point correspondence in meters - should be small ~5cm (default: 0.05m)"/>
+                <param argument="--disable-matching" type="boolean" truevalue="--disable-matching" falsevalue="" checked="false" label="Disable Matching" help="Disable cross-tile instance matching (default: False)"/>
+                <param argument="--workers" type="hidden" min="1" max="10" value="2" label="Workers" help="Number of workers for parallel processing (default: 2)"/>
+            </when>
+        </conditional>
+    </inputs>
+    <outputs>
+        <!-- Tile task outputs: collection of all output files -->
+        <collection name="Subsampled_Resolution_1" type="list" label="${tool.name}: Subsampled ${operation.resolution_1}m">
+            <filter>operation['task'] == "tile"</filter>
+            <discover_datasets pattern="__name_and_ext__" directory="output_dir/subsampled_res1" format="laz" recurse="false"/>
+        </collection>
+        <collection name="Subsampled_Resolution_2" type="list" label="${tool.name}: Subsampled ${operation.resolution_2}m">
+            <filter>operation['task'] == "tile"</filter>
+            <discover_datasets pattern="__name_and_ext__" directory="output_dir/subsampled_res2" format="laz" recurse="false"/>
+        </collection>
+        <data name="output_png" format="png" label="${tool.name}: Tiling preview" from_work_dir="output_dir/overview_copc_tiles.png">
+            <filter>operation['task'] == "tile"</filter>
+        </data>
+
+        <!-- Merge task outputs: collection of per-tile files + optional merged file -->
+        <collection name="output_merge_tiles" type="list" label="${tool.name}: Original with added dimensions">
+            <filter>operation['task'] == "merge"</filter>
+            <discover_datasets pattern="__name_and_ext__" directory="output_dir/original_with_predictions" format="laz"/>
+        </collection>
+        <data name="output_merged_laz" format="laz" label="${tool.name}: Merged LAZ file" from_work_dir="merged.laz">
+            <filter>operation['task'] == "merge"</filter>
+        </data>
+        
+    </outputs>
+    <tests>
+        <test expect_num_outputs="3">
+            <conditional name="operation">
+                <param name="task" value="tile"/>
+                <param name="input_files" value="mikro.laz"/>
+                <param name="tile_length" value="50"/>
+                <param name="tile_buffer" value="20"/>
+                <param name="tiling_threshold" value="3"/>
+                <param name="resolution_1" value="0.01"/>
+                <param name="resolution_2" value="0.1"/>
+            </conditional>
+            <output_collection name="Subsampled_Resolution_1" type="list" count="1"/>
+            <output_collection name="Subsampled_Resolution_2" type="list" count="1"/>
+            <output name="output_png" file="mikro_preview.png" compare="image_diff">
+                <assert_contents>
+                    <has_image_center_of_mass center_of_mass="1732,1785" eps="100"/>
+                </assert_contents>
+            </output>
+        </test>
+        <test expect_num_outputs="2">
+            <conditional name="operation">
+                <param name="task" value="merge"/>
+                <param name="input_segmented" value="mikro_segmented.laz"/>
+                <param name="input_res1" value="mikro_res1.laz"/>
+                <param name="input_original" value="mikro.laz"/>      
+            </conditional>
+            <output_collection name="output_merge_tiles" type="list" count="1"/>
+            <output name="output_merged_laz">
+                <assert_contents>
+                    <has_size value="47500" delta="1000"/>
+                </assert_contents>
+            </output>
+        </test>
+    </tests>
+    <help format="markdown">
+        **What it does**
+
+        This tool processes 3D point cloud data for tree segmentation with four task modes:
+
+        1. **Tile**: Subsample input point clouds and create overlapping tiles for processing
+        3. **Merge**: Remaps predictions to target resolution and merge tiles with instance matching
+
+        **Tile Task**
+
+        Processes input LAZ/LAS files through tiling and subsampling pipeline:
+        - Converts to COPC format
+        - Creates overlapping tiles
+        - Generates two subsampled resolutions (default: 2cm and 10cm)
+
+        *Parameters:*
+        - Tile Length: Size of tiles in meters (default: 100m)
+        - Tile Buffer: Overlap between tiles in meters (default: 5m)
+        - Tiling Threshold: File size threshold in MB - files below this skip tiling (optional)
+        - Resolution 1: First subsampling resolution in meters (default: 0.02 = 2cm)
+        - Resolution 2: Second subsampling resolution in meters (default: 0.1 = 10cm)
+        - Skip Dimension Reduction: Keep all point dimensions (default: True)
+
+        *Outputs:* Collection of tiled and subsampled LAZ files organized in subdirectories
+
+        **Remap Task**
+
+        Remaps predictions from source files to target resolution files using KDTree nearest neighbor matching.
+        Files are matched by spatial bounds.
+
+        *Parameters:*
+        - Source files: LAZ files with predictions (e.g., segmented 10cm files)
+        - Target files: LAZ files at target resolution (e.g., 2cm subsampled files)
+        - Tolerance: Bounds matching tolerance in meters (default: 5.0m)
+
+        *Outputs:* Collection of remapped LAZ files with predictions transferred to target resolution
+
+        **Merge Task**
+
+        Complete merge workflow:
+        1. Remaps 10cm predictions to target resolution (default: 2cm)
+        2. Merges overlapping tiles with cross-tile instance matching
+        3. Optionally remaps to original input resolution
+
+        *Parameters:*
+        - Input: Collection of 10cm subsampled LAZ files with predictions (PredInstance/PredSemantic)
+        - Target Resolution: Resolution for remapping (default: 2cm)
+        - Buffer: Buffer distance for filtering in meters (default: 10.0m)
+        - Overlap Threshold: Ratio for instance matching, 0-1 (default: 0.3 = 30%)
+        - Max Centroid Distance: Max distance to merge instances (default: 3.0m)
+        - Correspondence Tolerance: Point matching tolerance (default: 0.05m = 5cm)
+        - Max Volume for Merge: Max volume for small instance merging (default: 4.0m³)
+        - Min Cluster Size: Minimum points per cluster (default: 300)
+        - Border Zone Width: Width of border zone for matching (default: 10.0m)
+        - Retile Buffer: Buffer expansion during retiling (fixed: 2.0m)
+
+        *Outputs:*
+        - Collection of per-tile segmented LAZ files
+        - Single merged LAZ file (if not skipped)
+
+        **Remap and Merge Task**
+
+        Combined remap + merge workflow:
+        1. Remaps predictions from source to target files
+        2. Merges tiles with instance matching
+        3. Optionally remaps to original input resolution
+
+        Uses same parameters as separate remap and merge tasks.
+
+        *Outputs:*
+        - Collection of per-tile segmented LAZ files
+        - Single merged LAZ file (if not skipped)
+
+        **Processing Notes**
+
+        - All tasks use parallel processing with configurable workers (defaults to Galaxy job slots)
+        - Tiling uses spatial chunks aligned to voxel grid to prevent duplicate points
+        - Merge identifies whole trees, reassigns small clusters, and handles cross-tile instances
+        - Remap uses cKDTree for efficient nearest neighbor queries
+    </help>
+    <creator>
+        <person name="Kilian Gerberding" email="kilian.gerberding@geosense.uni-freiburg.de" identifier="0009-0002-5001-2571"/>
+        <organization name="3Dtrees-Team, University of Freiburg" url="https://github.com/3dTrees-earth"/>
+    </creator>
+    <citations>
+        <citation type="bibtex">
+            @misc{3dtrees_tile_merge, title = {3D Trees Tile and Merge Tool}, author = {3D Trees Project}, year = {2025}}
+        </citation>
+    </citations>
+</tool>
Binary file test-data/mikro.laz has changed
Binary file test-data/mikro_preview.png has changed
Binary file test-data/mikro_res1.laz has changed
Binary file test-data/mikro_segmented.laz has changed