Skip to content

Commit a6fd77b

Browse files
authored
Merge pull request #170 from kostrykin/dev/simple_filter
Update `ip_filter_standard` tool
2 parents a94f04c + 5ef6711 commit a6fd77b

File tree

9 files changed

+298
-76
lines changed

9 files changed

+298
-76
lines changed

tools/2d_simple_filter/.shed.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
categories:
22
- Imaging
3-
description: 2d simple filter
4-
long_description: Simple filter in 2D
3+
description: 2-D simple filter
4+
long_description: Apply 2-D image filter
55
name: 2d_simple_filter
66
owner: imgteam
77
homepage_url: https://github.com/bmcv

tools/2d_simple_filter/filter.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+
)

0 commit comments

Comments
 (0)