comparison morphological_operations.py @ 0:f10112b317a1 draft

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/morphological_operations commit c6d2a4fb19b54c804029ae3d52eb9fb2619e4265
author imgteam
date Fri, 08 Mar 2024 11:00:41 +0000
parents
children 4e25befab102
comparison
equal deleted inserted replaced
-1:000000000000 0:f10112b317a1
1 import argparse
2
3 import numpy as np
4 import scipy.ndimage as ndi
5 import skimage.io
6 import skimage.morphology as morph
7
8
9 def create_selem(args):
10 """
11 Creates structuring element based on commandline arguments.
12 """
13 assert args.selem_shape in (
14 'square',
15 'disk',
16 )
17
18 if args.selem_shape == 'square':
19 return np.ones((args.selem_size, args.selem_size))
20
21 elif args.selem_shape == 'disk':
22 return morph.disk(args.selem_size)
23
24
25 def apply_operation(args, im):
26 """
27 Applies morphological operation to a 2-D single-channel image.
28 """
29 assert im.ndim == 2
30 selem = create_selem(args)
31 values_count = len(np.unique(im))
32 if values_count <= 2:
33 im_proxy = np.zeros(im.shape, bool)
34 im_proxy[im == im.max()] = True
35 result_proxy = apply_binary_operation(args, im_proxy, selem)
36 result = np.full(im.shape, im.min(), im.dtype)
37 result[result_proxy] = im.max()
38 return result
39 else:
40 return apply_intensity_based_operation(args, im, selem)
41
42
43 def apply_intensity_based_operation(args, im, selem):
44 operations = {
45 'erosion': ndi.grey_erosion,
46 'dilation': ndi.grey_dilation,
47 'opening': ndi.grey_opening,
48 'closing': ndi.grey_closing,
49 }
50 if args.operation in operations:
51 operation = operations[args.operation]
52 return operation(input=im, structure=selem)
53 else:
54 raise ValueError(f'Operation "{args.operation}" not supported for this image type ({im.dtype}).')
55
56
57 def apply_binary_operation(args, im, selem):
58 operations = {
59 'erosion': ndi.binary_erosion,
60 'dilation': ndi.binary_dilation,
61 'opening': ndi.binary_opening,
62 'closing': ndi.binary_closing,
63 'fill_holes': ndi.binary_fill_holes,
64 }
65 operation = operations[args.operation]
66 return operation(input=im, structure=selem)
67
68
69 if __name__ == '__main__':
70
71 parser = argparse.ArgumentParser()
72 parser.add_argument('--operation', type=str)
73 parser.add_argument('--selem-shape', type=str)
74 parser.add_argument('--selem-size', type=int)
75 parser.add_argument('input', type=str)
76 parser.add_argument('output', type=str)
77 args = parser.parse_args()
78
79 im = skimage.io.imread(args.input)
80 assert im.ndim in (2, 3), 'Input image must be two-dimensional and either single-channel or multi-channel.'
81
82 if im.ndim == 2:
83 im_result = apply_operation(args, im)
84
85 else:
86 ch_result_list = []
87 for ch_idx in range(im.shape[2]):
88 ch = im[:, :, ch_idx]
89 ch_result = apply_operation(args, ch)
90 ch_result_list.append(ch_result)
91 im_result = np.dstack(ch_result_list)
92
93 skimage.io.imsave(args.output, im_result)