comparison filter_skimage.py @ 0:0cb07fefbe70 draft

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/ridge_filter/ commit 85b0f6afacb8933db19e03682559cc4d71031cf1
author imgteam
date Fri, 12 Dec 2025 22:21:46 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0cb07fefbe70
1 import argparse
2 import json
3 from typing import (
4 Any,
5 Callable,
6 )
7
8 import giatools
9 import numpy as np
10 import skimage.filters
11
12
13 filters = {
14 'frangi': lambda img, **kwargs: (
15 apply_nd_filter(skimage.filters.frangi, img, **kwargs)
16 ),
17 'hessian': lambda img, **kwargs: (
18 apply_nd_filter(skimage.filters.hessian, img, **kwargs)
19 ),
20 'laplace': lambda img, **kwargs: (
21 apply_nd_filter(skimage.filters.laplace, img, **kwargs)
22 ),
23 'meijering': lambda img, **kwargs: (
24 apply_nd_filter(skimage.filters.meijering, img, **kwargs)
25 ),
26 'sato': lambda img, **kwargs: (
27 apply_nd_filter(skimage.filters.sato, img, **kwargs)
28 ),
29 }
30
31
32 def apply_nd_filter(
33 filter_impl: Callable[[np.ndarray, Any, ...], np.ndarray],
34 img: giatools.Image,
35 dtype: str,
36 **kwargs: Any,
37 ) -> giatools.Image:
38 """
39 Apply the filter to the 2-D/3-D, potentially multi-frame and multi-channel image.
40 """
41 result_data = np.empty(img.data.shape, dtype=dtype)
42 for qtc in np.ndindex(
43 img.data.shape[ 0], # Q axis
44 img.data.shape[ 1], # T axis
45 img.data.shape[-1], # C axis
46 ):
47 sl = np.s_[*qtc[:2], ..., qtc[2]] # noqa: E999
48 arr = img.data[sl]
49 assert arr.ndim == 3 # sanity check, should always be True
50
51 # Perform 2-D or 3-D filtering
52 if arr.shape[0] == 1:
53 info = 'Performing 2-D filtering'
54 result_data[sl][0] = filter_impl(arr[0], **kwargs).astype(dtype)
55 else:
56 info = 'Performing 3-D filtering'
57 result_data[sl] = filter_impl(arr, **kwargs).astype(dtype)
58
59 # Print status info
60 print(info)
61
62 # Return results as 16bit, 32bit, or 64bit floating point
63 return giatools.Image(result_data.astype(dtype), img.axes)
64
65
66 def apply_filter(
67 input_filepath: str,
68 output_filepath: str,
69 filter_type: str,
70 **kwargs: Any,
71 ):
72 # Validate and transform input parameters
73 params = dict(kwargs)
74 if (sigma_min := params.pop('sigma_min', None)) is not None and (sigma_max := params.pop('sigma_max', None)) is not None:
75 num_sigma = params.pop('num_sigma')
76 if sigma_min < sigma_max:
77 params['sigmas'] = np.linspace(sigma_min, sigma_max, num_sigma)
78 elif sigma_min == sigma_max:
79 params['sigmas'] = [sigma_min]
80 else:
81 raise ValueError(f'Minimum sigma ({sigma_min:g}) must not be greater than Maximum sigma ({sigma_max:g})')
82
83 # Read the input image
84 img = giatools.Image.read(input_filepath)
85
86 # Perform filtering
87 print(f'Applying filter: "{filter_type}"')
88 filter_impl = filters[filter_type]
89 res = filter_impl(img, **params).normalize_axes_like(img.original_axes)
90
91 # Adopt metadata and write the result
92 res.metadata = img.metadata
93 res.write(output_filepath, backend='tifffile')
94
95
96 if __name__ == "__main__":
97 parser = argparse.ArgumentParser()
98 parser.add_argument('input', type=str)
99 parser.add_argument('output', type=str)
100 parser.add_argument('params', type=str)
101 args = parser.parse_args()
102
103 # Read the config file
104 with open(args.params) as cfgf:
105 cfg = json.load(cfgf)
106
107 apply_filter(
108 args.input,
109 args.output,
110 **cfg,
111 )