Mercurial > repos > bgruening > 3dtrees_smart_tile
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>
