changeset 0:f8bfa85cac4c draft default tip

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/crop_image/ commit 7a5037206d267aa7d9b7e5e062327c3464942471
author imgteam
date Fri, 06 Jun 2025 12:46:50 +0000
parents
children
files creators.xml crop_image.py crop_image.xml test-data/yx_float32.tiff test-data/yx_float32_uint8_0.tiff test-data/yx_float32_uint8_1.tiff test-data/yx_float32_uint8_2.tiff test-data/yx_uint8.tiff test-data/yxc_uint8.png test-data/yxc_uint8_mask.png test-data/yxc_uint8_uint8_2.png test-data/yxz_uint8.tiff test-data/zyx_uint16.tiff test-data/zyx_uint16_uint8_1.tiff tests.xml
diffstat 15 files changed, 301 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/creators.xml	Fri Jun 06 12:46:50 2025 +0000
@@ -0,0 +1,33 @@
+<macros>
+
+    <xml name="creators/bmcv">
+        <organization name="Biomedical Computer Vision Group, Heidelberg Universtiy" alternateName="BMCV" url="http://www.bioquant.uni-heidelberg.de/research/groups/biomedical_computer_vision.html" />
+        <yield />
+    </xml>
+
+    <xml name="creators/rmassei">
+        <person givenName="Riccardo" familyName="Massei"/>
+        <yield/>
+    </xml>
+
+    <xml name="creators/alliecreason">
+        <person givenName="Allison" familyName="Creason"/>
+        <yield/>
+    </xml>
+
+    <xml name="creators/bugraoezdemir">
+        <person givenName="Bugra" familyName="Oezdemir"/>
+        <yield/>
+    </xml>
+
+    <xml name="creators/thawn">
+        <person givenName="Till" familyName="Korten"/>
+        <yield/>
+    </xml>
+
+    <xml name="creators/pavanvidem">
+        <person givenName="Pavan" familyName="Videm"/>
+        <yield/>
+    </xml>
+
+</macros>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crop_image.py	Fri Jun 06 12:46:50 2025 +0000
@@ -0,0 +1,68 @@
+import argparse
+import os
+
+import numpy as np
+from giatools.image import Image
+
+
+def crop_image(
+    image_filepath: str,
+    labelmap_filepath: str,
+    output_ext: str,
+    output_dir: str,
+    skip_labels: frozenset[int],
+):
+    image = Image.read(image_filepath)
+    labelmap = Image.read(labelmap_filepath)
+
+    if image.axes != labelmap.axes:
+        raise ValueError(f'Axes mismatch between image ({image.axes}) and label map ({labelmap.axes}).')
+
+    if image.data.shape != labelmap.data.shape:
+        raise ValueError(f'Shape mismatch between image ({image.data.shape}) and label map ({labelmap.data.shape}).')
+
+    for label in np.unique(labelmap.data):
+        if label in skip_labels:
+            continue
+        roi_mask = (labelmap.data == label)
+        roi = crop_image_to_mask(image.data, roi_mask)
+        roi_image = Image(roi, image.axes).normalize_axes_like(image.original_axes)
+        roi_image.write(os.path.join(output_dir, f'{label}.{output_ext}'))
+
+
+def crop_image_to_mask(data: np.ndarray, mask: np.ndarray) -> np.ndarray:
+    """
+    Crop the `data` array to the minimal bounding box in `mask`.
+
+    The arguments are not modified.
+    """
+    assert data.shape == mask.shape
+
+    # Crop `data` to the convex hull of the mask in each dimension
+    for dim in range(data.ndim):
+        mask1d = mask.any(axis=tuple(i for i in range(mask.ndim) if i != dim))
+        mask1d_indices = np.where(mask1d)[0]
+        mask1d_indices_cvxhull = np.arange(min(mask1d_indices), max(mask1d_indices) + 1)
+        data = data.take(axis=dim, indices=mask1d_indices_cvxhull)
+
+    return data
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument('image', type=str)
+    parser.add_argument('labelmap', type=str)
+    parser.add_argument('skip_labels', type=str)
+    parser.add_argument('output_ext', type=str)
+    parser.add_argument('output_dir', type=str)
+    args = parser.parse_args()
+
+    crop_image(
+        image_filepath=args.image,
+        labelmap_filepath=args.labelmap,
+        output_ext=args.output_ext,
+        output_dir=args.output_dir,
+        skip_labels=frozenset(
+            int(label.strip()) for label in args.skip_labels.split(',') if label.strip()
+        ) if args.skip_labels.strip() else frozenset(),
+    )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crop_image.xml	Fri Jun 06 12:46:50 2025 +0000
@@ -0,0 +1,105 @@
+<tool id="ip_crop_image" name="Crop image" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="20.05"> 
+    <description>with giatools</description>
+    <macros>
+        <import>creators.xml</import>
+        <import>tests.xml</import>
+        <token name="@TOOL_VERSION@">0.4.1</token>
+        <token name="@VERSION_SUFFIX@">0</token>
+    </macros>
+    <creator>
+        <expand macro="creators/bmcv" />
+    </creator>
+    <edam_operations>
+        <edam_operation>operation_3443</edam_operation>
+    </edam_operations>
+    <xrefs>
+        <xref type="bio.tools">giatools</xref>
+    </xrefs>
+    <requirements>
+        <requirement type="package" version="@TOOL_VERSION@">giatools</requirement>
+    </requirements> 
+    <command detect_errors="aggressive"><![CDATA[
+
+        mkdir ./output &&
+        python '$__tool_directory__/crop_image.py'
+
+        '$image'
+        '$labelmap'
+        '$skip_labels'
+        '${image.ext}'
+
+        ./output
+
+    ]]></command>
+    <inputs>
+        <param name="image" type="data" format="png,tiff" label="Image file" help="The image to be cropped."/>
+        <param name="labelmap" type="data" format="png,tiff" label="Label map" help="Each label identifies an individual region of interest, for which a cropped image is produced."/>
+        <param name="skip_labels" type="text" label="Skip labels" value="0" optional="true" help="Comma-separated list of labels for which no cropped image shall be produced.">
+            <validator type="regex">^\d+(,\d+)*$|^$</validator>
+        </param>
+    </inputs>
+    <outputs>
+        <collection type="list" name="output" label="Crop ${on_string}" format_source="image">
+            <discover_datasets directory="output" pattern="__name_and_ext__"/>
+        </collection>
+    </outputs>
+    <tests>
+        <!-- Test 2D TIFF -->
+        <test>
+            <param name="image" value="yx_float32.tiff" ftype="tiff"/>
+            <param name="labelmap" value="yx_uint8.tiff"/>
+            <output_collection name="output" type="list" count="2">
+                <expand macro="tests/intensity_image_diff/element" name="1" value="yx_float32_uint8_1.tiff" ftype="tiff"/>
+                <expand macro="tests/intensity_image_diff/element" name="2" value="yx_float32_uint8_2.tiff" ftype="tiff"/>
+            </output_collection>
+        </test>
+        <!-- Test with `skip_labels` -->
+        <test>
+            <param name="image" value="yx_float32.tiff" ftype="tiff"/>
+            <param name="labelmap" value="yx_uint8.tiff"/>
+            <param name="skip_labels" value="0,1"/>
+            <output_collection name="output" type="list" count="1">
+                <expand macro="tests/intensity_image_diff/element" name="2" value="yx_float32_uint8_2.tiff" ftype="tiff"/>
+            </output_collection>
+        </test>
+        <!-- Test with empty `skip_labels` -->
+        <test>
+            <param name="image" value="yx_float32.tiff" ftype="tiff"/>
+            <param name="labelmap" value="yx_uint8.tiff"/>
+            <param name="skip_labels" value=""/>
+            <output_collection name="output" type="list" count="3">
+                <expand macro="tests/intensity_image_diff/element" name="0" value="yx_float32_uint8_0.tiff" ftype="tiff"/>
+                <expand macro="tests/intensity_image_diff/element" name="1" value="yx_float32_uint8_1.tiff" ftype="tiff"/>
+                <expand macro="tests/intensity_image_diff/element" name="2" value="yx_float32_uint8_2.tiff" ftype="tiff"/>
+            </output_collection>
+        </test>
+        <!-- Test 3D TIFF (multi-frame) -->
+        <test>
+            <param name="image" value="zyx_uint16.tiff" ftype="tiff"/>
+            <param name="labelmap" value="yxz_uint8.tiff"/>
+            <output_collection name="output" type="list" count="1">
+                <expand macro="tests/intensity_image_diff/element" name="1" value="zyx_uint16_uint8_1.tiff" ftype="tiff"/>
+            </output_collection>
+        </test>
+        <!-- Test PNG -->
+        <test>
+            <param name="image" value="yxc_uint8.png" ftype="png"/>
+            <param name="labelmap" value="yxc_uint8_mask.png"/>
+            <output_collection name="output" type="list" count="1">
+                <expand macro="tests/intensity_image_diff/element" name="2" value="yxc_uint8_uint8_2.png" ftype="png"/>
+            </output_collection>
+        </test>
+    </tests>
+    <help>
+
+        **Crops an image using one or more regions of interest.**
+
+        The image is cropped using a label map that identifies individual regions of interest. The image and the label map must be of equal size.
+
+        This operation preserves the file type of the image, the brightness, and the range of values.
+
+    </help>
+    <citations>
+        <citation type="doi">10.1016/j.jbiotec.2017.07.019</citation>
+    </citations>
+</tool>
Binary file test-data/yx_float32.tiff has changed
Binary file test-data/yx_float32_uint8_0.tiff has changed
Binary file test-data/yx_float32_uint8_1.tiff has changed
Binary file test-data/yx_float32_uint8_2.tiff has changed
Binary file test-data/yx_uint8.tiff has changed
Binary file test-data/yxc_uint8.png has changed
Binary file test-data/yxc_uint8_mask.png has changed
Binary file test-data/yxc_uint8_uint8_2.png has changed
Binary file test-data/yxz_uint8.tiff has changed
Binary file test-data/zyx_uint16.tiff has changed
Binary file test-data/zyx_uint16_uint8_1.tiff has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests.xml	Fri Jun 06 12:46:50 2025 +0000
@@ -0,0 +1,95 @@
+<macros>
+
+    <!-- Macros for verification of image outputs -->
+
+    <xml
+        name="tests/binary_image_diff"
+        tokens="name,value,ftype,metric,eps"
+        token_metric="mae"
+        token_eps="0.01">
+
+        <output name="@NAME@" value="@VALUE@" ftype="@FTYPE@" compare="image_diff" metric="@METRIC@" eps="@EPS@" pin_labels="0">
+            <assert_contents>
+                <has_image_n_labels n="2"/>
+                <yield/>
+            </assert_contents>
+        </output>
+
+    </xml>
+
+    <xml
+        name="tests/label_image_diff"
+        tokens="name,value,ftype,metric,eps,pin_labels"
+        token_metric="iou"
+        token_eps="0.01"
+        token_pin_labels="0">
+
+        <output name="@NAME@" value="@VALUE@" ftype="@FTYPE@" compare="image_diff" metric="@METRIC@" eps="@EPS@" pin_labels="@PIN_LABELS@">
+            <assert_contents>
+                <yield/>
+            </assert_contents>
+        </output>
+
+    </xml>
+
+    <xml
+        name="tests/intensity_image_diff"
+        tokens="name,value,ftype,metric,eps"
+        token_metric="rms"
+        token_eps="0.01">
+
+        <output name="@NAME@" value="@VALUE@" ftype="@FTYPE@" compare="image_diff" metric="@METRIC@" eps="@EPS@">
+            <assert_contents>
+                <yield/>
+            </assert_contents>
+        </output>
+
+    </xml>
+
+    <!-- Variants of the above for verification of collection elements -->
+
+    <xml
+        name="tests/binary_image_diff/element"
+        tokens="name,value,ftype,metric,eps"
+        token_metric="mae"
+        token_eps="0.01">
+
+        <element name="@NAME@" value="@VALUE@" ftype="@FTYPE@" compare="image_diff" metric="@METRIC@" eps="@EPS@" pin_labels="0">
+            <assert_contents>
+                <has_image_n_labels n="2"/>
+                <yield/>
+            </assert_contents>
+        </element>
+
+    </xml>
+
+    <xml
+        name="tests/label_image_diff/element"
+        tokens="name,value,ftype,metric,eps"
+        token_metric="iou"
+        token_eps="0.01"
+        token_pin_labels="0">
+
+        <element name="@NAME@" value="@VALUE@" ftype="@FTYPE@" compare="image_diff" metric="@METRIC@" eps="@EPS@" pin_labels="@PIN_LABELS@">
+            <assert_contents>
+                <yield/>
+            </assert_contents>
+        </element>
+
+    </xml>
+
+    <xml
+        name="tests/intensity_image_diff/element"
+        tokens="name,value,ftype,metric,eps"
+        token_metric="rms"
+        token_eps="0.01">
+
+        <element name="@NAME@" value="@VALUE@" ftype="@FTYPE@" compare="image_diff" metric="@METRIC@" eps="@EPS@">
+            <assert_contents>
+                <yield/>
+            </assert_contents>
+        </element>
+
+    </xml>
+
+</macros>