Mercurial > repos > imgteam > colorize_labels
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>
--- /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>