changeset 0:6f09b367cd9a draft default tip

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/colorize_labels commit 4344f548f365dba87c20188d6e3c2df8630d2313
author imgteam
date Tue, 24 Sep 2024 17:30:11 +0000
parents
children
files colorize_labels.py colorize_labels.xml creators.xml test-data/input1.tif test-data/input2.tif test-data/input3.tif test-data/output1.png test-data/output2.png test-data/output3.png tests.xml
diffstat 10 files changed, 317 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/colorize_labels.py	Tue Sep 24 17:30:11 2024 +0000
@@ -0,0 +1,94 @@
+import argparse
+
+import giatools.io
+import matplotlib.pyplot as plt
+import networkx as nx
+import numpy as np
+import scipy.ndimage as ndi
+import skimage.io
+import skimage.util
+
+
+def color_hex_to_rgb_tuple(hex):
+    if hex.startswith('#'):
+        hex = hex[1:]
+    return (
+        int(hex[0:2], 16),
+        int(hex[2:4], 16),
+        int(hex[4:6], 16),
+    )
+
+
+def build_label_adjacency_graph(im, radius, bg_label):
+    G = nx.Graph()
+    for label in np.unique(im):
+
+        if label == bg_label:
+            continue
+
+        G.add_node(label)
+
+        cc = (im == label)
+        neighborhood = (ndi.distance_transform_edt(~cc) <= radius)
+        adjacent_labels = np.unique(im[neighborhood])
+
+        for adjacent_label in adjacent_labels:
+
+            if adjacent_label == bg_label or adjacent_label <= label:
+                continue
+
+            G.add_edge(label, adjacent_label)
+            G.add_edge(adjacent_label, label)
+
+    return G
+
+
+def get_n_unique_mpl_colors(n, colormap='jet', cyclic=False):
+    """
+    Yields `n` unique colors from the given `colormap`.
+
+    Set `cyclic` to `True` if the `colormap` is cyclic.
+    """
+    cmap = plt.get_cmap(colormap)
+    m = n if cyclic else n - 1
+    for i in range(n):
+        yield np.multiply(255, cmap(i / m))
+
+
+if __name__ == '__main__':
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('input', type=str)
+    parser.add_argument('--bg_label', type=int)
+    parser.add_argument('--bg_color', type=str)
+    parser.add_argument('--radius', type=int)
+    parser.add_argument('--output', type=str)
+    args = parser.parse_args()
+
+    # Load image and normalize
+    im = giatools.io.imread(args.input)
+    im = np.squeeze(im)
+    assert im.ndim == 2
+
+    # Build adjacency graph of the labels
+    G = build_label_adjacency_graph(im, args.radius, args.bg_label)
+
+    # Apply greedy coloring
+    graph_coloring = nx.greedy_color(G)
+    unique_colors = frozenset(graph_coloring.values())
+
+    # Assign colors to nodes based on the greedy coloring
+    graph_color_to_mpl_color = dict(zip(unique_colors, get_n_unique_mpl_colors(len(unique_colors))))
+    node_colors = [graph_color_to_mpl_color[graph_coloring[n]] for n in G.nodes()]
+
+    # Render result
+    bg_color_rgb = color_hex_to_rgb_tuple(args.bg_color)
+    result = np.dstack([np.full(im.shape, bg_color_rgb[ch], np.uint8) for ch in range(3)])
+    for label, label_color in zip(G.nodes(), node_colors):
+
+        cc = (im == label)
+        for ch in range(3):
+            result[:, :, ch][cc] = label_color[ch]
+
+    # Write result image
+    skimage.io.imsave(args.output, result)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/colorize_labels.xml	Tue Sep 24 17:30:11 2024 +0000
@@ -0,0 +1,100 @@
+<tool id="colorize_labels" name="Colorize label map" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="20.05">
+    <description>with NetworkX</description>
+    <macros>
+        <import>creators.xml</import>
+        <import>tests.xml</import>
+        <token name="@TOOL_VERSION@">3.2.1</token>
+        <token name="@VERSION_SUFFIX@">3</token>
+    </macros>
+    <creator>
+        <expand macro="creators/bmcv" />
+    </creator>
+    <edam_operations>
+        <edam_operation>operation_3443</edam_operation>
+    </edam_operations>
+    <requirements>
+        <requirement type="package" version="@TOOL_VERSION@">networkx</requirement>
+        <requirement type="package" version="1.22">numpy</requirement>
+        <requirement type="package" version="0.18.1">scikit-image</requirement>
+        <requirement type="package" version="0.1">giatools</requirement>
+    </requirements>
+    <command><![CDATA[
+    
+    ## Inputs
+    
+    python '$__tool_directory__/colorize_labels.py' '$input'
+    --radius $radius
+    --bg_label $bg_label
+    --bg_color '$bg_color'
+    
+    ## Outputs
+    
+    --output output.png
+    
+    ]]>
+    </command>
+    <inputs>
+        <param name="input" type="data" format="tiff,png" label="Input image (label map)" />
+        <param argument="--radius" type="integer" min="1" value="10" label="Radius of the neighborhood" help="Defines the neighborhood (in pixels) where labels are considered to be adjacent." />
+        <param argument="--bg_label" type="integer" value="0" label="Background label" />
+        <param argument="--bg_color" type="color" value="#000000" label="Background color"/>
+    </inputs>
+    <outputs>
+       <data format="png" name="output" from_work_dir="output.png" />
+    </outputs>
+    <tests>
+        <!-- int64 -->
+        <test>
+            <param name="input" value="input1.tif" />
+            <param name="radius" value="1" />
+            <param name="bg_label" value="0" />
+            <param name="bg_color" value="#5a5a5a" />
+            <expand macro="tests/intensity_image_diff" name="output" value="output1.png" ftype="png">
+                <has_image_channels channels="3"/>
+            </expand>
+        </test>
+        <!-- uint8 -->
+        <test>
+            <param name="input" value="input2.tif" />
+            <param name="radius" value="10" />
+            <param name="bg_label" value="0" />
+            <param name="bg_color" value="#ffffff" />
+            <expand macro="tests/intensity_image_diff" name="output" value="output2.png" ftype="png">
+                <has_image_channels channels="3"/>
+            </expand>
+        </test>
+        <!-- uint16 -->
+        <test>
+            <param name="input" value="input3.tif" />
+            <param name="radius" value="100" />
+            <param name="bg_label" value="0" />
+            <param name="bg_color" value="#ffffff" />
+            <expand macro="tests/intensity_image_diff" name="output" value="output3.png" ftype="png">
+                <has_image_channels channels="3"/>
+            </expand>
+        </test>
+    </tests>
+    <help>
+
+        **Colorizes a 2-D label map for visualization using greedy coloring.**
+
+        Label maps are produced by segmentation and other image analysis steps.
+        Direct inspection of label maps can be difficult,
+        because labels usually correspond to gray values which are difficult to
+        distinguish visually from each other and from the image background.
+        To facilitate the visual inspection of label maps, this tools converts
+        label maps to color images, by assigning each label a unique color.
+
+    </help>
+    <citations>
+        <citation type="bibtex">
+        @inproceedings{networkx,
+          author = {Hagberg, Aric A. and Schult, Daniel A. and Swart, Pieter J.},
+          title = {Exploring network structure, dynamics, and function using {NetworkX}},
+          booktitle = {Proc. of the 7th Python in Science Conference (SciPy 2008)},
+          pages = {11--15},
+          year = {2008},
+        }
+        </citation>
+    </citations>
+</tool>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/creators.xml	Tue Sep 24 17:30:11 2024 +0000
@@ -0,0 +1,28 @@
+<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>
+    
+</macros>
Binary file test-data/input1.tif has changed
Binary file test-data/input2.tif has changed
Binary file test-data/input3.tif has changed
Binary file test-data/output1.png has changed
Binary file test-data/output2.png has changed
Binary file test-data/output3.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests.xml	Tue Sep 24 17:30:11 2024 +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>