You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
16 KiB
Python
448 lines
16 KiB
Python
''' Some tests for filters '''
|
|
from __future__ import division, print_function, absolute_import
|
|
|
|
import sys
|
|
import numpy as np
|
|
|
|
from numpy.testing import (assert_equal, assert_allclose,
|
|
assert_array_equal, assert_almost_equal)
|
|
from pytest import raises as assert_raises
|
|
|
|
import scipy.ndimage as sndi
|
|
from scipy.ndimage.filters import _gaussian_kernel1d, rank_filter
|
|
from scipy._lib._numpy_compat import suppress_warnings
|
|
|
|
def test_ticket_701():
|
|
# Test generic filter sizes
|
|
arr = np.arange(4).reshape((2,2))
|
|
func = lambda x: np.min(x)
|
|
res = sndi.generic_filter(arr, func, size=(1,1))
|
|
# The following raises an error unless ticket 701 is fixed
|
|
res2 = sndi.generic_filter(arr, func, size=1)
|
|
assert_equal(res, res2)
|
|
|
|
|
|
def test_gh_5430():
|
|
# At least one of these raises an error unless gh-5430 is
|
|
# fixed. In py2k an int is implemented using a C long, so
|
|
# which one fails depends on your system. In py3k there is only
|
|
# one arbitrary precision integer type, so both should fail.
|
|
sigma = np.int32(1)
|
|
out = sndi._ni_support._normalize_sequence(sigma, 1)
|
|
assert_equal(out, [sigma])
|
|
sigma = np.int64(1)
|
|
out = sndi._ni_support._normalize_sequence(sigma, 1)
|
|
assert_equal(out, [sigma])
|
|
# This worked before; make sure it still works
|
|
sigma = 1
|
|
out = sndi._ni_support._normalize_sequence(sigma, 1)
|
|
assert_equal(out, [sigma])
|
|
# This worked before; make sure it still works
|
|
sigma = [1, 1]
|
|
out = sndi._ni_support._normalize_sequence(sigma, 2)
|
|
assert_equal(out, sigma)
|
|
# Also include the OPs original example to make sure we fixed the issue
|
|
x = np.random.normal(size=(256, 256))
|
|
perlin = np.zeros_like(x)
|
|
for i in 2**np.arange(6):
|
|
perlin += sndi.filters.gaussian_filter(x, i, mode="wrap") * i**2
|
|
# This also fixes gh-4106, show that the OPs example now runs.
|
|
x = np.int64(21)
|
|
sndi._ni_support._normalize_sequence(x, 0)
|
|
|
|
|
|
def test_gaussian_kernel1d():
|
|
radius = 10
|
|
sigma = 2
|
|
sigma2 = sigma * sigma
|
|
x = np.arange(-radius, radius + 1, dtype=np.double)
|
|
phi_x = np.exp(-0.5 * x * x / sigma2)
|
|
phi_x /= phi_x.sum()
|
|
assert_allclose(phi_x, _gaussian_kernel1d(sigma, 0, radius))
|
|
assert_allclose(-phi_x * x / sigma2, _gaussian_kernel1d(sigma, 1, radius))
|
|
assert_allclose(phi_x * (x * x / sigma2 - 1) / sigma2,
|
|
_gaussian_kernel1d(sigma, 2, radius))
|
|
assert_allclose(phi_x * (3 - x * x / sigma2) * x / (sigma2 * sigma2),
|
|
_gaussian_kernel1d(sigma, 3, radius))
|
|
|
|
|
|
def test_orders_gauss():
|
|
# Check order inputs to Gaussians
|
|
arr = np.zeros((1,))
|
|
assert_equal(0, sndi.gaussian_filter(arr, 1, order=0))
|
|
assert_equal(0, sndi.gaussian_filter(arr, 1, order=3))
|
|
assert_raises(ValueError, sndi.gaussian_filter, arr, 1, -1)
|
|
assert_equal(0, sndi.gaussian_filter1d(arr, 1, axis=-1, order=0))
|
|
assert_equal(0, sndi.gaussian_filter1d(arr, 1, axis=-1, order=3))
|
|
assert_raises(ValueError, sndi.gaussian_filter1d, arr, 1, -1, -1)
|
|
|
|
|
|
def test_valid_origins():
|
|
"""Regression test for #1311."""
|
|
func = lambda x: np.mean(x)
|
|
data = np.array([1,2,3,4,5], dtype=np.float64)
|
|
assert_raises(ValueError, sndi.generic_filter, data, func, size=3,
|
|
origin=2)
|
|
func2 = lambda x, y: np.mean(x + y)
|
|
assert_raises(ValueError, sndi.generic_filter1d, data, func,
|
|
filter_size=3, origin=2)
|
|
assert_raises(ValueError, sndi.percentile_filter, data, 0.2, size=3,
|
|
origin=2)
|
|
|
|
for filter in [sndi.uniform_filter, sndi.minimum_filter,
|
|
sndi.maximum_filter, sndi.maximum_filter1d,
|
|
sndi.median_filter, sndi.minimum_filter1d]:
|
|
# This should work, since for size == 3, the valid range for origin is
|
|
# -1 to 1.
|
|
list(filter(data, 3, origin=-1))
|
|
list(filter(data, 3, origin=1))
|
|
# Just check this raises an error instead of silently accepting or
|
|
# segfaulting.
|
|
assert_raises(ValueError, filter, data, 3, origin=2)
|
|
|
|
|
|
def test_bad_convolve_and_correlate_origins():
|
|
"""Regression test for gh-822."""
|
|
# Before gh-822 was fixed, these would generate seg. faults or
|
|
# other crashes on many system.
|
|
assert_raises(ValueError, sndi.correlate1d,
|
|
[0, 1, 2, 3, 4, 5], [1, 1, 2, 0], origin=2)
|
|
assert_raises(ValueError, sndi.correlate,
|
|
[0, 1, 2, 3, 4, 5], [0, 1, 2], origin=[2])
|
|
assert_raises(ValueError, sndi.correlate,
|
|
np.ones((3, 5)), np.ones((2, 2)), origin=[0, 1])
|
|
|
|
assert_raises(ValueError, sndi.convolve1d,
|
|
np.arange(10), np.ones(3), origin=-2)
|
|
assert_raises(ValueError, sndi.convolve,
|
|
np.arange(10), np.ones(3), origin=[-2])
|
|
assert_raises(ValueError, sndi.convolve,
|
|
np.ones((3, 5)), np.ones((2, 2)), origin=[0, -2])
|
|
|
|
|
|
def test_multiple_modes():
|
|
# Test that the filters with multiple mode cababilities for different
|
|
# dimensions give the same result as applying a single mode.
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
mode1 = 'reflect'
|
|
mode2 = ['reflect', 'reflect']
|
|
|
|
assert_equal(sndi.gaussian_filter(arr, 1, mode=mode1),
|
|
sndi.gaussian_filter(arr, 1, mode=mode2))
|
|
assert_equal(sndi.prewitt(arr, mode=mode1),
|
|
sndi.prewitt(arr, mode=mode2))
|
|
assert_equal(sndi.sobel(arr, mode=mode1),
|
|
sndi.sobel(arr, mode=mode2))
|
|
assert_equal(sndi.laplace(arr, mode=mode1),
|
|
sndi.laplace(arr, mode=mode2))
|
|
assert_equal(sndi.gaussian_laplace(arr, 1, mode=mode1),
|
|
sndi.gaussian_laplace(arr, 1, mode=mode2))
|
|
assert_equal(sndi.maximum_filter(arr, size=5, mode=mode1),
|
|
sndi.maximum_filter(arr, size=5, mode=mode2))
|
|
assert_equal(sndi.minimum_filter(arr, size=5, mode=mode1),
|
|
sndi.minimum_filter(arr, size=5, mode=mode2))
|
|
assert_equal(sndi.gaussian_gradient_magnitude(arr, 1, mode=mode1),
|
|
sndi.gaussian_gradient_magnitude(arr, 1, mode=mode2))
|
|
assert_equal(sndi.uniform_filter(arr, 5, mode=mode1),
|
|
sndi.uniform_filter(arr, 5, mode=mode2))
|
|
|
|
|
|
def test_multiple_modes_sequentially():
|
|
# Test that the filters with multiple mode cababilities for different
|
|
# dimensions give the same result as applying the filters with
|
|
# different modes sequentially
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
modes = ['reflect', 'wrap']
|
|
|
|
expected = sndi.gaussian_filter1d(arr, 1, axis=0, mode=modes[0])
|
|
expected = sndi.gaussian_filter1d(expected, 1, axis=1, mode=modes[1])
|
|
assert_equal(expected,
|
|
sndi.gaussian_filter(arr, 1, mode=modes))
|
|
|
|
expected = sndi.uniform_filter1d(arr, 5, axis=0, mode=modes[0])
|
|
expected = sndi.uniform_filter1d(expected, 5, axis=1, mode=modes[1])
|
|
assert_equal(expected,
|
|
sndi.uniform_filter(arr, 5, mode=modes))
|
|
|
|
expected = sndi.maximum_filter1d(arr, size=5, axis=0, mode=modes[0])
|
|
expected = sndi.maximum_filter1d(expected, size=5, axis=1, mode=modes[1])
|
|
assert_equal(expected,
|
|
sndi.maximum_filter(arr, size=5, mode=modes))
|
|
|
|
expected = sndi.minimum_filter1d(arr, size=5, axis=0, mode=modes[0])
|
|
expected = sndi.minimum_filter1d(expected, size=5, axis=1, mode=modes[1])
|
|
assert_equal(expected,
|
|
sndi.minimum_filter(arr, size=5, mode=modes))
|
|
|
|
|
|
def test_multiple_modes_prewitt():
|
|
# Test prewitt filter for multiple extrapolation modes
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
expected = np.array([[1., -3., 2.],
|
|
[1., -2., 1.],
|
|
[1., -1., 0.]])
|
|
|
|
modes = ['reflect', 'wrap']
|
|
|
|
assert_equal(expected,
|
|
sndi.prewitt(arr, mode=modes))
|
|
|
|
|
|
def test_multiple_modes_sobel():
|
|
# Test sobel filter for multiple extrapolation modes
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
expected = np.array([[1., -4., 3.],
|
|
[2., -3., 1.],
|
|
[1., -1., 0.]])
|
|
|
|
modes = ['reflect', 'wrap']
|
|
|
|
assert_equal(expected,
|
|
sndi.sobel(arr, mode=modes))
|
|
|
|
|
|
def test_multiple_modes_laplace():
|
|
# Test laplace filter for multiple extrapolation modes
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
expected = np.array([[-2., 2., 1.],
|
|
[-2., -3., 2.],
|
|
[1., 1., 0.]])
|
|
|
|
modes = ['reflect', 'wrap']
|
|
|
|
assert_equal(expected,
|
|
sndi.laplace(arr, mode=modes))
|
|
|
|
|
|
def test_multiple_modes_gaussian_laplace():
|
|
# Test gaussian_laplace filter for multiple extrapolation modes
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
expected = np.array([[-0.28438687, 0.01559809, 0.19773499],
|
|
[-0.36630503, -0.20069774, 0.07483620],
|
|
[0.15849176, 0.18495566, 0.21934094]])
|
|
|
|
modes = ['reflect', 'wrap']
|
|
|
|
assert_almost_equal(expected,
|
|
sndi.gaussian_laplace(arr, 1, mode=modes))
|
|
|
|
|
|
def test_multiple_modes_gaussian_gradient_magnitude():
|
|
# Test gaussian_gradient_magnitude filter for multiple
|
|
# extrapolation modes
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
expected = np.array([[0.04928965, 0.09745625, 0.06405368],
|
|
[0.23056905, 0.14025305, 0.04550846],
|
|
[0.19894369, 0.14950060, 0.06796850]])
|
|
|
|
modes = ['reflect', 'wrap']
|
|
|
|
calculated = sndi.gaussian_gradient_magnitude(arr, 1, mode=modes)
|
|
|
|
assert_almost_equal(expected, calculated)
|
|
|
|
|
|
def test_multiple_modes_uniform():
|
|
# Test uniform filter for multiple extrapolation modes
|
|
arr = np.array([[1., 0., 0.],
|
|
[1., 1., 0.],
|
|
[0., 0., 0.]])
|
|
|
|
expected = np.array([[0.32, 0.40, 0.48],
|
|
[0.20, 0.28, 0.32],
|
|
[0.28, 0.32, 0.40]])
|
|
|
|
modes = ['reflect', 'wrap']
|
|
|
|
assert_almost_equal(expected,
|
|
sndi.uniform_filter(arr, 5, mode=modes))
|
|
|
|
|
|
def test_gaussian_truncate():
|
|
# Test that Gaussian filters can be truncated at different widths.
|
|
# These tests only check that the result has the expected number
|
|
# of nonzero elements.
|
|
arr = np.zeros((100, 100), float)
|
|
arr[50, 50] = 1
|
|
num_nonzeros_2 = (sndi.gaussian_filter(arr, 5, truncate=2) > 0).sum()
|
|
assert_equal(num_nonzeros_2, 21**2)
|
|
num_nonzeros_5 = (sndi.gaussian_filter(arr, 5, truncate=5) > 0).sum()
|
|
assert_equal(num_nonzeros_5, 51**2)
|
|
|
|
# Test truncate when sigma is a sequence.
|
|
f = sndi.gaussian_filter(arr, [0.5, 2.5], truncate=3.5)
|
|
fpos = f > 0
|
|
n0 = fpos.any(axis=0).sum()
|
|
# n0 should be 2*int(2.5*3.5 + 0.5) + 1
|
|
assert_equal(n0, 19)
|
|
n1 = fpos.any(axis=1).sum()
|
|
# n1 should be 2*int(0.5*3.5 + 0.5) + 1
|
|
assert_equal(n1, 5)
|
|
|
|
# Test gaussian_filter1d.
|
|
x = np.zeros(51)
|
|
x[25] = 1
|
|
f = sndi.gaussian_filter1d(x, sigma=2, truncate=3.5)
|
|
n = (f > 0).sum()
|
|
assert_equal(n, 15)
|
|
|
|
# Test gaussian_laplace
|
|
y = sndi.gaussian_laplace(x, sigma=2, truncate=3.5)
|
|
nonzero_indices = np.nonzero(y != 0)[0]
|
|
n = nonzero_indices.ptp() + 1
|
|
assert_equal(n, 15)
|
|
|
|
# Test gaussian_gradient_magnitude
|
|
y = sndi.gaussian_gradient_magnitude(x, sigma=2, truncate=3.5)
|
|
nonzero_indices = np.nonzero(y != 0)[0]
|
|
n = nonzero_indices.ptp() + 1
|
|
assert_equal(n, 15)
|
|
|
|
|
|
class TestThreading(object):
|
|
def check_func_thread(self, n, fun, args, out):
|
|
from threading import Thread
|
|
thrds = [Thread(target=fun, args=args, kwargs={'output': out[x]}) for x in range(n)]
|
|
[t.start() for t in thrds]
|
|
[t.join() for t in thrds]
|
|
|
|
def check_func_serial(self, n, fun, args, out):
|
|
for i in range(n):
|
|
fun(*args, output=out[i])
|
|
|
|
def test_correlate1d(self):
|
|
d = np.random.randn(5000)
|
|
os = np.empty((4, d.size))
|
|
ot = np.empty_like(os)
|
|
self.check_func_serial(4, sndi.correlate1d, (d, np.arange(5)), os)
|
|
self.check_func_thread(4, sndi.correlate1d, (d, np.arange(5)), ot)
|
|
assert_array_equal(os, ot)
|
|
|
|
def test_correlate(self):
|
|
d = np.random.randn(500, 500)
|
|
k = np.random.randn(10, 10)
|
|
os = np.empty([4] + list(d.shape))
|
|
ot = np.empty_like(os)
|
|
self.check_func_serial(4, sndi.correlate, (d, k), os)
|
|
self.check_func_thread(4, sndi.correlate, (d, k), ot)
|
|
assert_array_equal(os, ot)
|
|
|
|
def test_median_filter(self):
|
|
d = np.random.randn(500, 500)
|
|
os = np.empty([4] + list(d.shape))
|
|
ot = np.empty_like(os)
|
|
self.check_func_serial(4, sndi.median_filter, (d, 3), os)
|
|
self.check_func_thread(4, sndi.median_filter, (d, 3), ot)
|
|
assert_array_equal(os, ot)
|
|
|
|
def test_uniform_filter1d(self):
|
|
d = np.random.randn(5000)
|
|
os = np.empty((4, d.size))
|
|
ot = np.empty_like(os)
|
|
self.check_func_serial(4, sndi.uniform_filter1d, (d, 5), os)
|
|
self.check_func_thread(4, sndi.uniform_filter1d, (d, 5), ot)
|
|
assert_array_equal(os, ot)
|
|
|
|
def test_minmax_filter(self):
|
|
d = np.random.randn(500, 500)
|
|
os = np.empty([4] + list(d.shape))
|
|
ot = np.empty_like(os)
|
|
self.check_func_serial(4, sndi.maximum_filter, (d, 3), os)
|
|
self.check_func_thread(4, sndi.maximum_filter, (d, 3), ot)
|
|
assert_array_equal(os, ot)
|
|
self.check_func_serial(4, sndi.minimum_filter, (d, 3), os)
|
|
self.check_func_thread(4, sndi.minimum_filter, (d, 3), ot)
|
|
assert_array_equal(os, ot)
|
|
|
|
|
|
def test_minmaximum_filter1d():
|
|
# Regression gh-3898
|
|
in_ = np.arange(10)
|
|
out = sndi.minimum_filter1d(in_, 1)
|
|
assert_equal(in_, out)
|
|
out = sndi.maximum_filter1d(in_, 1)
|
|
assert_equal(in_, out)
|
|
# Test reflect
|
|
out = sndi.minimum_filter1d(in_, 5, mode='reflect')
|
|
assert_equal([0, 0, 0, 1, 2, 3, 4, 5, 6, 7], out)
|
|
out = sndi.maximum_filter1d(in_, 5, mode='reflect')
|
|
assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 9, 9], out)
|
|
#Test constant
|
|
out = sndi.minimum_filter1d(in_, 5, mode='constant', cval=-1)
|
|
assert_equal([-1, -1, 0, 1, 2, 3, 4, 5, -1, -1], out)
|
|
out = sndi.maximum_filter1d(in_, 5, mode='constant', cval=10)
|
|
assert_equal([10, 10, 4, 5, 6, 7, 8, 9, 10, 10], out)
|
|
# Test nearest
|
|
out = sndi.minimum_filter1d(in_, 5, mode='nearest')
|
|
assert_equal([0, 0, 0, 1, 2, 3, 4, 5, 6, 7], out)
|
|
out = sndi.maximum_filter1d(in_, 5, mode='nearest')
|
|
assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 9, 9], out)
|
|
# Test wrap
|
|
out = sndi.minimum_filter1d(in_, 5, mode='wrap')
|
|
assert_equal([0, 0, 0, 1, 2, 3, 4, 5, 0, 0], out)
|
|
out = sndi.maximum_filter1d(in_, 5, mode='wrap')
|
|
assert_equal([9, 9, 4, 5, 6, 7, 8, 9, 9, 9], out)
|
|
|
|
|
|
def test_uniform_filter1d_roundoff_errors():
|
|
# gh-6930
|
|
in_ = np.repeat([0, 1, 0], [9, 9, 9])
|
|
for filter_size in range(3, 10):
|
|
out = sndi.uniform_filter1d(in_, filter_size)
|
|
assert_equal(out.sum(), 10 - filter_size)
|
|
|
|
|
|
def test_footprint_all_zeros():
|
|
# regression test for gh-6876: footprint of all zeros segfaults
|
|
arr = np.random.randint(0, 100, (100, 100))
|
|
kernel = np.zeros((3, 3), bool)
|
|
with assert_raises(ValueError):
|
|
sndi.maximum_filter(arr, footprint=kernel)
|
|
|
|
def test_gaussian_filter():
|
|
# Test gaussian filter with np.float16
|
|
# gh-8207
|
|
data = np.array([1],dtype = np.float16)
|
|
sigma = 1.0
|
|
with assert_raises(RuntimeError):
|
|
sndi.gaussian_filter(data,sigma)
|
|
|
|
|
|
def test_rank_filter_noninteger_rank():
|
|
# regression test for issue 9388: ValueError for
|
|
# non integer rank when performing rank_filter
|
|
arr = np.random.random((10, 20, 30))
|
|
assert_raises(TypeError, rank_filter, arr, 0.5,
|
|
footprint=np.ones((1, 1, 10), dtype=bool))
|
|
|
|
|
|
def test_size_footprint_both_set():
|
|
# test for input validation, expect user warning when
|
|
# size and footprint is set
|
|
with suppress_warnings() as sup:
|
|
sup.filter(UserWarning,
|
|
"ignoring size because footprint is set")
|
|
arr = np.random.random((10, 20, 30))
|
|
rank_filter(arr, 5, size=2, footprint=np.ones((1, 1, 10), dtype=bool))
|