changeset 7:048545339ced draft default tip

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/2d_feature_extraction/ commit b8e0b656d417db6e2ad0f187fc3c5afff0c3acd7
author imgteam
date Tue, 06 Jan 2026 09:25:17 +0000
parents 8e3a52b74876
children
files 2d_feature_extraction.py 2d_feature_extraction.xml test-data/output/input13-bbox.tsv test-data/output/input13-centroid.tsv test-data/output/input9.tsv validators.xml
diffstat 6 files changed, 29 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/2d_feature_extraction.py	Mon Jan 05 14:35:43 2026 +0000
+++ b/2d_feature_extraction.py	Tue Jan 06 09:25:17 2026 +0000
@@ -45,11 +45,11 @@
     # Validate the input image
     try:
         label_image = tool.args.input_images['labels']
-        if any(label_image.shape[label_image.axes.index(axis)] > 1 for axis in label_image.axes if axis not in 'ZYX'):
+        if any(label_image.shape[label_image.axes.index(axis)] > 1 for axis in label_image.axes if axis not in 'XYZ'):
             raise ValueError(f'This tool is not applicable to images with {label_image.original_axes} axes.')
 
         # Extract the image features
-        for section in tool.run('ZYX'):  # the validation code above guarantees that we will have only a single iteration
+        for section in tool.run('XYZ'):  # the validation code above guarantees that we will have only a single iteration
             df = pd.DataFrame()
 
             # Get the labels array and cast to `uint8` if it is `bool` (`skimage.measure.regionprops` refuses `bool` typed arrays)
@@ -89,6 +89,14 @@
                         lambda ait: surface(labels_section_data, regions[ait].label),  # `skimage.measure.regionprops` cannot compute perimeters for 3-D data
                     )
 
+                # Add the object centroid using separate columns for the different coordinates
+                elif feature_name == 'centroid':
+                    for axis_idx, axis in enumerate(section['labels'].axes):  # XYZ
+                        if section['labels'].shape[axis_idx] > 1:
+                            df[f'{feature_name}_{axis.lower()}'] = df['it'].map(
+                                lambda ait: getattr(regions[ait], feature_name)[axis_idx],
+                            )
+
                 # Skip features that are not available when processing 3-D images
                 elif feature_name in ('eccentricity', 'moments_hu', 'orientation') and labels_section_data.ndim == 3:
                     print(f'Skip feature that is not available for 3-D images: "{feature_name}"')
--- a/2d_feature_extraction.xml	Mon Jan 05 14:35:43 2026 +0000
+++ b/2d_feature_extraction.xml	Tue Jan 06 09:25:17 2026 +0000
@@ -4,7 +4,7 @@
         <import>creators.xml</import>
         <import>validators.xml</import>
         <token name="@TOOL_VERSION@">0.25.2</token>
-        <token name="@VERSION_SUFFIX@">0</token>
+        <token name="@VERSION_SUFFIX@">1</token>
         <xml name="features">
             <param name="features" type="select" label="Available features" multiple="true" display="checkboxes"
                    help="*) Features marked with an asterisk are only available for 2-D images (not for 3-D images).">
@@ -231,7 +231,7 @@
 
 **Bounding box:** Bounding box `(min_row, min_col, max_row, max_col)`. Pixels belonging to the bounding box are in the half-open interval `[min_row; max_row)` and `[min_col; max_col)`.
 
-**Centroid:** Centroid coordinate tuple `(row, col)`.
+**Centroid:** Centroid coordinates in separate columns ``centroid_x``, ``centroid_y``, and ``centroid_z`` when processing 3-D data.
 
 **Eccentricity:** Eccentricity of the ellipse that has the same second-moments as the region. The eccentricity is the ratio of the focal distance (distance between focal points) over the major axis length. The value is in the interval [0, 1). When it is 0, the ellipse becomes a circle.
 
--- a/test-data/output/input13-bbox.tsv	Mon Jan 05 14:35:43 2026 +0000
+++ b/test-data/output/input13-bbox.tsv	Tue Jan 06 09:25:17 2026 +0000
@@ -1,3 +1,3 @@
 bbox
-\[50, 60, 100, 110\]
-\[150, 160, 200, 210\]
+\[60, 50, 110, 100\]
+\[160, 150, 210, 200\]
--- a/test-data/output/input13-centroid.tsv	Mon Jan 05 14:35:43 2026 +0000
+++ b/test-data/output/input13-centroid.tsv	Tue Jan 06 09:25:17 2026 +0000
@@ -1,3 +1,3 @@
-centroid
-\[74.5, 84.5\]
-\[174.5, 184.5\]
+centroid_x	centroid_y
+84.5	74.5
+184.5	174.5
--- a/test-data/output/input9.tsv	Mon Jan 05 14:35:43 2026 +0000
+++ b/test-data/output/input9.tsv	Tue Jan 06 09:25:17 2026 +0000
@@ -1,2 +1,2 @@
-area	area_convex	area_filled	axis_major_length	axis_minor_length	bbox	centroid	equivalent_diameter_area	euler_number	extent	inertia_tensor_eigvals	moments	perimeter	solidity	max_intensity	mean_intensity	min_intensity
-10076.0	19452.0	10076.0	141.5372[0-9]+	2.2275[0-9]+	\[0, 0, 0, 2, 100, 100\]	\[0.4791[0-9]+, 51.0215[0-9]+, 55.5112[0-9]+\]	26.7976[0-9]+	-1	0.5038	\[1633.5242[0-9]+, 1001.8878[0-9]+, 632.1326[0-9]+\]	\[\[\[10076.0, 559331.0, 39680985.0, 3075710795.0\], \[514093.0, 26719026.0, 1828782204.0, 137703070104.0\], \[34057349.0, 1680671976.0, 112117199682.0, 8307987945522.0\], \[2545051621.0, 120295106826.0, 7853098605480.0, 574813269790152.0\]\], \[\[4828.0, 278845.0, 20126387.0, 1574048161.0\], \[246982.0, 13386366.0, 940613844.0, 72136219614.0\], \[16531236.0, 855530424.0, 59225271630.0, 4513705336536.0\], \[1248767206.0, 62249971170.0, 4259056106556.0, 323493844156146.0\]\], \[\[4828.0, 278845.0, 20126387.0, 1574048161.0\], \[246982.0, 13386366.0, 940613844.0, 72136219614.0\], \[16531236.0, 855530424.0, 59225271630.0, 4513705336536.0\], \[1248767206.0, 62249971170.0, 4259056106556.0, 323493844156146.0\]\], \[\[4828.0, 278845.0, 20126387.0, 1574048161.0\], \[246982.0, 13386366.0, 940613844.0, 72136219614.0\], \[16531236.0, 855530424.0, 59225271630.0, 4513705336536.0\], \[1248767206.0, 62249971170.0, 4259056106556.0, 323493844156146.0\]\]\]	10076	0.5179[0-9]+	999.8037[0-9]+	523.4422[0-9]+	0.1145[0-9]+
+area	area_convex	area_filled	axis_major_length	axis_minor_length	bbox	centroid_x	centroid_y	centroid_z	equivalent_diameter_area	euler_number	extent	inertia_tensor_eigvals	moments	perimeter	solidity	max_intensity	mean_intensity	min_intensity
+10076.0	19452.0	10076.0	141.5372[0-9]+	2.2275[0-9]+	\[0, 0, 0, 100, 100, 2\]	55.5112[0-9]+	51.0215[0-9]+	0.4791[0-9]+	26.7976[0-9]+	-1	0.5038	\[1633.5242[0-9]+, 1001.8878[0-9]+, 632.1326[0-9]+\]	\[\[\[10076.0, 4828.0, 4828.0, 4828.0\], \[514093.0, 246982.0, 246982.0, 246982.0\], \[34057349.0, 16531236.0, 16531236.0, 16531236.0\], \[2545051621.0, 1248767206.0, 1248767206.0, 1248767206.0\]\], \[\[559331.0, 278845.0, 278845.0, 278845.0\], \[26719026.0, 13386366.0, 13386366.0, 13386366.0\], \[1680671976.0, 855530424.0, 855530424.0, 855530424.0\], \[120295106826.0, 62249971170.0, 62249971170.0, 62249971170.0\]\], \[\[39680985.0, 20126387.0, 20126387.0, 20126387.0\], \[1828782204.0, 940613844.0, 940613844.0, 940613844.0\], \[112117199682.0, 59225271630.0, 59225271630.0, 59225271630.0\], \[7853098605480.0, 4259056106556.0, 4259056106556.0, 4259056106556.0\]\], \[\[3075710795.0, 1574048161.0, 1574048161.0, 1574048161.0\], \[137703070104.0, 72136219614.0, 72136219614.0, 72136219614.0\], \[8307987945522.0, 4513705336536.0, 4513705336536.0, 4513705336536.0\], \[574813269790152.0, 323493844156146.0, 323493844156146.0, 323493844156146.0\]\]\]	10076	0.5179[0-9]+	999.8037[0-9]+	523.4422[0-9]+	0.1145[0-9]+
--- a/validators.xml	Mon Jan 05 14:35:43 2026 +0000
+++ b/validators.xml	Tue Jan 06 09:25:17 2026 +0000
@@ -32,6 +32,16 @@
             ><![CDATA[getattr(value.metadata, "depth", None) in (None, '') or int(value.metadata.depth) < 2]]></validator>
     </xml>
 
+    <xml name="validators/is_3d">
+        <!--
+        The OME-Zarr datatype in Galaxy is currently not derived from the Image datatype, and it does
+        hence not inherit the metadata fields like `depth`. To cope with that, we allow all datasets
+        except those where we *know* that they are *not* 3-D.
+        -->
+        <validator type="expression" message="Dataset is a 2-D image"
+            ><![CDATA[getattr(value.metadata, "depth", None) in (None, '') or int(value.metadata.depth) >= 2]]></validator>
+    </xml>
+
     <xml name="validators/is_binary">
         <!--
         The OME-Zarr datatype in Galaxy is currently not derived from the Image datatype, and it does