Previous changeset 1:bf590a9733ed (2022-07-19) Next changeset 3:22ff7c705a83 (2023-11-08) |
Commit message:
planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/overlay_images/ commit 71dae1df58f579b84d4f9d92fb0dd509c02dd48f |
modified:
overlay_images.py overlay_images.xml test-data/test3.tif |
added:
contours.py test-data/mask2.tif test-data/test4.tif |
b |
diff -r bf590a9733ed -r b74693340624 contours.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contours.py Thu Aug 10 07:29:34 2023 +0000 |
b |
@@ -0,0 +1,49 @@ +""" +Copyright (c) 2017-2023 Leonid Kostrykin, Biomedical Computer Vision Group, Heidelberg University. + +Distributed under the MIT license. +See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +""" + +import numpy as np +import skimage.morphology as morph + + +class ContourPaint: + """Yields masks corresponding to contours of objects. + + :param fg_mask: Binary mask of the image foreground. Any contour never overlaps the image foreground except of those image regions corresponding to the contoured object itself. + :param thickness: The thickness of the contour (width, in pixels). + :param where: The position of the contour (``inner``, ``center``, or ``outer``). + """ + + def __init__(self, fg_mask, thickness, where='center'): + assert where in ('inner', 'center', 'outer') + self.fg_mask = fg_mask + self.where = where + self.thickness = thickness + if where == 'inner': + self.selem_inner = morph.disk(self.thickness) + self.selem_outer = None + elif where == 'center': + self.selem_inner = morph.disk(self.thickness - self.thickness // 2) + self.selem_outer = morph.disk(self.thickness // 2) + elif where == 'outer': + self.selem_inner = None + self.selem_outer = morph.disk(self.thickness) + + def get_contour_mask(self, mask): + """Returns the binary mask of the contour of an object. + + :param mask: Binary mask of an object. + :return: Binary mask of the contour + """ + if self.selem_inner is not None: + inner_contour = np.logical_xor(mask, morph.binary_erosion(mask, self.selem_inner)) + else: + inner_contour = np.zeros(mask.shape, bool) + if self.selem_outer is not None: + outer_contour = np.logical_and(np.logical_not(self.fg_mask), morph.binary_dilation(mask, self.selem_outer)) + else: + outer_contour = np.zeros(mask.shape, bool) + return np.logical_or(inner_contour, outer_contour) |
b |
diff -r bf590a9733ed -r b74693340624 overlay_images.py --- a/overlay_images.py Tue Jul 19 08:52:04 2022 +0000 +++ b/overlay_images.py Thu Aug 10 07:29:34 2023 +0000 |
[ |
@@ -1,19 +1,20 @@ """ -Copyright 2022 Biomedical Computer Vision Group, Heidelberg University. +Copyright 2022-2023 Biomedical Computer Vision Group, Heidelberg University. Distributed under the MIT license. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT - """ import argparse +import matplotlib.colors import matplotlib.pyplot as plt import numpy as np import skimage.color import skimage.io import skimage.measure import tifffile +from contours import ContourPaint def read_im_gray(fn): @@ -28,6 +29,21 @@ return img +def get_rgb8_copy(img): + img = np.squeeze(img) + assert img.ndim == 2 or (img.ndim == 3 and img.shape[-1] in (3, 4)) + if str(img.dtype).startswith('float'): + img = np.round(img * 255).astype('uint8') + elif img.dtype == 'uint16': + img = img // 256 + elif img.dtype != 'uint8': + raise ValueError(f'unknown dtype: {img.dtype}') + if img.ndim == 2: + return np.dstack([img] * 3).copy() + else: + return img[:, :, :3].copy() + + def coloc_vis(in_red_fn, in_green_fn, out_fn): im1 = read_im_gray(in_red_fn) im2 = read_im_gray(in_green_fn) @@ -53,23 +69,32 @@ skimage.io.imsave(out_fn, out_im.astype(im1.dtype)) # format of output is the same as input -def seg_contour(im1_fn, im2_fn, out_fn, linewidth=0.3, color='#ff0000', show_label=False): +def seg_contour(im1_fn, im2_fn, out_fn, linewidth, color='#ff0000', show_label=False, label_color='#ffff00'): img = skimage.io.imread(im1_fn) - label = skimage.io.imread(im2_fn) + labels = skimage.io.imread(im2_fn) + + result = get_rgb8_copy(img) + cp = ContourPaint(labels, linewidth, where='center') + color_rgb = np.multiply(255, matplotlib.colors.to_rgb(color)) - fig = plt.figure() - ax = fig.add_axes([0, 0, 1, 1]) - ax.axis('off') + for label in np.unique(labels): + if label > 0: + cc = (labels == label) + bd = cp.get_contour_mask(cc) + for i in range(3): + result[:, :, i][bd] = color_rgb[i] + if show_label: - for reg in skimage.measure.regionprops(label): - ax.text(reg.centroid[1], reg.centroid[0], str(reg.label), color=color) + fig = plt.figure(figsize=np.divide(img.shape[:2][::-1], 100), dpi=100) + ax = fig.add_axes([0, 0, 1, 1]) + ax.axis('off') + ax.imshow(result) + for reg in skimage.measure.regionprops(labels): + ax.text(reg.centroid[1], reg.centroid[0], str(reg.label), color=label_color) + fig.canvas.print_png(out_fn) - if len(img.shape) == 2: - plt.imshow(img, cmap=plt.cm.gray) else: - plt.imshow(img) - plt.contour(label, linewidths=linewidth, colors=color) - fig.canvas.print_png(out_fn) # output is RGB + skimage.io.imsave(out_fn, result) # format of output is RGB8 if __name__ == "__main__": @@ -79,9 +104,10 @@ parser.add_argument("out", help="Output image") parser.add_argument('--method', dest='method', default='coloc_vis', help='How to overlay images') parser.add_argument('--alpha', dest='alpha', default=0.5, type=float, help='Blending weight') - parser.add_argument('--thickness', dest='thickness', default=0.3, type=float, help='Contour thickness') - parser.add_argument('--color', dest='color', default='#FFFF00', help='Contour color') - parser.add_argument('--show_label', dest='show_label', action='store_true', help='Plot label') + parser.add_argument('--thickness', dest='thickness', default=2, type=int, help='Contour thickness') + parser.add_argument('--color', dest='color', default='#FF0000', help='Contour color') + parser.add_argument('--show_label', dest='show_label', action='store_true', help='Show labels') + parser.add_argument('--label_color', dest='label_color', default='#FFFF00', help='Label color') args = parser.parse_args() if args.method == 'coloc_vis': @@ -92,4 +118,5 @@ seg_contour(args.im1, args.im2, args.out, linewidth=args.thickness, color=args.color, - show_label=args.show_label) + show_label=args.show_label, + label_color=args.label_color) |
b |
diff -r bf590a9733ed -r b74693340624 overlay_images.xml --- a/overlay_images.xml Tue Jul 19 08:52:04 2022 +0000 +++ b/overlay_images.xml Thu Aug 10 07:29:34 2023 +0000 |
b |
@@ -1,4 +1,4 @@ -<tool id="ip_overlay_images" name="Overlay Images" version="0.0.2" profile="20.05"> +<tool id="ip_overlay_images" name="Overlay Images" version="0.0.3" profile="20.05"> <description>for visualization</description> <requirements> <requirement type="package" version="0.18.1">scikit-image</requirement> @@ -15,8 +15,9 @@ --alpha $method_option.alpha #elif $method_option.method == "seg_contour" --thickness $method_option.thickness - --color '$method_option.colour' + --color '$method_option.color' $method_option.show_label + --label_color '$method_option.label_color' #end if ]]> </command> @@ -39,9 +40,10 @@ <when value="seg_contour"> <param name="im1" type="data" format="tiff,png" label="Image" /> <param name="im2" type="data" format="tiff,png" label="Label image" /> - <param name="thickness" type="float" value="0.3" label="Contour thickness" /> - <param name="colour" type="color" value="#ff0000" label="Contour color"/> + <param name="thickness" type="integer" value="2" min="1" label="Contour thickness (in pixels)" /> + <param name="color" type="color" value="#ff0000" label="Contour color"/> <param argument="--show_label" type="boolean" checked='false' truevalue="--show_label" falsevalue="" label="Show labels" /> + <param name="label_color" type="color" value="#ffff00" label="Label color"/> </when> </conditional> </inputs> @@ -66,10 +68,18 @@ <param name="im1" value="sample1.tif"/> <param name="im2" value="mask1.tif"/> <param name="method" value="seg_contour"/> - <param name="thickness" value="0.4"/> - <param name="colour" value="#ffaa00"/> + <param name="thickness" value="2"/> + <param name="color" value="#ff0000"/> <param name="show_label" value="--show_label"/> - <output name="out" value="test3.tif" ftype="tiff" compare="sim_size" delta="20000" delta_frac="0.2"/> + <output name="out" value="test3.tif" ftype="tiff" compare="sim_size" delta_frac="0.1"/> + </test> + <test> + <param name="im1" value="sample1.tif"/> + <param name="im2" value="mask2.tif"/> + <param name="method" value="seg_contour"/> + <param name="thickness" value="2"/> + <param name="color" value="#ff0000"/> + <output name="out" value="test4.tif" ftype="tiff" compare="sim_size" delta_frac="0.1"/> </test> </tests> <help> @@ -78,5 +88,6 @@ This tool overlays two image to visualize 1) image blending, 2) colocalization, or 3) a segmentation mask over an image. </help> <citations> + <citation type="doi">10.1016/j.jbiotec.2017.07.019</citation> </citations> </tool> |
b |
diff -r bf590a9733ed -r b74693340624 test-data/mask2.tif |
b |
Binary file test-data/mask2.tif has changed |
b |
diff -r bf590a9733ed -r b74693340624 test-data/test3.tif |
b |
Binary file test-data/test3.tif has changed |
b |
diff -r bf590a9733ed -r b74693340624 test-data/test4.tif |
b |
Binary file test-data/test4.tif has changed |