Mercurial > repos > imgteam > morphological_operations
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) |