view smart_tile.xml @ 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
line wrap: on
line source

<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>