diff options
author | Picca Frédéric-Emmanuel <picca@debian.org> | 2022-02-02 14:19:58 +0100 |
---|---|---|
committer | Picca Frédéric-Emmanuel <picca@debian.org> | 2022-02-02 14:19:58 +0100 |
commit | 4e774db12d5ebe7a20eded6dd434a289e27999e5 (patch) | |
tree | a9822974ba45196f1e3740995ab157d6eb214a04 /silx/math/medianfilter | |
parent | d3194b1a9c4404ba93afac43d97172ab24c57098 (diff) |
New upstream version 1.0.0+dfsg
Diffstat (limited to 'silx/math/medianfilter')
-rw-r--r-- | silx/math/medianfilter/__init__.py | 30 | ||||
-rw-r--r-- | silx/math/medianfilter/include/median_filter.hpp | 284 | ||||
-rw-r--r-- | silx/math/medianfilter/median_filter.pxd | 42 | ||||
-rw-r--r-- | silx/math/medianfilter/medianfilter.pyx | 496 | ||||
-rw-r--r-- | silx/math/medianfilter/setup.py | 59 | ||||
-rw-r--r-- | silx/math/medianfilter/test/__init__.py | 36 | ||||
-rw-r--r-- | silx/math/medianfilter/test/benchmark.py | 122 | ||||
-rw-r--r-- | silx/math/medianfilter/test/test_medianfilter.py | 740 |
8 files changed, 0 insertions, 1809 deletions
diff --git a/silx/math/medianfilter/__init__.py b/silx/math/medianfilter/__init__.py deleted file mode 100644 index 2b05f06..0000000 --- a/silx/math/medianfilter/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# Copyright (C) 2016 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ############################################################################*/ - -__authors__ = ["H. Payno"] -__license__ = "MIT" -__date__ = "02/05/2017" - - -from .medianfilter import (medfilt, medfilt1d, medfilt2d) diff --git a/silx/math/medianfilter/include/median_filter.hpp b/silx/math/medianfilter/include/median_filter.hpp deleted file mode 100644 index 7e42980..0000000 --- a/silx/math/medianfilter/include/median_filter.hpp +++ /dev/null @@ -1,284 +0,0 @@ -/*########################################################################## -# -# Copyright (c) 2017-2019 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ###########################################################################*/ -// __authors__ = ["H. Payno"] -// __license__ = "MIT" -// __date__ = "10/02/2017" - -#ifndef MEDIAN_FILTER -#define MEDIAN_FILTER - -#include <vector> -#include <assert.h> -#include <algorithm> -#include <signal.h> -#include <iostream> -#include <cmath> -#include <cfloat> - -/* Needed for pytohn2.7 on Windows... */ -#ifndef INFINITY -#define INFINITY (DBL_MAX+DBL_MAX) -#endif - -#ifndef NAN -#define NAN (INFINITY-INFINITY) -#endif - -// Modes for the median filter -enum MODE{ - NEAREST=0, - REFLECT=1, - MIRROR=2, - SHRINK=3, - CONSTANT=4, -}; - -// Simple function browsing a deque and registering the min and max values -// and if those values are unique or not -template<typename T> -void getMinMax(std::vector<T>& v, T& min, T&max, - typename std::vector<T>::const_iterator end){ - // init min and max values - typename std::vector<T>::const_iterator it = v.begin(); - if (v.size() == 0){ - raise(SIGINT); - }else{ - min = max = *it; - } - it++; - - // Browse all the deque - while(it!=end){ - // check if repeated (should always be before min/max setting) - T value = *it; - if(value > max) max = value; - if(value < min) min = value; - - it++; - } -} - - -// apply the median filter only on limited part of the vector -// In case of even number of elements (either due to NaNs in the window -// or for image borders in shrink mode): -// the highest of the 2 central values is returned -template<typename T> -inline T median(std::vector<T>& v, int window_size) { - int pivot = window_size / 2; - std::nth_element(v.begin(), v.begin() + pivot, v.begin()+window_size); - return v[pivot]; -} - - -// return the index into 0, (length_max - 1) in reflect mode -inline int reflect(int index, int length_max){ - int res = index; - // if the index is negative get the positive symmetrical value - if(res < 0){ - res += 1; - res = -res; - } - // then apply the reflect algorithm. Frequency is 2 max length - res = res % (2*length_max); - if(res >= length_max){ - res = 2*length_max - res -1; - res = res % length_max; - } - return res; -} - -// return the index into 0, (length_max - 1) in mirror mode -inline int mirror(int index, int length_max){ - int res = index; - // if the index is negative get the positive symmetrical value - if(res < 0){ - res = -res; - } - int rightLimit = length_max -1; - // apply the redundancy each two right limit - res = res % (2*rightLimit); - if(res >= length_max){ - int distToRedundancy = (2*rightLimit) - res; - res = distToRedundancy; - } - return res; -} - -/* Provide a way to access NaN that also works for integers*/ - -template<typename T> -inline T NotANumber(void) { - assert(false); //This should never be called - return 0; -} - -template<> -inline float NotANumber<float>(void) { return NAN; } - -template<> -inline double NotANumber<double>(void) { return NAN; } - - -// Browse the column of pixel_x -template<typename T> -void median_filter( - const T* input, - T* output, - int* kernel_dim, // two values : 0:width, 1:height - int* image_dim, // two values : 0:width, 1:height - int y_pixel, // the x pixel to process - int x_pixel_range_min, - int x_pixel_range_max, - bool conditional, - int pMode, - T cval) { - - assert(kernel_dim[0] > 0); - assert(kernel_dim[1] > 0); - assert(y_pixel >= 0); - assert(image_dim[0] > 0); - assert(image_dim[1] > 0); - assert(y_pixel >= 0); - assert(y_pixel < image_dim[0]); - assert(x_pixel_range_max < image_dim[1]); - assert(x_pixel_range_min <= x_pixel_range_max); - // kernel odd assertion - assert((kernel_dim[0] - 1)%2 == 0); - assert((kernel_dim[1] - 1)%2 == 0); - - // # this should be move up to avoid calculation each time - int halfKernel_x = (kernel_dim[1] - 1) / 2; - int halfKernel_y = (kernel_dim[0] - 1) / 2; - - MODE mode = static_cast<MODE>(pMode); - - // init buffer - std::vector<T> window_values(kernel_dim[0]*kernel_dim[1]); - - bool not_horizontal_border = (y_pixel >= halfKernel_y && y_pixel < image_dim[0] - halfKernel_y); - - for(int x_pixel=x_pixel_range_min; x_pixel <= x_pixel_range_max; x_pixel ++ ){ - typename std::vector<T>::iterator it = window_values.begin(); - // fill the vector - - if (not_horizontal_border && - x_pixel >= halfKernel_x && x_pixel < image_dim[1] - halfKernel_x) { - //This is not a border, just fill it - for(int win_y=y_pixel-halfKernel_y; win_y<= y_pixel+halfKernel_y; win_y++) { - for(int win_x = x_pixel-halfKernel_x; win_x <= x_pixel+halfKernel_x; win_x++){ - T value = input[win_y*image_dim[1] + win_x]; - if (value == value) { // Ignore NaNs - *it = value; - ++it; - } - } - } - - } else { // This is a border, handle the special case - for(int win_y=y_pixel-halfKernel_y; win_y<= y_pixel+halfKernel_y; win_y++) - { - for(int win_x = x_pixel-halfKernel_x; win_x <= x_pixel+halfKernel_x; win_x++) - { - T value = 0; - int index_x = win_x; - int index_y = win_y; - - switch(mode){ - case NEAREST: - index_x = std::min(std::max(win_x, 0), image_dim[1] - 1); - index_y = std::min(std::max(win_y, 0), image_dim[0] - 1); - value = input[index_y*image_dim[1] + index_x]; - break; - - case REFLECT: - index_x = reflect(win_x, image_dim[1]); - index_y = reflect(win_y, image_dim[0]); - value = input[index_y*image_dim[1] + index_x]; - break; - - case MIRROR: - index_x = mirror(win_x, image_dim[1]); - // deal with 1d case - if(win_y == 0 && image_dim[0] == 1){ - index_y = 0; - }else{ - index_y = mirror(win_y, image_dim[0]); - } - value = input[index_y*image_dim[1] + index_x]; - break; - - case SHRINK: - if ((index_x < 0) || (index_x > image_dim[1] -1) || - (index_y < 0) || (index_y > image_dim[0] -1)) { - continue; - } - value = input[index_y*image_dim[1] + index_x]; - break; - case CONSTANT: - if ((index_x < 0) || (index_x > image_dim[1] -1) || - (index_y < 0) || (index_y > image_dim[0] -1)) { - value = cval; - } else { - value = input[index_y*image_dim[1] + index_x]; - } - break; - } - - if (value == value) { // Ignore NaNs - *it = value; - ++it; - } - } - } - } - - //window_size can be smaller than kernel size in shrink mode or if there is NaNs - int window_size = std::distance(window_values.begin(), it); - - if (window_size == 0) { - // Window is empty, this is the case when all values are NaNs - output[image_dim[1]*y_pixel + x_pixel] = NotANumber<T>(); - } else { - // apply the median value if needed for this pixel - const T currentPixelValue = input[image_dim[1]*y_pixel + x_pixel]; - if (conditional == true){ - typename std::vector<T>::iterator window_end = window_values.begin() + window_size; - T min = 0; - T max = 0; - getMinMax(window_values, min, max, window_end); - // NaNs are propagated through unchanged - if ((currentPixelValue == max) || (currentPixelValue == min)){ - output[image_dim[1]*y_pixel + x_pixel] = median<T>(window_values, window_size); - }else{ - output[image_dim[1]*y_pixel + x_pixel] = currentPixelValue; - } - }else{ - output[image_dim[1]*y_pixel + x_pixel] = median<T>(window_values, window_size); - } - } - } -} - -#endif // MEDIAN_FILTER diff --git a/silx/math/medianfilter/median_filter.pxd b/silx/math/medianfilter/median_filter.pxd deleted file mode 100644 index 2fc0283..0000000 --- a/silx/math/medianfilter/median_filter.pxd +++ /dev/null @@ -1,42 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2015-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ###########################################################################*/ - -from libcpp cimport bool - -# pyx -cdef extern from "median_filter.hpp": - cdef extern void median_filter[T](const T* image, - T* output, - int* kernel_dim, - int* image_dim, - int x_pixel_range_min, - int x_pixel_range_max, - int y_pixel_range_min, - int y_pixel_range_max, - bool conditional, - T cval) nogil; - - cdef extern int reflect(int index, int length_max); - cdef extern int mirror(int index, int length_max); diff --git a/silx/math/medianfilter/medianfilter.pyx b/silx/math/medianfilter/medianfilter.pyx deleted file mode 100644 index fe05a78..0000000 --- a/silx/math/medianfilter/medianfilter.pyx +++ /dev/null @@ -1,496 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2015-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ###########################################################################*/ -"""This module provides median filter function for 1D and 2D arrays. -""" - -__authors__ = ["H. Payno", "J. Kieffer"] -__license__ = "MIT" -__date__ = "02/05/2017" - - -from cython.parallel import prange -cimport cython -cimport silx.math.medianfilter.median_filter as median_filter -import numpy -cimport numpy as cnumpy -from libcpp cimport bool - -import numbers - -ctypedef unsigned long uint64 -ctypedef unsigned int uint32 -ctypedef unsigned short uint16 - - -MODES = {'nearest': 0, 'reflect': 1, 'mirror': 2, 'shrink': 3, 'constant': 4} - - -def medfilt1d(data, - kernel_size=3, - bool conditional=False, - mode='nearest', - cval=0): - """Function computing the median filter of the given input. - - Behavior at boundaries: the algorithm is reducing the size of the - window/kernel for pixels at boundaries (there is no mirroring). - - Not-a-Number (NaN) float values are ignored. - If the window only contains NaNs, it evaluates to NaN. - - In event of an even number of valid values in the window (either - because of NaN values or on image border in shrink mode), - the highest of the 2 central sorted values is taken. - - :param numpy.ndarray data: the array for which we want to apply - the median filter. Should be 1d. - :param kernel_size: the dimension of the kernel. - :type kernel_size: int - :param bool conditional: True if we want to apply a conditional median - filtering. - :param str mode: the algorithm used to determine how values at borders - are determined: 'nearest', 'reflect', 'mirror', 'shrink', 'constant' - :param cval: Value used outside borders in 'constant' mode - - :returns: the array with the median value for each pixel. - """ - return medfilt(data, kernel_size, conditional, mode, cval) - - -def medfilt2d(image, - kernel_size=3, - bool conditional=False, - mode='nearest', - cval=0): - """Function computing the median filter of the given input. - Behavior at boundaries: the algorithm is reducing the size of the - window/kernel for pixels at boundaries (there is no mirroring). - - Not-a-Number (NaN) float values are ignored. - If the window only contains NaNs, it evaluates to NaN. - - In event of an even number of valid values in the window (either - because of NaN values or on image border in shrink mode), - the highest of the 2 central sorted values is taken. - - :param numpy.ndarray data: the array for which we want to apply - the median filter. Should be 2d. - :param kernel_size: the dimension of the kernel. - :type kernel_size: For 1D should be an int for 2D should be a tuple or - a list of (kernel_height, kernel_width) - :param bool conditional: True if we want to apply a conditional median - filtering. - :param str mode: the algorithm used to determine how values at borders - are determined: 'nearest', 'reflect', 'mirror', 'shrink', 'constant' - :param cval: Value used outside borders in 'constant' mode - - :returns: the array with the median value for each pixel. - """ - return medfilt(image, kernel_size, conditional, mode, cval) - - -def medfilt(data, - kernel_size=3, - bool conditional=False, - mode='nearest', - cval=0): - """Function computing the median filter of the given input. - Behavior at boundaries: the algorithm is reducing the size of the - window/kernel for pixels at boundaries (there is no mirroring). - - Not-a-Number (NaN) float values are ignored. - If the window only contains NaNs, it evaluates to NaN. - - In event of an even number of valid values in the window (either - because of NaN values or on image border in shrink mode), - the highest of the 2 central sorted values is taken. - - :param numpy.ndarray data: the array for which we want to apply - the median filter. Should be 1d or 2d. - :param kernel_size: the dimension of the kernel. - :type kernel_size: For 1D should be an int for 2D should be a tuple or - a list of (kernel_height, kernel_width) - :param bool conditional: True if we want to apply a conditional median - filtering. - :param str mode: the algorithm used to determine how values at borders - are determined: 'nearest', 'reflect', 'mirror', 'shrink', 'constant' - :param cval: Value used outside borders in 'constant' mode - - :returns: the array with the median value for each pixel. - """ - if mode not in MODES: - err = 'Requested mode %s is unknown.' % mode - raise ValueError(err) - - if data.ndim > 2: - raise ValueError( - "Invalid data shape. Dimension of the array should be 1 or 2") - - # Handle case of scalar kernel size - if isinstance(kernel_size, numbers.Integral): - kernel_size = [kernel_size] * data.ndim - - assert len(kernel_size) == data.ndim - - # Convert 1D arrays to 2D - reshaped = False - if len(data.shape) == 1: - data = data.reshape(1, data.shape[0]) - kernel_size = [1, kernel_size[0]] - reshaped = True - - # simple median filter apply into a 2D buffer - output_buffer = numpy.zeros_like(data) - check(data, output_buffer) - - ker_dim = numpy.array(kernel_size, dtype=numpy.int32) - - if data.dtype == numpy.float64: - medfilterfc = _median_filter_float64 - elif data.dtype == numpy.float32: - medfilterfc = _median_filter_float32 - elif data.dtype == numpy.int64: - medfilterfc = _median_filter_int64 - elif data.dtype == numpy.uint64: - medfilterfc = _median_filter_uint64 - elif data.dtype == numpy.int32: - medfilterfc = _median_filter_int32 - elif data.dtype == numpy.uint32: - medfilterfc = _median_filter_uint32 - elif data.dtype == numpy.int16: - medfilterfc = _median_filter_int16 - elif data.dtype == numpy.uint16: - medfilterfc = _median_filter_uint16 - else: - raise ValueError("%s type is not managed by the median filter" % data.dtype) - - medfilterfc(input_buffer=data, - output_buffer=output_buffer, - kernel_size=ker_dim, - conditional=conditional, - mode=MODES[mode], - cval=cval) - - if reshaped: - output_buffer.shape = -1 # Convert to 1D array - - return output_buffer - - -def check(input_buffer, output_buffer): - """Simple check on the two buffers to make sure we can apply the median filter - """ - if (input_buffer.flags['C_CONTIGUOUS'] is False): - raise ValueError('<input_buffer> must be a C_CONTIGUOUS numpy array.') - - if (output_buffer.flags['C_CONTIGUOUS'] is False): - raise ValueError('<output_buffer> must be a C_CONTIGUOUS numpy array.') - - if not (len(input_buffer.shape) <= 2): - raise ValueError('<input_buffer> dimension must mo higher than 2.') - - if not (len(output_buffer.shape) <= 2): - raise ValueError('<output_buffer> dimension must mo higher than 2.') - - if not(input_buffer.dtype == output_buffer.dtype): - raise ValueError('input buffer and output_buffer must be of the same type') - - if not (input_buffer.shape == output_buffer.shape): - raise ValueError('input buffer and output_buffer must be of the same dimension and same dimension') - - -######### implementations of the include/median_filter.hpp function ############ -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def reflect(int index, int length_max): - """find the correct index into [0, length_max-1] for index in reflect mode - - :param int index: the index to move into [0, length_max-1] in reflect mode - :param int length_max: the higher bound limit - """ - return median_filter.reflect(index, length_max) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def mirror(int index, int length_max): - """find the correct index into [0, length_max-1] for index in mirror mode - - :param int index: the index to move into [0, length_max-1] in mirror mode - :param int length_max: the higher bound limit - """ - return median_filter.mirror(index, length_max) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_float32(float[:, ::1] input_buffer not None, - float[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - float cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[float](<float*> & input_buffer[0,0], - <float*> & output_buffer[0,0], - <int*>& kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_float64(double[:, ::1] input_buffer not None, - double[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - double cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[double](<double*> & input_buffer[0, 0], - <double*> & output_buffer[0, 0], - <int*>&kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_int64(cnumpy.int64_t[:, ::1] input_buffer not None, - cnumpy.int64_t[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - cnumpy.int64_t cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[long](<long*> & input_buffer[0,0], - <long*> & output_buffer[0, 0], - <int*>&kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_uint64(cnumpy.uint64_t[:, ::1] input_buffer not None, - cnumpy.uint64_t[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - cnumpy.uint64_t cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[uint64](<uint64*> & input_buffer[0,0], - <uint64*> & output_buffer[0, 0], - <int*>&kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_int32(cnumpy.int32_t[:, ::1] input_buffer not None, - cnumpy.int32_t[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - cnumpy.int32_t cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[int](<int*> & input_buffer[0,0], - <int*> & output_buffer[0, 0], - <int*>&kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_uint32(cnumpy.uint32_t[:, ::1] input_buffer not None, - cnumpy.uint32_t[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - cnumpy.uint32_t cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[uint32](<uint32*> & input_buffer[0,0], - <uint32*> & output_buffer[0, 0], - <int*>&kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_int16(cnumpy.int16_t[:, ::1] input_buffer not None, - cnumpy.int16_t[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - cnumpy.int16_t cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[short](<short*> & input_buffer[0,0], - <short*> & output_buffer[0, 0], - <int*>&kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.initializedcheck(False) -def _median_filter_uint16( - cnumpy.uint16_t[:, ::1] input_buffer not None, - cnumpy.uint16_t[:, ::1] output_buffer not None, - cnumpy.int32_t[::1] kernel_size not None, - bool conditional, - int mode, - cnumpy.uint16_t cval): - - cdef: - int y = 0 - int image_dim = input_buffer.shape[1] - 1 - int[2] buffer_shape, - buffer_shape[0] = input_buffer.shape[0] - buffer_shape[1] = input_buffer.shape[1] - - for y in prange(input_buffer.shape[0], nogil=True): - median_filter.median_filter[uint16](<uint16*> & input_buffer[0, 0], - <uint16*> & output_buffer[0, 0], - <int*>&kernel_size[0], - <int*>buffer_shape, - y, - 0, - image_dim, - conditional, - mode, - cval) diff --git a/silx/math/medianfilter/setup.py b/silx/math/medianfilter/setup.py deleted file mode 100644 index d228357..0000000 --- a/silx/math/medianfilter/setup.py +++ /dev/null @@ -1,59 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# Copyright (C) 2016-2017 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ############################################################################*/ - -__authors__ = ["D. Naudet"] -__license__ = "MIT" -__date__ = "02/05/2017" - - -import numpy - -from numpy.distutils.misc_util import Configuration - - -def configuration(parent_package='', top_path=None): - config = Configuration('medianfilter', parent_package, top_path) - config.add_subpackage('test') - - # ===================================== - # median filter - # ===================================== - medfilt_src = ['medianfilter.pyx'] - medfilt_inc = ['include', numpy.get_include()] - extra_link_args = ['-fopenmp'] - extra_compile_args = ['-fopenmp'] - config.add_extension('medianfilter', - sources=medfilt_src, - include_dirs=[medfilt_inc], - language='c++', - extra_link_args=extra_link_args, - extra_compile_args=extra_compile_args) - - return config - - -if __name__ == "__main__": - from numpy.distutils.core import setup - - setup(configuration=configuration)
\ No newline at end of file diff --git a/silx/math/medianfilter/test/__init__.py b/silx/math/medianfilter/test/__init__.py deleted file mode 100644 index 92a6524..0000000 --- a/silx/math/medianfilter/test/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# Copyright (C) 2016-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ############################################################################*/ -__authors__ = ["H. Payno"] -__license__ = "MIT" -__date__ = "22/06/2016" - -import unittest - -from . import test_medianfilter - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest(test_medianfilter.suite()) - return test_suite diff --git a/silx/math/medianfilter/test/benchmark.py b/silx/math/medianfilter/test/benchmark.py deleted file mode 100644 index cbb16b3..0000000 --- a/silx/math/medianfilter/test/benchmark.py +++ /dev/null @@ -1,122 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# Copyright (C) 2017-2019 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ############################################################################*/ -"""Tests of the median filter""" - -__authors__ = ["H. Payno"] -__license__ = "MIT" -__date__ = "02/05/2017" - -from silx.gui import qt -from silx.math.medianfilter import medfilt2d as medfilt2d_silx -import numpy -import numpy.random -from timeit import Timer -from silx.gui.plot import Plot1D -import logging - -try: - import scipy -except: - scipy = None -else: - import scipy.ndimage - -try: - import PyMca5.PyMca as pymca -except: - pymca = None -else: - from PyMca5.PyMca.median import medfilt2d as medfilt2d_pymca - -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - - -class BenchmarkMedianFilter(object): - """Simple benchmark of the median fiter silx vs scipy""" - - NB_ITER = 3 - - def __init__(self, imageWidth, kernels): - self.img = numpy.random.rand(imageWidth, imageWidth) - self.kernels = kernels - - self.run() - - def run(self): - self.execTime = {} - for kernel in self.kernels: - self.execTime[kernel] = self.bench(kernel) - - def bench(self, width): - def execSilx(): - medfilt2d_silx(self.img, width) - - def execScipy(): - scipy.ndimage.median_filter(input=self.img, - size=width, - mode='nearest') - - def execPymca(): - medfilt2d_pymca(self.img, width) - - execTime = {} - - t = Timer(execSilx) - execTime["silx"] = t.timeit(BenchmarkMedianFilter.NB_ITER) - logger.info( - 'exec time silx (kernel size = %s) is %s' % (width, execTime["silx"])) - - if scipy is not None: - t = Timer(execScipy) - execTime["scipy"] = t.timeit(BenchmarkMedianFilter.NB_ITER) - logger.info( - 'exec time scipy (kernel size = %s) is %s' % (width, execTime["scipy"])) - if pymca is not None: - t = Timer(execPymca) - execTime["pymca"] = t.timeit(BenchmarkMedianFilter.NB_ITER) - logger.info( - 'exec time pymca (kernel size = %s) is %s' % (width, execTime["pymca"])) - - return execTime - - def getExecTimeFor(self, id): - res = [] - for k in self.kernels: - res.append(self.execTime[k][id]) - return res - - -app = qt.QApplication([]) -kernels = [3, 5, 7, 11, 15] -benchmark = BenchmarkMedianFilter(imageWidth=1000, kernels=kernels) -plot = Plot1D() -plot.addCurve(x=kernels, y=benchmark.getExecTimeFor("silx"), legend='silx') -if scipy is not None: - plot.addCurve(x=kernels, y=benchmark.getExecTimeFor("scipy"), legend='scipy') -if pymca is not None: - plot.addCurve(x=kernels, y=benchmark.getExecTimeFor("pymca"), legend='pymca') -plot.show() -app.exec_() -del app diff --git a/silx/math/medianfilter/test/test_medianfilter.py b/silx/math/medianfilter/test/test_medianfilter.py deleted file mode 100644 index 3a45b3d..0000000 --- a/silx/math/medianfilter/test/test_medianfilter.py +++ /dev/null @@ -1,740 +0,0 @@ -# coding: utf-8 -# ########################################################################## -# Copyright (C) 2017-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ############################################################################ -"""Tests of the median filter""" - -__authors__ = ["H. Payno"] -__license__ = "MIT" -__date__ = "17/01/2018" - -import unittest -import numpy -from silx.math.medianfilter import medfilt2d, medfilt1d -from silx.math.medianfilter.medianfilter import reflect, mirror -from silx.math.medianfilter.medianfilter import MODES as silx_mf_modes -from silx.utils.testutils import ParametricTestCase -try: - import scipy - import scipy.misc -except: - scipy = None -else: - import scipy.ndimage - -import logging -_logger = logging.getLogger(__name__) - -RANDOM_FLOAT_MAT = numpy.array([ - [0.05564293, 0.62717157, 0.75002406, 0.40555336, 0.70278975], - [0.76532598, 0.02839148, 0.05272484, 0.65166994, 0.42161216], - [0.23067427, 0.74219128, 0.56049024, 0.44406320, 0.28773158], - [0.81025249, 0.20303021, 0.68382382, 0.46372299, 0.81281709], - [0.94691602, 0.07813661, 0.81651256, 0.84220106, 0.33623165]]) - -RANDOM_INT_MAT = numpy.array([ - [0, 5, 2, 6, 1], - [2, 3, 1, 7, 1], - [9, 8, 6, 7, 8], - [5, 6, 8, 2, 4]]) - - -class TestMedianFilterNearest(ParametricTestCase): - """Unit tests for the median filter in nearest mode""" - - def testFilter3_100(self): - """Test median filter on a 10x10 matrix with a 3x3 kernel.""" - dataIn = numpy.arange(100, dtype=numpy.int32) - dataIn = dataIn.reshape((10, 10)) - - dataOut = medfilt2d(image=dataIn, - kernel_size=(3, 3), - conditional=False, - mode='nearest') - self.assertTrue(dataOut[0, 0] == 1) - self.assertTrue(dataOut[9, 0] == 90) - self.assertTrue(dataOut[9, 9] == 98) - - self.assertTrue(dataOut[0, 9] == 9) - self.assertTrue(dataOut[0, 4] == 5) - self.assertTrue(dataOut[9, 4] == 93) - self.assertTrue(dataOut[4, 4] == 44) - - def testFilter3_9(self): - "Test median filter on a 3x3 matrix with a 3x3 kernel." - dataIn = numpy.array([0, -1, 1, - 12, 6, -2, - 100, 4, 12], - dtype=numpy.int16) - dataIn = dataIn.reshape((3, 3)) - dataOut = medfilt2d(image=dataIn, - kernel_size=(3, 3), - conditional=False, - mode='nearest') - self.assertTrue(dataOut.shape == dataIn.shape) - self.assertTrue(dataOut[1, 1] == 4) - self.assertTrue(dataOut[0, 0] == 0) - self.assertTrue(dataOut[0, 1] == 0) - self.assertTrue(dataOut[1, 0] == 6) - - def testFilterWidthOne(self): - """Make sure a filter of one by one give the same result as the input - """ - dataIn = numpy.arange(100, dtype=numpy.int32) - dataIn = dataIn.reshape((10, 10)) - - dataOut = medfilt2d(image=dataIn, - kernel_size=(1, 1), - conditional=False, - mode='nearest') - - self.assertTrue(numpy.array_equal(dataIn, dataOut)) - - def testFilter3_1d(self): - """Test binding and result of the 1d filter""" - self.assertTrue(numpy.array_equal( - medfilt1d(RANDOM_INT_MAT[0], kernel_size=3, conditional=False, - mode='nearest'), - [0, 2, 5, 2, 1]) - ) - - def testFilter3Conditionnal(self): - """Test that the conditional filter apply correctly in a 10x10 matrix - with a 3x3 kernel - """ - dataIn = numpy.arange(100, dtype=numpy.int32) - dataIn = dataIn.reshape((10, 10)) - - dataOut = medfilt2d(image=dataIn, - kernel_size=(3, 3), - conditional=True, - mode='nearest') - self.assertTrue(dataOut[0, 0] == 1) - self.assertTrue(dataOut[0, 1] == 1) - self.assertTrue(numpy.array_equal(dataOut[1:8, 1:8], dataIn[1:8, 1:8])) - self.assertTrue(dataOut[9, 9] == 98) - - def testFilter3_1D(self): - """Simple test of a 3x3 median filter on a 1D array""" - dataIn = numpy.arange(100, dtype=numpy.int32) - - dataOut = medfilt2d(image=dataIn, - kernel_size=(5), - conditional=False, - mode='nearest') - - self.assertTrue(dataOut[0] == 0) - self.assertTrue(dataOut[9] == 9) - self.assertTrue(dataOut[99] == 99) - - def testNaNs(self): - """Test median filter on image with NaNs in nearest mode""" - # Data with a NaN in first corner - nan_corner = numpy.arange(100.).reshape(10, 10) - nan_corner[0, 0] = numpy.nan - output = medfilt2d( - nan_corner, kernel_size=3, conditional=False, mode='nearest') - self.assertEqual(output[0, 0], 10) - self.assertEqual(output[0, 1], 2) - self.assertEqual(output[1, 0], 11) - self.assertEqual(output[1, 1], 12) - - # Data with some NaNs - some_nans = numpy.arange(100.).reshape(10, 10) - some_nans[0, 1] = numpy.nan - some_nans[1, 1] = numpy.nan - some_nans[1, 0] = numpy.nan - output = medfilt2d( - some_nans, kernel_size=3, conditional=False, mode='nearest') - self.assertEqual(output[0, 0], 0) - self.assertEqual(output[0, 1], 2) - self.assertEqual(output[1, 0], 20) - self.assertEqual(output[1, 1], 20) - - -class TestMedianFilterReflect(ParametricTestCase): - """Unit test for the median filter in reflect mode""" - - def testArange9(self): - """Test from a 3x3 window to RANDOM_FLOAT_MAT""" - img = numpy.arange(9, dtype=numpy.int32) - img = img.reshape(3, 3) - kernel = (3, 3) - res = medfilt2d(image=img, - kernel_size=kernel, - conditional=False, - mode='reflect') - self.assertTrue( - numpy.array_equal(res.ravel(), [1, 2, 2, 3, 4, 5, 6, 6, 7])) - - def testRandom10(self): - """Test a (5, 3) window to a RANDOM_FLOAT_MAT""" - kernel = (5, 3) - - thRes = numpy.array([ - [0.23067427, 0.56049024, 0.56049024, 0.4440632, 0.42161216], - [0.23067427, 0.62717157, 0.56049024, 0.56049024, 0.46372299], - [0.62717157, 0.62717157, 0.56049024, 0.56049024, 0.4440632], - [0.76532598, 0.68382382, 0.56049024, 0.56049024, 0.42161216], - [0.81025249, 0.68382382, 0.56049024, 0.68382382, 0.46372299]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=False, - mode='reflect') - - self.assertTrue(numpy.array_equal(thRes, res)) - - def testApplyReflect1D(self): - """Test the reflect function used for the median filter in reflect mode - """ - # test for inside values - self.assertTrue(reflect(2, 3) == 2) - # test for boundaries values - self.assertTrue(reflect(3, 3) == 2) - self.assertTrue(reflect(4, 3) == 1) - self.assertTrue(reflect(5, 3) == 0) - self.assertTrue(reflect(6, 3) == 0) - self.assertTrue(reflect(7, 3) == 1) - self.assertTrue(reflect(-1, 3) == 0) - self.assertTrue(reflect(-2, 3) == 1) - self.assertTrue(reflect(-3, 3) == 2) - self.assertTrue(reflect(-4, 3) == 2) - self.assertTrue(reflect(-5, 3) == 1) - self.assertTrue(reflect(-6, 3) == 0) - self.assertTrue(reflect(-7, 3) == 0) - - def testRandom10Conditionnal(self): - """Test the median filter in reflect mode and with the conditionnal - option""" - kernel = (3, 1) - - thRes = numpy.array([ - [0.05564293, 0.62717157, 0.75002406, 0.40555336, 0.70278975], - [0.23067427, 0.62717157, 0.56049024, 0.44406320, 0.42161216], - [0.76532598, 0.20303021, 0.56049024, 0.46372299, 0.42161216], - [0.81025249, 0.20303021, 0.68382382, 0.46372299, 0.33623165], - [0.94691602, 0.07813661, 0.81651256, 0.84220106, 0.33623165]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=True, - mode='reflect') - self.assertTrue(numpy.array_equal(thRes, res)) - - def testNaNs(self): - """Test median filter on image with NaNs in reflect mode""" - # Data with a NaN in first corner - nan_corner = numpy.arange(100.).reshape(10, 10) - nan_corner[0, 0] = numpy.nan - output = medfilt2d( - nan_corner, kernel_size=3, conditional=False, mode='reflect') - self.assertEqual(output[0, 0], 10) - self.assertEqual(output[0, 1], 2) - self.assertEqual(output[1, 0], 11) - self.assertEqual(output[1, 1], 12) - - # Data with some NaNs - some_nans = numpy.arange(100.).reshape(10, 10) - some_nans[0, 1] = numpy.nan - some_nans[1, 1] = numpy.nan - some_nans[1, 0] = numpy.nan - output = medfilt2d( - some_nans, kernel_size=3, conditional=False, mode='reflect') - self.assertEqual(output[0, 0], 0) - self.assertEqual(output[0, 1], 2) - self.assertEqual(output[1, 0], 20) - self.assertEqual(output[1, 1], 20) - - def testFilter3_1d(self): - """Test binding and result of the 1d filter""" - self.assertTrue(numpy.array_equal( - medfilt1d(RANDOM_INT_MAT[0], kernel_size=5, conditional=False, - mode='reflect'), - [2, 2, 2, 2, 2]) - ) - - -class TestMedianFilterMirror(ParametricTestCase): - """Unit test for the median filter in mirror mode - """ - - def testApplyMirror1D(self): - """Test the reflect function used for the median filter in mirror mode - """ - # test for inside values - self.assertTrue(mirror(2, 3) == 2) - # test for boundaries values - self.assertTrue(mirror(4, 4) == 2) - self.assertTrue(mirror(5, 4) == 1) - self.assertTrue(mirror(6, 4) == 0) - self.assertTrue(mirror(7, 4) == 1) - self.assertTrue(mirror(8, 4) == 2) - self.assertTrue(mirror(-1, 4) == 1) - self.assertTrue(mirror(-2, 4) == 2) - self.assertTrue(mirror(-3, 4) == 3) - self.assertTrue(mirror(-4, 4) == 2) - self.assertTrue(mirror(-5, 4) == 1) - self.assertTrue(mirror(-6, 4) == 0) - - def testRandom10(self): - """Test a (5, 3) window to a random array""" - kernel = (3, 5) - - thRes = numpy.array([ - [0.05272484, 0.40555336, 0.42161216, 0.42161216, 0.42161216], - [0.56049024, 0.56049024, 0.4440632, 0.4440632, 0.4440632], - [0.56049024, 0.46372299, 0.46372299, 0.46372299, 0.46372299], - [0.68382382, 0.56049024, 0.56049024, 0.46372299, 0.56049024], - [0.68382382, 0.46372299, 0.68382382, 0.46372299, 0.68382382]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=False, - mode='mirror') - - self.assertTrue(numpy.array_equal(thRes, res)) - - def testRandom10Conditionnal(self): - """Test the median filter in reflect mode and with the conditionnal - option""" - kernel = (1, 3) - - thRes = numpy.array([ - [0.62717157, 0.62717157, 0.62717157, 0.70278975, 0.40555336], - [0.02839148, 0.05272484, 0.05272484, 0.42161216, 0.65166994], - [0.74219128, 0.56049024, 0.56049024, 0.44406320, 0.44406320], - [0.20303021, 0.68382382, 0.46372299, 0.68382382, 0.46372299], - [0.07813661, 0.81651256, 0.81651256, 0.81651256, 0.84220106]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=True, - mode='mirror') - - self.assertTrue(numpy.array_equal(thRes, res)) - - def testNaNs(self): - """Test median filter on image with NaNs in mirror mode""" - # Data with a NaN in first corner - nan_corner = numpy.arange(100.).reshape(10, 10) - nan_corner[0, 0] = numpy.nan - output = medfilt2d( - nan_corner, kernel_size=3, conditional=False, mode='mirror') - self.assertEqual(output[0, 0], 11) - self.assertEqual(output[0, 1], 11) - self.assertEqual(output[1, 0], 11) - self.assertEqual(output[1, 1], 12) - - # Data with some NaNs - some_nans = numpy.arange(100.).reshape(10, 10) - some_nans[0, 1] = numpy.nan - some_nans[1, 1] = numpy.nan - some_nans[1, 0] = numpy.nan - output = medfilt2d( - some_nans, kernel_size=3, conditional=False, mode='mirror') - self.assertEqual(output[0, 0], 0) - self.assertEqual(output[0, 1], 12) - self.assertEqual(output[1, 0], 21) - self.assertEqual(output[1, 1], 20) - - def testFilter3_1d(self): - """Test binding and result of the 1d filter""" - self.assertTrue(numpy.array_equal( - medfilt1d(RANDOM_INT_MAT[0], kernel_size=5, conditional=False, - mode='mirror'), - [2, 5, 2, 5, 2]) - ) - -class TestMedianFilterShrink(ParametricTestCase): - """Unit test for the median filter in mirror mode - """ - - def testRandom_3x3(self): - """Test the median filter in shrink mode and with the conditionnal - option""" - kernel = (3, 3) - - thRes = numpy.array([ - [0.62717157, 0.62717157, 0.62717157, 0.65166994, 0.65166994], - [0.62717157, 0.56049024, 0.56049024, 0.44406320, 0.44406320], - [0.74219128, 0.56049024, 0.46372299, 0.46372299, 0.46372299], - [0.74219128, 0.68382382, 0.56049024, 0.56049024, 0.46372299], - [0.81025249, 0.81025249, 0.68382382, 0.81281709, 0.81281709]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=False, - mode='shrink') - - self.assertTrue(numpy.array_equal(thRes, res)) - - def testBounds(self): - """Test the median filter in shrink mode with 3 different kernels - which should return the same result due to the large values of kernels - used. - """ - kernel1 = (1, 9) - kernel2 = (1, 11) - kernel3 = (1, 21) - - thRes = numpy.array([[2, 2, 2, 2, 2], - [2, 2, 2, 2, 2], - [8, 8, 8, 8, 8], - [5, 5, 5, 5, 5]]) - - resK1 = medfilt2d(image=RANDOM_INT_MAT, - kernel_size=kernel1, - conditional=False, - mode='shrink') - - resK2 = medfilt2d(image=RANDOM_INT_MAT, - kernel_size=kernel2, - conditional=False, - mode='shrink') - - resK3 = medfilt2d(image=RANDOM_INT_MAT, - kernel_size=kernel3, - conditional=False, - mode='shrink') - - self.assertTrue(numpy.array_equal(resK1, thRes)) - self.assertTrue(numpy.array_equal(resK2, resK1)) - self.assertTrue(numpy.array_equal(resK3, resK1)) - - def testRandom_3x3Conditionnal(self): - """Test the median filter in reflect mode and with the conditionnal - option""" - kernel = (3, 3) - - thRes = numpy.array([ - [0.05564293, 0.62717157, 0.62717157, 0.40555336, 0.65166994], - [0.62717157, 0.56049024, 0.05272484, 0.65166994, 0.42161216], - [0.23067427, 0.74219128, 0.56049024, 0.44406320, 0.46372299], - [0.81025249, 0.20303021, 0.68382382, 0.46372299, 0.81281709], - [0.81025249, 0.81025249, 0.81651256, 0.81281709, 0.81281709]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=True, - mode='shrink') - - self.assertTrue(numpy.array_equal(res, thRes)) - - def testRandomInt(self): - """Test 3x3 kernel on RANDOM_INT_MAT - """ - kernel = (3, 3) - - thRes = numpy.array([[3, 2, 5, 2, 6], - [5, 3, 6, 6, 7], - [6, 6, 6, 6, 7], - [8, 8, 7, 7, 7]]) - - resK1 = medfilt2d(image=RANDOM_INT_MAT, - kernel_size=kernel, - conditional=False, - mode='shrink') - - self.assertTrue(numpy.array_equal(resK1, thRes)) - - def testNaNs(self): - """Test median filter on image with NaNs in shrink mode""" - # Data with a NaN in first corner - nan_corner = numpy.arange(100.).reshape(10, 10) - nan_corner[0, 0] = numpy.nan - output = medfilt2d( - nan_corner, kernel_size=3, conditional=False, mode='shrink') - self.assertEqual(output[0, 0], 10) - self.assertEqual(output[0, 1], 10) - self.assertEqual(output[1, 0], 11) - self.assertEqual(output[1, 1], 12) - - # Data with some NaNs - some_nans = numpy.arange(100.).reshape(10, 10) - some_nans[0, 1] = numpy.nan - some_nans[1, 1] = numpy.nan - some_nans[1, 0] = numpy.nan - output = medfilt2d( - some_nans, kernel_size=3, conditional=False, mode='shrink') - self.assertEqual(output[0, 0], 0) - self.assertEqual(output[0, 1], 2) - self.assertEqual(output[1, 0], 20) - self.assertEqual(output[1, 1], 20) - - def testFilter3_1d(self): - """Test binding and result of the 1d filter""" - self.assertTrue(numpy.array_equal( - medfilt1d(RANDOM_INT_MAT[0], kernel_size=3, conditional=False, - mode='shrink'), - [5, 2, 5, 2, 6]) - ) - -class TestMedianFilterConstant(ParametricTestCase): - """Unit test for the median filter in constant mode - """ - - def testRandom10(self): - """Test a (5, 3) window to a random array""" - kernel = (3, 5) - - thRes = numpy.array([ - [0., 0.02839148, 0.05564293, 0.02839148, 0.], - [0.05272484, 0.40555336, 0.4440632, 0.42161216, 0.28773158], - [0.05272484, 0.44406320, 0.46372299, 0.42161216, 0.28773158], - [0.20303021, 0.46372299, 0.56049024, 0.44406320, 0.33623165], - [0., 0.07813661, 0.33623165, 0.07813661, 0.]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=False, - mode='constant') - - self.assertTrue(numpy.array_equal(thRes, res)) - - RANDOM_FLOAT_MAT = numpy.array([ - [0.05564293, 0.62717157, 0.75002406, 0.40555336, 0.70278975], - [0.76532598, 0.02839148, 0.05272484, 0.65166994, 0.42161216], - [0.23067427, 0.74219128, 0.56049024, 0.44406320, 0.28773158], - [0.81025249, 0.20303021, 0.68382382, 0.46372299, 0.81281709], - [0.94691602, 0.07813661, 0.81651256, 0.84220106, 0.33623165]]) - - def testRandom10Conditionnal(self): - """Test the median filter in reflect mode and with the conditionnal - option""" - kernel = (1, 3) - - print(RANDOM_FLOAT_MAT) - - thRes = numpy.array([ - [0.05564293, 0.62717157, 0.62717157, 0.70278975, 0.40555336], - [0.02839148, 0.05272484, 0.05272484, 0.42161216, 0.42161216], - [0.23067427, 0.56049024, 0.56049024, 0.44406320, 0.28773158], - [0.20303021, 0.68382382, 0.46372299, 0.68382382, 0.46372299], - [0.07813661, 0.81651256, 0.81651256, 0.81651256, 0.33623165]]) - - res = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=True, - mode='constant') - - self.assertTrue(numpy.array_equal(thRes, res)) - - def testNaNs(self): - """Test median filter on image with NaNs in constant mode""" - # Data with a NaN in first corner - nan_corner = numpy.arange(100.).reshape(10, 10) - nan_corner[0, 0] = numpy.nan - output = medfilt2d(nan_corner, - kernel_size=3, - conditional=False, - mode='constant', - cval=0) - self.assertEqual(output[0, 0], 0) - self.assertEqual(output[0, 1], 2) - self.assertEqual(output[1, 0], 10) - self.assertEqual(output[1, 1], 12) - - # Data with some NaNs - some_nans = numpy.arange(100.).reshape(10, 10) - some_nans[0, 1] = numpy.nan - some_nans[1, 1] = numpy.nan - some_nans[1, 0] = numpy.nan - output = medfilt2d(some_nans, - kernel_size=3, - conditional=False, - mode='constant', - cval=0) - self.assertEqual(output[0, 0], 0) - self.assertEqual(output[0, 1], 0) - self.assertEqual(output[1, 0], 0) - self.assertEqual(output[1, 1], 20) - - def testFilter3_1d(self): - """Test binding and result of the 1d filter""" - self.assertTrue(numpy.array_equal( - medfilt1d(RANDOM_INT_MAT[0], kernel_size=5, conditional=False, - mode='constant'), - [0, 2, 2, 2, 1]) - ) - -class TestGeneralExecution(ParametricTestCase): - """Some general test on median filter application""" - - def testTypes(self): - """Test that all needed types have their implementation of the median - filter - """ - for mode in silx_mf_modes: - for testType in [numpy.float32, numpy.float64, numpy.int16, - numpy.uint16, numpy.int32, numpy.int64, - numpy.uint64]: - with self.subTest(mode=mode, type=testType): - data = (numpy.random.rand(10, 10) * 65000).astype(testType) - out = medfilt2d(image=data, - kernel_size=(3, 3), - conditional=False, - mode=mode) - self.assertTrue(out.dtype.type is testType) - - def testInputDataIsNotModify(self): - """Make sure input data is not modify by the median filter""" - dataIn = numpy.arange(100, dtype=numpy.int32) - dataIn = dataIn.reshape((10, 10)) - dataInCopy = dataIn.copy() - - for mode in silx_mf_modes: - with self.subTest(mode=mode): - medfilt2d(image=dataIn, - kernel_size=(3, 3), - conditional=False, - mode=mode) - self.assertTrue(numpy.array_equal(dataIn, dataInCopy)) - - def testAllNaNs(self): - """Test median filter on image all NaNs""" - all_nans = numpy.empty((10, 10), dtype=numpy.float32) - all_nans[:] = numpy.nan - - for mode in silx_mf_modes: - for conditional in (True, False): - with self.subTest(mode=mode, conditional=conditional): - output = medfilt2d( - all_nans, - kernel_size=3, - conditional=conditional, - mode=mode, - cval=numpy.nan) - self.assertTrue(numpy.all(numpy.isnan(output))) - - def testConditionalWithNaNs(self): - """Test that NaNs are propagated through conditional median filter""" - for mode in silx_mf_modes: - with self.subTest(mode=mode): - image = numpy.ones((10, 10), dtype=numpy.float32) - nan_mask = numpy.zeros_like(image, dtype=bool) - nan_mask[0, 0] = True - nan_mask[4, :] = True - nan_mask[6, 4] = True - image[nan_mask] = numpy.nan - output = medfilt2d( - image, - kernel_size=3, - conditional=True, - mode=mode) - out_isnan = numpy.isnan(output) - self.assertTrue(numpy.all(out_isnan[nan_mask])) - self.assertFalse( - numpy.any(out_isnan[numpy.logical_not(nan_mask)])) - - -def _getScipyAndSilxCommonModes(): - """return the mode which are comparable between silx and scipy""" - modes = silx_mf_modes.copy() - del modes['shrink'] - return modes - - -@unittest.skipUnless(scipy is not None, "scipy not available") -class TestVsScipy(ParametricTestCase): - """Compare scipy.ndimage.median_filter vs silx.math.medianfilter - on comparable - """ - def testWithArange(self): - """Test vs scipy with different kernels on arange matrix""" - data = numpy.arange(10000, dtype=numpy.int32) - data = data.reshape(100, 100) - - kernels = [(3, 7), (7, 5), (1, 1), (3, 3)] - modesToTest = _getScipyAndSilxCommonModes() - for kernel in kernels: - for mode in modesToTest: - with self.subTest(kernel=kernel, mode=mode): - resScipy = scipy.ndimage.median_filter(input=data, - size=kernel, - mode=mode) - resSilx = medfilt2d(image=data, - kernel_size=kernel, - conditional=False, - mode=mode) - - self.assertTrue(numpy.array_equal(resScipy, resSilx)) - - def testRandomMatrice(self): - """Test vs scipy with different kernels on RANDOM_FLOAT_MAT""" - kernels = [(3, 7), (7, 5), (1, 1), (3, 3)] - modesToTest = _getScipyAndSilxCommonModes() - for kernel in kernels: - for mode in modesToTest: - with self.subTest(kernel=kernel, mode=mode): - resScipy = scipy.ndimage.median_filter(input=RANDOM_FLOAT_MAT, - size=kernel, - mode=mode) - - resSilx = medfilt2d(image=RANDOM_FLOAT_MAT, - kernel_size=kernel, - conditional=False, - mode=mode) - - self.assertTrue(numpy.array_equal(resScipy, resSilx)) - - def testAscentOrLena(self): - """Test vs scipy with """ - if hasattr(scipy.misc, 'ascent'): - img = scipy.misc.ascent() - else: - img = scipy.misc.lena() - - kernels = [(3, 1), (3, 5), (5, 9), (9, 3)] - modesToTest = _getScipyAndSilxCommonModes() - - for kernel in kernels: - for mode in modesToTest: - with self.subTest(kernel=kernel, mode=mode): - resScipy = scipy.ndimage.median_filter(input=img, - size=kernel, - mode=mode) - - resSilx = medfilt2d(image=img, - kernel_size=kernel, - conditional=False, - mode=mode) - - self.assertTrue(numpy.array_equal(resScipy, resSilx)) - - -def suite(): - test_suite = unittest.TestSuite() - for test in [TestGeneralExecution, - TestVsScipy, - TestMedianFilterNearest, - TestMedianFilterReflect, - TestMedianFilterMirror, - TestMedianFilterShrink, - TestMedianFilterConstant]: - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(test)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') |