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