comparison filter.py @ 2:b2d9c92bc431 draft

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/2d_simple_filter/ commit a6fd77be465068f709a71d377900da99becf94d8
author imgteam
date Fri, 12 Dec 2025 21:18:04 +0000
parents
children 5ab62693dca5
comparison
equal deleted inserted replaced
1:e2542d0ac64f 2:b2d9c92bc431
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 scipy.ndimage as ndi
11 from skimage.morphology import disk
12
13
14 def image_astype(img: giatools.Image, dtype: np.dtype) -> giatools.Image:
15 return giatools.Image(
16 data=img.data.astype(dtype),
17 axes=img.axes,
18 original_axes=img.original_axes,
19 metadata=img.metadata,
20 )
21
22
23 filters = {
24 'gaussian': lambda img, sigma, order=0, axis=None: (
25 apply_2d_filter(
26 ndi.gaussian_filter,
27 img if order == 0 else image_astype(img, float),
28 sigma=sigma,
29 order=order,
30 axes=axis,
31 )
32 ),
33 'uniform': lambda img, size: (
34 apply_2d_filter(ndi.uniform_filter, img, size=size)
35 ),
36 'median': lambda img, radius: (
37 apply_2d_filter(ndi.median_filter, img, footprint=disk(radius))
38 ),
39 'prewitt': lambda img, axis: (
40 apply_2d_filter(ndi.prewitt, img, axis=axis)
41 ),
42 'sobel': lambda img, axis: (
43 apply_2d_filter(ndi.sobel, img, axis=axis)
44 ),
45 }
46
47
48 def apply_2d_filter(
49 filter_impl: Callable[[np.ndarray, Any, ...], np.ndarray],
50 img: giatools.Image,
51 **kwargs: Any,
52 ) -> giatools.Image:
53 """
54 Apply the 2-D filter to the 2-D/3-D, potentially multi-frame and multi-channel image.
55 """
56 result_data = None
57 for qtzc in np.ndindex(
58 img.data.shape[ 0], # Q axis
59 img.data.shape[ 1], # T axis
60 img.data.shape[ 2], # Z axis
61 img.data.shape[-1], # C axis
62 ):
63 sl = np.s_[*qtzc[:3], ..., qtzc[3]] # noqa: E999
64 arr = img.data[sl]
65 assert arr.ndim == 2 # sanity check, should always be True
66
67 # Perform 2-D filtering
68 res = filter_impl(arr, **kwargs)
69 if result_data is None:
70 result_data = np.empty(img.data.shape, res.dtype)
71 result_data[sl] = res
72
73 # Return results
74 return giatools.Image(result_data, img.axes)
75
76
77 def apply_filter(
78 input_filepath: str,
79 output_filepath: str,
80 filter_type: str,
81 **kwargs: Any,
82 ):
83 # Read the input image
84 img = giatools.Image.read(input_filepath)
85
86 # Perform filtering
87 filter_impl = filters[filter_type]
88 res = filter_impl(img, **kwargs).normalize_axes_like(img.original_axes)
89
90 # Adopt metadata and write the result
91 res.metadata = img.metadata
92 res.write(output_filepath, backend='tifffile')
93
94
95 if __name__ == "__main__":
96 parser = argparse.ArgumentParser()
97 parser.add_argument('input', type=str, help='Input image filepath')
98 parser.add_argument('output', type=str, help='Output image filepath (TIFF)')
99 parser.add_argument('params', type=str)
100 args = parser.parse_args()
101
102 # Read the config file
103 with open(args.params) as cfgf:
104 cfg = json.load(cfgf)
105
106 apply_filter(
107 args.input,
108 args.output,
109 **cfg,
110 )