summaryrefslogtreecommitdiff
path: root/silx/math/medianfilter
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@debian.org>2022-02-02 14:19:58 +0100
committerPicca Frédéric-Emmanuel <picca@debian.org>2022-02-02 14:19:58 +0100
commit4e774db12d5ebe7a20eded6dd434a289e27999e5 (patch)
treea9822974ba45196f1e3740995ab157d6eb214a04 /silx/math/medianfilter
parentd3194b1a9c4404ba93afac43d97172ab24c57098 (diff)
New upstream version 1.0.0+dfsg
Diffstat (limited to 'silx/math/medianfilter')
-rw-r--r--silx/math/medianfilter/__init__.py30
-rw-r--r--silx/math/medianfilter/include/median_filter.hpp284
-rw-r--r--silx/math/medianfilter/median_filter.pxd42
-rw-r--r--silx/math/medianfilter/medianfilter.pyx496
-rw-r--r--silx/math/medianfilter/setup.py59
-rw-r--r--silx/math/medianfilter/test/__init__.py36
-rw-r--r--silx/math/medianfilter/test/benchmark.py122
-rw-r--r--silx/math/medianfilter/test/test_medianfilter.py740
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')