Mercurial > repos > imgteam > overlay_images
view overlay_images.py @ 4:61009b4361c1 draft default tip
planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/overlay_images/ commit a11042fbd0da4bfcc54522b31919aa5efb862f3d
| author | imgteam |
|---|---|
| date | Fri, 28 Nov 2025 08:40:45 +0000 |
| parents | eb173a1fabc4 |
| children |
line wrap: on
line source
""" 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 giatools.io 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): img = giatools.io.imread(fn) nDims = len(img.shape) assert nDims in [2, 3], 'this tool only supports single 2D images' if nDims == 3 and img.shape[-1] in [3, 4]: img = skimage.color.rgb2gray(img) if len(img.shape) == 3: return img[:, :, 0] else: return img def get_rgb8_copy(img, fp_lower, fp_upper): img = np.squeeze(img) assert img.ndim == 2 or (img.ndim == 3 and img.shape[-1] in (3, 4)) assert fp_lower == 'min' or abs(float(fp_lower)) < np.inf # 'min' or number assert fp_upper == 'max' or abs(float(fp_upper)) < np.inf # 'max' or number # Convert from floating point if str(img.dtype).startswith('float'): a = img.min() if fp_lower == 'min' else float(fp_lower) b = img.max() if fp_upper == 'max' else float(fp_upper) if a > b: raise ValueError( f'Lower bound ({a:g}) must be less than upper bound ({b:g}).' ) if a == b: raise ValueError( 'Floating point conversion is undefined' ' because lower and upper bounds are identical.' ) # Perform linear mapping to [0, 1] img = img.clip(a, b) img = (img - a) / (b - a) # Convert to uint8 img = np.round(img * 255).astype(np.uint8) # Convert from uint16 elif img.dtype == np.uint16: img = (img // 256).astype(np.uint8) # Other dtypes than float, uint8, uint16 are not supported elif img.dtype != np.uint8: raise ValueError(f'unknown dtype: {img.dtype}') if img.ndim == 2: result = np.dstack([img] * 3).copy() else: result = img[:, :, :3].copy() assert result.dtype == np.uint8, result.dtype return result 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) assert im1.shape == im2.shape, 'Two images should have the same dimension' vmin = np.min([np.min(im1), np.min(im2)]) scal = 255.0 / (np.max([np.max(im1), np.max(im2)]) - vmin) out_im = np.zeros(im1.shape + (3,), dtype=np.ubyte) out_im[:, :, 0] = (im1 - vmin) * scal out_im[:, :, 1] = (im2 - vmin) * scal skimage.io.imsave(out_fn, out_im) # output is RGB def blending(im1_fn, im2_fn, out_fn, alpha=0.5): im1 = giatools.io.imread(im1_fn) im2 = giatools.io.imread(im2_fn) assert im1.shape == im2.shape, 'Two images should have the same dimension' out_im = (1 - alpha) * im1 + alpha * im2 if len(im1.shape) > 3: tifffile.imwrite(out_fn, out_im.astype(im1.dtype), imagej=True) else: 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, fp_lower, fp_upper, linewidth, color='#ff0000', show_label=False, label_color='#ffff00'): img = giatools.io.imread(im1_fn) labels = giatools.io.imread(im2_fn) result = get_rgb8_copy(img, fp_lower, fp_upper) cp = ContourPaint(labels, linewidth, where='center') color_rgb = np.multiply(255, matplotlib.colors.to_rgb(color)) 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: 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) else: skimage.io.imsave(out_fn, result) # format of output is RGB8 if __name__ == "__main__": parser = argparse.ArgumentParser(description="Overlay two images") parser.add_argument("im1", help="The first image") parser.add_argument("im2", help="The second image") parser.add_argument("out", help="Output image") parser.add_argument('--method', dest='method', default='coloc_vis', help='How to overlay images') parser.add_argument('--fp_lower', default='0', type=str, help='Lower bound for floating point conversion') parser.add_argument('--fp_upper', default='1', type=str, help='Upper bound for floating point conversion') parser.add_argument('--alpha', dest='alpha', default=0.5, type=float, help='Blending weight') 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': coloc_vis(args.im1, args.im2, args.out) elif args.method == 'blending': blending(args.im1, args.im2, args.out, alpha=args.alpha) elif args.method == 'seg_contour': seg_contour( args.im1, args.im2, args.out, fp_lower=args.fp_lower, fp_upper=args.fp_upper, linewidth=args.thickness, color=args.color, show_label=args.show_label, label_color=args.label_color, )
