123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- # Copyright (C) 2003-2005 Peter J. Verveer
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions
- # are met:
- #
- # 1. Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- #
- # 2. Redistributions in binary form must reproduce the above
- # copyright notice, this list of conditions and the following
- # disclaimer in the documentation and/or other materials provided
- # with the distribution.
- #
- # 3. The name of the author may not be used to endorse or promote
- # products derived from this software without specific prior
- # written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- import numpy
- from numpy.core.multiarray import normalize_axis_index
- from . import _ni_support
- from . import _nd_image
- __all__ = ['fourier_gaussian', 'fourier_uniform', 'fourier_ellipsoid',
- 'fourier_shift']
- def _get_output_fourier(output, input):
- if output is None:
- if input.dtype.type in [numpy.complex64, numpy.complex128,
- numpy.float32]:
- output = numpy.zeros(input.shape, dtype=input.dtype)
- else:
- output = numpy.zeros(input.shape, dtype=numpy.float64)
- elif type(output) is type:
- if output not in [numpy.complex64, numpy.complex128,
- numpy.float32, numpy.float64]:
- raise RuntimeError("output type not supported")
- output = numpy.zeros(input.shape, dtype=output)
- elif output.shape != input.shape:
- raise RuntimeError("output shape not correct")
- return output
- def _get_output_fourier_complex(output, input):
- if output is None:
- if input.dtype.type in [numpy.complex64, numpy.complex128]:
- output = numpy.zeros(input.shape, dtype=input.dtype)
- else:
- output = numpy.zeros(input.shape, dtype=numpy.complex128)
- elif type(output) is type:
- if output not in [numpy.complex64, numpy.complex128]:
- raise RuntimeError("output type not supported")
- output = numpy.zeros(input.shape, dtype=output)
- elif output.shape != input.shape:
- raise RuntimeError("output shape not correct")
- return output
- def fourier_gaussian(input, sigma, n=-1, axis=-1, output=None):
- """
- Multidimensional Gaussian fourier filter.
- The array is multiplied with the fourier transform of a Gaussian
- kernel.
- Parameters
- ----------
- input : array_like
- The input array.
- sigma : float or sequence
- The sigma of the Gaussian kernel. If a float, `sigma` is the same for
- all axes. If a sequence, `sigma` has to contain one value for each
- axis.
- n : int, optional
- If `n` is negative (default), then the input is assumed to be the
- result of a complex fft.
- If `n` is larger than or equal to zero, the input is assumed to be the
- result of a real fft, and `n` gives the length of the array before
- transformation along the real transform direction.
- axis : int, optional
- The axis of the real transform.
- output : ndarray, optional
- If given, the result of filtering the input is placed in this array.
- Returns
- -------
- fourier_gaussian : ndarray
- The filtered input.
- Examples
- --------
- >>> from scipy import ndimage, datasets
- >>> import numpy.fft
- >>> import matplotlib.pyplot as plt
- >>> fig, (ax1, ax2) = plt.subplots(1, 2)
- >>> plt.gray() # show the filtered result in grayscale
- >>> ascent = datasets.ascent()
- >>> input_ = numpy.fft.fft2(ascent)
- >>> result = ndimage.fourier_gaussian(input_, sigma=4)
- >>> result = numpy.fft.ifft2(result)
- >>> ax1.imshow(ascent)
- >>> ax2.imshow(result.real) # the imaginary part is an artifact
- >>> plt.show()
- """
- input = numpy.asarray(input)
- output = _get_output_fourier(output, input)
- axis = normalize_axis_index(axis, input.ndim)
- sigmas = _ni_support._normalize_sequence(sigma, input.ndim)
- sigmas = numpy.asarray(sigmas, dtype=numpy.float64)
- if not sigmas.flags.contiguous:
- sigmas = sigmas.copy()
- _nd_image.fourier_filter(input, sigmas, n, axis, output, 0)
- return output
- def fourier_uniform(input, size, n=-1, axis=-1, output=None):
- """
- Multidimensional uniform fourier filter.
- The array is multiplied with the Fourier transform of a box of given
- size.
- Parameters
- ----------
- input : array_like
- The input array.
- size : float or sequence
- The size of the box used for filtering.
- If a float, `size` is the same for all axes. If a sequence, `size` has
- to contain one value for each axis.
- n : int, optional
- If `n` is negative (default), then the input is assumed to be the
- result of a complex fft.
- If `n` is larger than or equal to zero, the input is assumed to be the
- result of a real fft, and `n` gives the length of the array before
- transformation along the real transform direction.
- axis : int, optional
- The axis of the real transform.
- output : ndarray, optional
- If given, the result of filtering the input is placed in this array.
- Returns
- -------
- fourier_uniform : ndarray
- The filtered input.
- Examples
- --------
- >>> from scipy import ndimage, datasets
- >>> import numpy.fft
- >>> import matplotlib.pyplot as plt
- >>> fig, (ax1, ax2) = plt.subplots(1, 2)
- >>> plt.gray() # show the filtered result in grayscale
- >>> ascent = datasets.ascent()
- >>> input_ = numpy.fft.fft2(ascent)
- >>> result = ndimage.fourier_uniform(input_, size=20)
- >>> result = numpy.fft.ifft2(result)
- >>> ax1.imshow(ascent)
- >>> ax2.imshow(result.real) # the imaginary part is an artifact
- >>> plt.show()
- """
- input = numpy.asarray(input)
- output = _get_output_fourier(output, input)
- axis = normalize_axis_index(axis, input.ndim)
- sizes = _ni_support._normalize_sequence(size, input.ndim)
- sizes = numpy.asarray(sizes, dtype=numpy.float64)
- if not sizes.flags.contiguous:
- sizes = sizes.copy()
- _nd_image.fourier_filter(input, sizes, n, axis, output, 1)
- return output
- def fourier_ellipsoid(input, size, n=-1, axis=-1, output=None):
- """
- Multidimensional ellipsoid Fourier filter.
- The array is multiplied with the fourier transform of an ellipsoid of
- given sizes.
- Parameters
- ----------
- input : array_like
- The input array.
- size : float or sequence
- The size of the box used for filtering.
- If a float, `size` is the same for all axes. If a sequence, `size` has
- to contain one value for each axis.
- n : int, optional
- If `n` is negative (default), then the input is assumed to be the
- result of a complex fft.
- If `n` is larger than or equal to zero, the input is assumed to be the
- result of a real fft, and `n` gives the length of the array before
- transformation along the real transform direction.
- axis : int, optional
- The axis of the real transform.
- output : ndarray, optional
- If given, the result of filtering the input is placed in this array.
- Returns
- -------
- fourier_ellipsoid : ndarray
- The filtered input.
- Notes
- -----
- This function is implemented for arrays of rank 1, 2, or 3.
- Examples
- --------
- >>> from scipy import ndimage, datasets
- >>> import numpy.fft
- >>> import matplotlib.pyplot as plt
- >>> fig, (ax1, ax2) = plt.subplots(1, 2)
- >>> plt.gray() # show the filtered result in grayscale
- >>> ascent = datasets.ascent()
- >>> input_ = numpy.fft.fft2(ascent)
- >>> result = ndimage.fourier_ellipsoid(input_, size=20)
- >>> result = numpy.fft.ifft2(result)
- >>> ax1.imshow(ascent)
- >>> ax2.imshow(result.real) # the imaginary part is an artifact
- >>> plt.show()
- """
- input = numpy.asarray(input)
- if input.ndim > 3:
- raise NotImplementedError("Only 1d, 2d and 3d inputs are supported")
- output = _get_output_fourier(output, input)
- if output.size == 0:
- # The C code has a bug that can result in a segfault with arrays
- # that have size 0 (gh-17270), so check here.
- return output
- axis = normalize_axis_index(axis, input.ndim)
- sizes = _ni_support._normalize_sequence(size, input.ndim)
- sizes = numpy.asarray(sizes, dtype=numpy.float64)
- if not sizes.flags.contiguous:
- sizes = sizes.copy()
- _nd_image.fourier_filter(input, sizes, n, axis, output, 2)
- return output
- def fourier_shift(input, shift, n=-1, axis=-1, output=None):
- """
- Multidimensional Fourier shift filter.
- The array is multiplied with the Fourier transform of a shift operation.
- Parameters
- ----------
- input : array_like
- The input array.
- shift : float or sequence
- The size of the box used for filtering.
- If a float, `shift` is the same for all axes. If a sequence, `shift`
- has to contain one value for each axis.
- n : int, optional
- If `n` is negative (default), then the input is assumed to be the
- result of a complex fft.
- If `n` is larger than or equal to zero, the input is assumed to be the
- result of a real fft, and `n` gives the length of the array before
- transformation along the real transform direction.
- axis : int, optional
- The axis of the real transform.
- output : ndarray, optional
- If given, the result of shifting the input is placed in this array.
- Returns
- -------
- fourier_shift : ndarray
- The shifted input.
- Examples
- --------
- >>> from scipy import ndimage, datasets
- >>> import matplotlib.pyplot as plt
- >>> import numpy.fft
- >>> fig, (ax1, ax2) = plt.subplots(1, 2)
- >>> plt.gray() # show the filtered result in grayscale
- >>> ascent = datasets.ascent()
- >>> input_ = numpy.fft.fft2(ascent)
- >>> result = ndimage.fourier_shift(input_, shift=200)
- >>> result = numpy.fft.ifft2(result)
- >>> ax1.imshow(ascent)
- >>> ax2.imshow(result.real) # the imaginary part is an artifact
- >>> plt.show()
- """
- input = numpy.asarray(input)
- output = _get_output_fourier_complex(output, input)
- axis = normalize_axis_index(axis, input.ndim)
- shifts = _ni_support._normalize_sequence(shift, input.ndim)
- shifts = numpy.asarray(shifts, dtype=numpy.float64)
- if not shifts.flags.contiguous:
- shifts = shifts.copy()
- _nd_image.fourier_shift(input, shifts, n, axis, output)
- return output
|