# HG changeset patch # User imgteam # Date 1765578106 0 # Node ID 0cb07fefbe70492bf6a822f5703783010811f2bb planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/ridge_filter/ commit 85b0f6afacb8933db19e03682559cc4d71031cf1 diff -r 000000000000 -r 0cb07fefbe70 creators.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/creators.xml Fri Dec 12 22:21:46 2025 +0000 @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 000000000000 -r 0cb07fefbe70 filter_skimage.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/filter_skimage.py Fri Dec 12 22:21:46 2025 +0000 @@ -0,0 +1,111 @@ +import argparse +import json +from typing import ( + Any, + Callable, +) + +import giatools +import numpy as np +import skimage.filters + + +filters = { + 'frangi': lambda img, **kwargs: ( + apply_nd_filter(skimage.filters.frangi, img, **kwargs) + ), + 'hessian': lambda img, **kwargs: ( + apply_nd_filter(skimage.filters.hessian, img, **kwargs) + ), + 'laplace': lambda img, **kwargs: ( + apply_nd_filter(skimage.filters.laplace, img, **kwargs) + ), + 'meijering': lambda img, **kwargs: ( + apply_nd_filter(skimage.filters.meijering, img, **kwargs) + ), + 'sato': lambda img, **kwargs: ( + apply_nd_filter(skimage.filters.sato, img, **kwargs) + ), +} + + +def apply_nd_filter( + filter_impl: Callable[[np.ndarray, Any, ...], np.ndarray], + img: giatools.Image, + dtype: str, + **kwargs: Any, +) -> giatools.Image: + """ + Apply the filter to the 2-D/3-D, potentially multi-frame and multi-channel image. + """ + result_data = np.empty(img.data.shape, dtype=dtype) + for qtc in np.ndindex( + img.data.shape[ 0], # Q axis + img.data.shape[ 1], # T axis + img.data.shape[-1], # C axis + ): + sl = np.s_[*qtc[:2], ..., qtc[2]] # noqa: E999 + arr = img.data[sl] + assert arr.ndim == 3 # sanity check, should always be True + + # Perform 2-D or 3-D filtering + if arr.shape[0] == 1: + info = 'Performing 2-D filtering' + result_data[sl][0] = filter_impl(arr[0], **kwargs).astype(dtype) + else: + info = 'Performing 3-D filtering' + result_data[sl] = filter_impl(arr, **kwargs).astype(dtype) + + # Print status info + print(info) + + # Return results as 16bit, 32bit, or 64bit floating point + return giatools.Image(result_data.astype(dtype), img.axes) + + +def apply_filter( + input_filepath: str, + output_filepath: str, + filter_type: str, + **kwargs: Any, +): + # Validate and transform input parameters + params = dict(kwargs) + if (sigma_min := params.pop('sigma_min', None)) is not None and (sigma_max := params.pop('sigma_max', None)) is not None: + num_sigma = params.pop('num_sigma') + if sigma_min < sigma_max: + params['sigmas'] = np.linspace(sigma_min, sigma_max, num_sigma) + elif sigma_min == sigma_max: + params['sigmas'] = [sigma_min] + else: + raise ValueError(f'Minimum sigma ({sigma_min:g}) must not be greater than Maximum sigma ({sigma_max:g})') + + # Read the input image + img = giatools.Image.read(input_filepath) + + # Perform filtering + print(f'Applying filter: "{filter_type}"') + filter_impl = filters[filter_type] + res = filter_impl(img, **params).normalize_axes_like(img.original_axes) + + # Adopt metadata and write the result + res.metadata = img.metadata + res.write(output_filepath, backend='tifffile') + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('input', type=str) + parser.add_argument('output', type=str) + parser.add_argument('params', type=str) + args = parser.parse_args() + + # Read the config file + with open(args.params) as cfgf: + cfg = json.load(cfgf) + + apply_filter( + args.input, + args.output, + **cfg, + ) diff -r 000000000000 -r 0cb07fefbe70 skimage.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skimage.xml Fri Dec 12 22:21:46 2025 +0000 @@ -0,0 +1,270 @@ + + with scikit-image + + creators.xml + tests.xml + 0.22.0 + 1 + + + + + + + + + + + + + + + + + + + + + operation_3443 + + + galaxy_image_analysis + scikit-image + scikit-image + + + scikit-image + giatools + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +**Applies a ridge filter to an image.** + +Ridge filters can be used to detect ridge-like structures, such as neurites, tubes, vessels, wrinkles, or rivers. Different +ridge filters may be suited for detecting different structures, e.g., depending on contrast or noise level. 2-D and 3-D +images are supported. For multi-channel images, the filter is applied to all channels of the image. For time-series images, +the filter is also applied for all time steps. + +Frangi vesselness filter +======================== + +Filter an image with the Frangi vesselness filter. This filter can be used to detect continuous ridges, e.g. vessels, +wrinkles, rivers. It can be used to calculate the fraction of the whole image containing such objects. Calculates the +eigenvalues of the Hessian to compute the similarity of an image region to vessels, according to the method described in +Frangi et al. (1998). + +Hybrid Hessian filter +===================== + +Filter an image with the Hybrid Hessian filter (Schrijver 2001, Kroon 2009). This filter can be used to detect continuous +edges, e.g. vessels, wrinkles, rivers. It can be used to calculate the fraction of the whole image containing such objects. +Almost equal to Frangi filter, but uses alternative method of smoothing. + +Laplace filter +============== + +Find the edges of an image using the Laplace operator. + +Meijering neuriteness filter +============================ + +Filter an image with the Meijering neuriteness filter. This filter can be used to detect continuous ridges, e.g. neurites, +wrinkles, rivers. It can be used to calculate the fraction of the whole image containing such objects. Calculates the +eigenvalues of the Hessian to compute the similarity of an image region to neurites, according to the method described in +Meijering et al. (2004). + +Sato tubeness filter +==================== + +Filter an image with the Sato tubeness filter. This filter can be used to detect continuous ridges, e.g. tubes, wrinkles, +rivers. It can be used to calculate the fraction of the whole image containing such objects. Calculates the eigenvalues of +the Hessian to compute the similarity of an image region to tubes, according to the method described in Sato et al. (1998). + + + + 10.1007/BFb0056195 + 10.1002/cyto.a.20022 + 10.1016/S1361-8415(98)80009-1 + + diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_0z_0t_0q.tiff Binary file test-data/retina_0c_0z_0t_0q.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_0z_0t_0q_hessian.tiff Binary file test-data/retina_0c_0z_0t_0q_hessian.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_0z_0t_2q.tiff Binary file test-data/retina_0c_0z_0t_2q.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_0z_0t_2q_sato.tiff Binary file test-data/retina_0c_0z_0t_2q_sato.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_0z_3t_0q.tiff Binary file test-data/retina_0c_0z_3t_0q.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_0z_3t_0q_meijering.tiff Binary file test-data/retina_0c_0z_3t_0q_meijering.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_5z_0t_0q.tiff Binary file test-data/retina_0c_5z_0t_0q.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_0c_5z_0t_0q_laplace.tiff Binary file test-data/retina_0c_5z_0t_0q_laplace.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_frangi.tiff Binary file test-data/retina_frangi.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_inv_0c_0z_0t_0q.tiff Binary file test-data/retina_inv_0c_0z_0t_0q.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/retina_inv_0c_0z_0t_0q_frangi.tiff Binary file test-data/retina_inv_0c_0z_0t_0q_frangi.tiff has changed diff -r 000000000000 -r 0cb07fefbe70 test-data/scikit-image/LICENSE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/scikit-image/LICENSE.txt Fri Dec 12 22:21:46 2025 +0000 @@ -0,0 +1,28 @@ +Files: * +Copyright: 2009-2022 the scikit-image team +License: BSD-3-Clause + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -r 000000000000 -r 0cb07fefbe70 test-data/scikit-image/retina.png Binary file test-data/scikit-image/retina.png has changed diff -r 000000000000 -r 0cb07fefbe70 tests.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests.xml Fri Dec 12 22:21:46 2025 +0000 @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +