comparison binary2label.py @ 6:364e235bf378 draft default tip

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/binary2labelimage/ commit f5a4de7535e433e3b0e96e0694e481b6643a54f8
author imgteam
date Sat, 03 Jan 2026 14:14:28 +0000
parents 7f8102bdbfa1
children
comparison
equal deleted inserted replaced
5:7f8102bdbfa1 6:364e235bf378
1 import argparse 1 import giatools
2 import numpy as np
3 import scipy.ndimage as ndi
2 4
3 import giatools 5 # Fail early if an optional backend is not available
4 import scipy.ndimage as ndi 6 giatools.require_backend('omezarr')
5 import tifffile
6 7
7 8
8 # Parse CLI parameters 9 def label_watershed(arr: np.ndarray, **kwargs) -> np.ndarray:
9 parser = argparse.ArgumentParser() 10 import skimage.util
10 parser.add_argument('input', type=str, help='input file') 11 from skimage.feature import peak_local_max
11 parser.add_argument('output', type=str, help='output file (TIFF)') 12 from skimage.segmentation import watershed
12 args = parser.parse_args() 13 distance = ndi.distance_transform_edt(arr)
14 local_max_indices = peak_local_max(
15 distance,
16 labels=arr,
17 **kwargs,
18 )
19 local_max_mask = np.zeros(arr.shape, dtype=bool)
20 local_max_mask[tuple(local_max_indices.T)] = True
21 markers = ndi.label(local_max_mask)[0]
22 res = watershed(-distance, markers, mask=arr)
23 return skimage.util.img_as_uint(res) # converts to uint16
13 24
14 # Read the input image with the original axes
15 img = giatools.Image.read(args.input)
16 img = img.normalize_axes_like(
17 img.original_axes,
18 )
19 25
20 # Make sure the image is truly binary 26 if __name__ == '__main__':
21 img_arr_bin = (img.data > 0)
22 27
23 # Perform the labeling 28 tool = giatools.ToolBaseplate()
24 img.data = ndi.label(img_arr_bin)[0] 29 tool.add_input_image('input')
30 tool.add_output_image('output')
31 tool.parse_args()
25 32
26 # Write the result image (same axes as input image) 33 # Validate the input image and the selected method
27 tifffile.imwrite(args.output, img.data, metadata=dict(axes=img.axes)) 34 try:
35 input_image = tool.args.input_images['input']
36 if (method := tool.args.params.pop('method')) == 'watershed' and input_image.shape[input_image.axes.index('Z')] > 1:
37 raise ValueError(f'Method "{method}" is not applicable to 3-D images.')
38
39 elif input_image.shape[input_image.axes.index('C')] > 1:
40 raise ValueError('Multi-channel images are forbidden to avoid confusion with multi-channel labels (e.g., RGB labels).')
41
42 else:
43
44 # Choose the requested labeling method
45 match method:
46
47 case 'cca':
48 joint_axes = 'ZYX'
49 label = lambda input_section_bin: ( # noqa: E731
50 ndi.label(input_section_bin, **tool.args.params)[0].astype(np.uint16)
51 )
52
53 case 'watershed':
54 joint_axes = 'YX'
55 label = lambda input_section_bin: ( # noqa: E731
56 label_watershed(input_section_bin, **tool.args.params) # already uint16
57 )
58
59 case _:
60 raise ValueError(f'Unknown method: "{method}"')
61
62 # Perform the labeling
63 for section in tool.run(joint_axes):
64 section['output'] = label(
65 section['input'].data > 0, # ensure that the input data is truly binary
66 )
67
68 # Exit and print error to stderr
69 except ValueError as err:
70 exit(err.args[0])