Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

ENH: ndimage: gaussian filter truncation #2767

Merged
merged 3 commits into from

4 participants

@WarrenWeckesser
Collaborator

This is an extension of #239
I added a commit that strengthens the existing test, and adds tests for more of the affected functions.

There are two API enhancements in this PR:

  • Add the truncate argument to gaussian_filter and gaussian_filter1d. This controls the size of the filter, measured in terms of the standard deviations of the gaussian.
  • Add **kwargs to the signature of gaussian_gradient_magnitude and gaussian_laplace. Any additional keyword arguments passed to these functions are passed on to gaussian_filter. This allows these functions to use the truncate argument.

This API looks reasonable to me. If there are no objections, I'd like to get this into 0.13.

@rgommers
Owner
  • can you rebase?
  • a bit late for 0.13.x, I'd rather leave it till 0.14
  • @thouis can you review the last commit?
thouis and others added some commits
@thouis thouis ENH: expose control truncation of ndimage.gaussian_filter().
This change gives the user control over the size at which the Gaussian filter is truncated,
with default behavior to truncate at 4 standard deviations (the previous fixed value).
19eff1c
@thouis thouis ENH: Pass extra keyword arguments to gaussian_laplace() and gaussian_…
…gradient_magnitude() to gaussian_filter()

This change allows control over the truncation radius of the gaussian filter used in
gaussian_laplace() and gaussian_gradient_magnitude().
f6c8d9d
@WarrenWeckesser WarrenWeckesser TST: ndimage: add more tests in test_gaussian_truncate() cf3aa17
@WarrenWeckesser
Collaborator

Rebased.

@WarrenWeckesser
Collaborator

@roderikk is probably interested in this too, since he created the original patch.

@pv pv referenced this pull request
Closed

Gaussian filter truncation #239

@thouis

Looks good to me.

@pv pv merged commit 56db4ed into from
@pv
Owner
pv commented

LGTM too, merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 28, 2013
  1. @thouis @WarrenWeckesser

    ENH: expose control truncation of ndimage.gaussian_filter().

    thouis authored WarrenWeckesser committed
    This change gives the user control over the size at which the Gaussian filter is truncated,
    with default behavior to truncate at 4 standard deviations (the previous fixed value).
  2. @thouis @WarrenWeckesser

    ENH: Pass extra keyword arguments to gaussian_laplace() and gaussian_…

    thouis authored WarrenWeckesser committed
    …gradient_magnitude() to gaussian_filter()
    
    This change allows control over the truncation radius of the gaussian filter used in
    gaussian_laplace() and gaussian_gradient_magnitude().
  3. @WarrenWeckesser
This page is out of date. Refresh to see the latest.
Showing with 68 additions and 14 deletions.
  1. +27 −14 scipy/ndimage/filters.py
  2. +41 −0 scipy/ndimage/tests/test_filters.py
View
41 scipy/ndimage/filters.py
@@ -178,7 +178,7 @@ def convolve1d(input, weights, axis=-1, output=None, mode="reflect",
@docfiller
def gaussian_filter1d(input, sigma, axis=-1, order=0, output=None,
- mode="reflect", cval=0.0):
+ mode="reflect", cval=0.0, truncate=4.0):
"""One-dimensional Gaussian filter.
Parameters
@@ -195,6 +195,9 @@ def gaussian_filter1d(input, sigma, axis=-1, order=0, output=None,
%(output)s
%(mode)s
%(cval)s
+ truncate : float
+ Truncate the filter at this many standard deviations.
+ Default is 4.0.
Returns
-------
@@ -204,9 +207,8 @@ def gaussian_filter1d(input, sigma, axis=-1, order=0, output=None,
if order not in range(4):
raise ValueError('Order outside 0..3 not implemented')
sd = float(sigma)
- # make the length of the filter equal to 4 times the standard
- # deviations:
- lw = int(4.0 * sd + 0.5)
+ # make the radius of the filter equal to truncate standard deviations
+ lw = int(truncate * sd + 0.5)
weights = [0.0] * (2 * lw + 1)
weights[lw] = 1.0
sum = 1.0
@@ -247,7 +249,7 @@ def gaussian_filter1d(input, sigma, axis=-1, order=0, output=None,
@docfiller
def gaussian_filter(input, sigma, order=0, output=None,
- mode="reflect", cval=0.0):
+ mode="reflect", cval=0.0, truncate=4.0):
"""Multidimensional Gaussian filter.
Parameters
@@ -268,6 +270,9 @@ def gaussian_filter(input, sigma, order=0, output=None,
%(output)s
%(mode)s
%(cval)s
+ truncate : float
+ Truncate the filter at this many standard deviations.
+ Default is 4.0.
Returns
-------
@@ -296,7 +301,7 @@ def gaussian_filter(input, sigma, order=0, output=None,
if len(axes) > 0:
for axis, sigma, order in axes:
gaussian_filter1d(input, sigma, axis, order, output,
- mode, cval)
+ mode, cval, truncate)
input = output
else:
output[...] = input[...]
@@ -405,7 +410,7 @@ def derivative2(input, axis, output, mode, cval):
@docfiller
def gaussian_laplace(input, sigma, output=None, mode="reflect",
- cval=0.0):
+ cval=0.0, **kwargs):
"""Multidimensional Laplace filter using gaussian second derivatives.
Parameters
@@ -418,15 +423,19 @@ def gaussian_laplace(input, sigma, output=None, mode="reflect",
%(output)s
%(mode)s
%(cval)s
+ Extra keyword arguments will be passed to gaussian_filter().
"""
input = numpy.asarray(input)
- def derivative2(input, axis, output, mode, cval, sigma):
+ def derivative2(input, axis, output, mode, cval, sigma, **kwargs):
order = [0] * input.ndim
order[axis] = 2
- return gaussian_filter(input, sigma, order, output, mode, cval)
+ return gaussian_filter(input, sigma, order, output, mode, cval,
+ **kwargs)
+
return generic_laplace(input, derivative2, output, mode, cval,
- extra_arguments=(sigma,))
+ extra_arguments=(sigma,),
+ extra_keywords=kwargs)
@docfiller
@@ -480,7 +489,7 @@ def generic_gradient_magnitude(input, derivative, output=None,
@docfiller
def gaussian_gradient_magnitude(input, sigma, output=None,
- mode="reflect", cval=0.0):
+ mode="reflect", cval=0.0, **kwargs):
"""Multidimensional gradient magnitude using Gaussian derivatives.
Parameters
@@ -493,15 +502,19 @@ def gaussian_gradient_magnitude(input, sigma, output=None,
%(output)s
%(mode)s
%(cval)s
+ Extra keyword arguments will be passed to gaussian_filter().
"""
input = numpy.asarray(input)
- def derivative(input, axis, output, mode, cval, sigma):
+ def derivative(input, axis, output, mode, cval, sigma, **kwargs):
order = [0] * input.ndim
order[axis] = 1
- return gaussian_filter(input, sigma, order, output, mode, cval)
+ return gaussian_filter(input, sigma, order, output, mode,
+ cval, **kwargs)
+
return generic_gradient_magnitude(input, derivative, output, mode,
- cval, extra_arguments=(sigma,))
+ cval, extra_arguments=(sigma,),
+ extra_keywords=kwargs)
def _correlate_or_convolve(input, weights, output, mode, cval, origin,
View
41 scipy/ndimage/tests/test_filters.py
@@ -53,3 +53,44 @@ def test_valid_origins():
# Just check this raises an error instead of silently accepting or
# segfaulting.
assert_raises(ValueError, filter, data, 3, origin=2)
+
+
+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), np.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.where(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.where(y != 0)[0]
+ n = nonzero_indices.ptp() + 1
+ assert_equal(n, 15)
Something went wrong with that request. Please try again.