# Source code for astropy.convolution.kernels

# Licensed under a 3-clause BSD style license - see LICENSE.rst

import math

import numpy as np

from .core import Kernel1D, Kernel2D, Kernel
from .utils import has_even_axis, raise_even_kernel_exception
from astropy.modeling import models
from astropy.modeling.core import Fittable1DModel, Fittable2DModel
from astropy.utils.decorators import deprecated

__all__ = ['Gaussian1DKernel', 'Gaussian2DKernel', 'CustomKernel',
'Box1DKernel', 'Box2DKernel', 'Tophat2DKernel',
'Trapezoid1DKernel', 'RickerWavelet1DKernel', 'RickerWavelet2DKernel',
'AiryDisk2DKernel', 'Moffat2DKernel', 'Model1DKernel',
'Model2DKernel', 'TrapezoidDisk2DKernel', 'Ring2DKernel']

def _round_up_to_odd_integer(value):
i = math.ceil(value)
if i % 2 == 0:
return i + 1
else:
return i

[docs]class Gaussian1DKernel(Kernel1D): """ 1D Gaussian filter kernel. The Gaussian filter is a filter with great smoothing properties. It is isotropic and does not produce artifacts. Parameters ---------- stddev : number Standard deviation of the Gaussian kernel. x_size : odd int, optional Size of the kernel array. Default = 8 * stddev mode : str, optional One of the following discretization modes: * 'center' (default) Discretize model by taking the value at the center of the bin. * 'linear_interp' Discretize model by linearly interpolating between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. Very slow. factor : number, optional Factor of oversampling. Default factor = 10. If the factor is too large, evaluation can be very slow. See Also -------- Box1DKernel, Trapezoid1DKernel, RickerWavelet1DKernel Examples -------- Kernel response: .. plot:: :include-source: import matplotlib.pyplot as plt from astropy.convolution import Gaussian1DKernel gauss_1D_kernel = Gaussian1DKernel(10) plt.plot(gauss_1D_kernel, drawstyle='steps') plt.xlabel('x [pixels]') plt.ylabel('value') plt.show() """ _separable = True _is_bool = False def __init__(self, stddev, **kwargs): self._model = models.Gaussian1D(1. / (np.sqrt(2 * np.pi) * stddev), 0, stddev) self._default_size = _round_up_to_odd_integer(8 * stddev) super().__init__(**kwargs) self._truncation = np.abs(1. - self._array.sum())
[docs]class Gaussian2DKernel(Kernel2D): """ 2D Gaussian filter kernel. The Gaussian filter is a filter with great smoothing properties. It is isotropic and does not produce artifacts. Parameters ---------- x_stddev : float Standard deviation of the Gaussian in x before rotating by theta. y_stddev : float Standard deviation of the Gaussian in y before rotating by theta. theta : float or :class:~astropy.units.Quantity Rotation angle. If passed as a float, it is assumed to be in radians. The rotation angle increases counterclockwise. x_size : odd int, optional Size in x direction of the kernel array. Default = 8 * stddev. y_size : odd int, optional Size in y direction of the kernel array. Default = 8 * stddev. mode : str, optional One of the following discretization modes: * 'center' (default) Discretize model by taking the value at the center of the bin. * 'linear_interp' Discretize model by performing a bilinear interpolation between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. See Also -------- Box2DKernel, Tophat2DKernel, RickerWavelet2DKernel, Ring2DKernel, TrapezoidDisk2DKernel, AiryDisk2DKernel, Moffat2DKernel Examples -------- Kernel response: .. plot:: :include-source: import matplotlib.pyplot as plt from astropy.convolution import Gaussian2DKernel gaussian_2D_kernel = Gaussian2DKernel(10) plt.imshow(gaussian_2D_kernel, interpolation='none', origin='lower') plt.xlabel('x [pixels]') plt.ylabel('y [pixels]') plt.colorbar() plt.show() """ _separable = True _is_bool = False def __init__(self, x_stddev, y_stddev=None, theta=0.0, **kwargs): if y_stddev is None: y_stddev = x_stddev self._model = models.Gaussian2D(1. / (2 * np.pi * x_stddev * y_stddev), 0, 0, x_stddev=x_stddev, y_stddev=y_stddev, theta=theta) self._default_size = _round_up_to_odd_integer( 8 * np.max([x_stddev, y_stddev])) super().__init__(**kwargs) self._truncation = np.abs(1. - self._array.sum())
[docs]class Box1DKernel(Kernel1D): """ 1D Box filter kernel. The Box filter or running mean is a smoothing filter. It is not isotropic and can produce artifacts, when applied repeatedly to the same data. By default the Box kernel uses the linear_interp discretization mode, which allows non-shifting, even-sized kernels. This is achieved by weighting the edge pixels with 1/2. E.g a Box kernel with an effective smoothing of 4 pixel would have the following array: [0.5, 1, 1, 1, 0.5]. Parameters ---------- width : number Width of the filter kernel. mode : str, optional One of the following discretization modes: * 'center' Discretize model by taking the value at the center of the bin. * 'linear_interp' (default) Discretize model by linearly interpolating between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. See Also -------- Gaussian1DKernel, Trapezoid1DKernel, RickerWavelet1DKernel Examples -------- Kernel response function: .. plot:: :include-source: import matplotlib.pyplot as plt from astropy.convolution import Box1DKernel box_1D_kernel = Box1DKernel(9) plt.plot(box_1D_kernel, drawstyle='steps') plt.xlim(-1, 9) plt.xlabel('x [pixels]') plt.ylabel('value') plt.show() """ _separable = True _is_bool = True def __init__(self, width, **kwargs): self._model = models.Box1D(1. / width, 0, width) self._default_size = _round_up_to_odd_integer(width) kwargs['mode'] = 'linear_interp' super().__init__(**kwargs) self._truncation = 0 self.normalize()
[docs]class Box2DKernel(Kernel2D): """ 2D Box filter kernel. The Box filter or running mean is a smoothing filter. It is not isotropic and can produce artifact, when applied repeatedly to the same data. By default the Box kernel uses the linear_interp discretization mode, which allows non-shifting, even-sized kernels. This is achieved by weighting the edge pixels with 1/2. Parameters ---------- width : number Width of the filter kernel. mode : str, optional One of the following discretization modes: * 'center' Discretize model by taking the value at the center of the bin. * 'linear_interp' (default) Discretize model by performing a bilinear interpolation between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. See Also -------- Gaussian2DKernel, Tophat2DKernel, RickerWavelet2DKernel, Ring2DKernel, TrapezoidDisk2DKernel, AiryDisk2DKernel, Moffat2DKernel Examples -------- Kernel response: .. plot:: :include-source: import matplotlib.pyplot as plt from astropy.convolution import Box2DKernel box_2D_kernel = Box2DKernel(9) plt.imshow(box_2D_kernel, interpolation='none', origin='lower', vmin=0.0, vmax=0.015) plt.xlim(-1, 9) plt.ylim(-1, 9) plt.xlabel('x [pixels]') plt.ylabel('y [pixels]') plt.colorbar() plt.show() """ _separable = True _is_bool = True def __init__(self, width, **kwargs): self._model = models.Box2D(1. / width ** 2, 0, 0, width, width) self._default_size = _round_up_to_odd_integer(width) kwargs['mode'] = 'linear_interp' super().__init__(**kwargs) self._truncation = 0 self.normalize()
[docs]class Tophat2DKernel(Kernel2D): """ 2D Tophat filter kernel. The Tophat filter is an isotropic smoothing filter. It can produce artifacts when applied repeatedly on the same data. Parameters ---------- radius : int Radius of the filter kernel. mode : str, optional One of the following discretization modes: * 'center' (default) Discretize model by taking the value at the center of the bin. * 'linear_interp' Discretize model by performing a bilinear interpolation between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. See Also -------- Gaussian2DKernel, Box2DKernel, RickerWavelet2DKernel, Ring2DKernel, TrapezoidDisk2DKernel, AiryDisk2DKernel, Moffat2DKernel Examples -------- Kernel response: .. plot:: :include-source: import matplotlib.pyplot as plt from astropy.convolution import Tophat2DKernel tophat_2D_kernel = Tophat2DKernel(40) plt.imshow(tophat_2D_kernel, interpolation='none', origin='lower') plt.xlabel('x [pixels]') plt.ylabel('y [pixels]') plt.colorbar() plt.show() """ def __init__(self, radius, **kwargs): self._model = models.Disk2D(1. / (np.pi * radius ** 2), 0, 0, radius) self._default_size = _round_up_to_odd_integer(2 * radius) super().__init__(**kwargs) self._truncation = 0
[docs]class RickerWavelet1DKernel(Kernel1D): """ 1D Ricker wavelet filter kernel (sometimes known as a "Mexican Hat" kernel). The Ricker wavelet, or inverted Gaussian-Laplace filter, is a bandpass filter. It smooths the data and removes slowly varying or constant structures (e.g. Background). It is useful for peak or multi-scale detection. This kernel is derived from a normalized Gaussian function, by computing the second derivative. This results in an amplitude at the kernels center of 1. / (sqrt(2 * pi) * width ** 3). The normalization is the same as for scipy.ndimage.gaussian_laplace, except for a minus sign. .. note:: See https://github.com/astropy/astropy/pull/9445 for discussions related to renaming of this kernel. Parameters ---------- width : number Width of the filter kernel, defined as the standard deviation of the Gaussian function from which it is derived. x_size : odd int, optional Size in x direction of the kernel array. Default = 8 * width. mode : str, optional One of the following discretization modes: * 'center' (default) Discretize model by taking the value at the center of the bin. * 'linear_interp' Discretize model by linearly interpolating between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. See Also -------- Box1DKernel, Gaussian1DKernel, Trapezoid1DKernel Examples -------- Kernel response: .. plot:: :include-source: import matplotlib.pyplot as plt from astropy.convolution import RickerWavelet1DKernel ricker_1d_kernel = RickerWavelet1DKernel(10) plt.plot(ricker_1d_kernel, drawstyle='steps') plt.xlabel('x [pixels]') plt.ylabel('value') plt.show() """ _is_bool = True def __init__(self, width, **kwargs): amplitude = 1.0 / (np.sqrt(2 * np.pi) * width ** 3) self._model = models.RickerWavelet1D(amplitude, 0, width) self._default_size = _round_up_to_odd_integer(8 * width) super().__init__(**kwargs) self._truncation = np.abs(self._array.sum() / self._array.size)
[docs]class RickerWavelet2DKernel(Kernel2D): """ 2D Ricker wavelet filter kernel (sometimes known as a "Mexican Hat" kernel). The Ricker wavelet, or inverted Gaussian-Laplace filter, is a bandpass filter. It smooths the data and removes slowly varying or constant structures (e.g. Background). It is useful for peak or multi-scale detection. This kernel is derived from a normalized Gaussian function, by computing the second derivative. This results in an amplitude at the kernels center of 1. / (pi * width ** 4). The normalization is the same as for scipy.ndimage.gaussian_laplace, except for a minus sign. .. note:: See https://github.com/astropy/astropy/pull/9445 for discussions related to renaming of this kernel. Parameters ---------- width : number Width of the filter kernel, defined as the standard deviation of the Gaussian function from which it is derived. x_size : odd int, optional Size in x direction of the kernel array. Default = 8 * width. y_size : odd int, optional Size in y direction of the kernel array. Default = 8 * width. mode : str, optional One of the following discretization modes: * 'center' (default) Discretize model by taking the value at the center of the bin. * 'linear_interp' Discretize model by performing a bilinear interpolation between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. See Also -------- Gaussian2DKernel, Box2DKernel, Tophat2DKernel, Ring2DKernel, TrapezoidDisk2DKernel, AiryDisk2DKernel, Moffat2DKernel Examples -------- Kernel response: .. plot:: :include-source: import matplotlib.pyplot as plt from astropy.convolution import RickerWavelet2DKernel ricker_2d_kernel = RickerWavelet2DKernel(10) plt.imshow(ricker_2d_kernel, interpolation='none', origin='lower') plt.xlabel('x [pixels]') plt.ylabel('y [pixels]') plt.colorbar() plt.show() """ _is_bool = False def __init__(self, width, **kwargs): amplitude = 1.0 / (np.pi * width ** 4) self._model = models.RickerWavelet2D(amplitude, 0, 0, width) self._default_size = _round_up_to_odd_integer(8 * width) super().__init__(**kwargs) self._truncation = np.abs(self._array.sum() / self._array.size)
[docs]class Model1DKernel(Kernel1D): """ Create kernel from 1D model. The model has to be centered on x = 0. Parameters ---------- model : ~astropy.modeling.Fittable1DModel Kernel response function model x_size : odd int, optional Size in x direction of the kernel array. Default = 8 * width. mode : str, optional One of the following discretization modes: * 'center' (default) Discretize model by taking the value at the center of the bin. * 'linear_interp' Discretize model by linearly interpolating between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. Raises ------ TypeError If model is not an instance of ~astropy.modeling.Fittable1DModel See also -------- Model2DKernel : Create kernel from ~astropy.modeling.Fittable2DModel CustomKernel : Create kernel from list or array Examples -------- Define a Gaussian1D model: >>> from astropy.modeling.models import Gaussian1D >>> from astropy.convolution.kernels import Model1DKernel >>> gauss = Gaussian1D(1, 0, 2) And create a custom one dimensional kernel from it: >>> gauss_kernel = Model1DKernel(gauss, x_size=9) This kernel can now be used like a usual Astropy kernel. """ _separable = False _is_bool = False def __init__(self, model, **kwargs): if isinstance(model, Fittable1DModel): self._model = model else: raise TypeError("Must be Fittable1DModel") super().__init__(**kwargs)
[docs]class Model2DKernel(Kernel2D): """ Create kernel from 2D model. The model has to be centered on x = 0 and y = 0. Parameters ---------- model : ~astropy.modeling.Fittable2DModel Kernel response function model x_size : odd int, optional Size in x direction of the kernel array. Default = 8 * width. y_size : odd int, optional Size in y direction of the kernel array. Default = 8 * width. mode : str, optional One of the following discretization modes: * 'center' (default) Discretize model by taking the value at the center of the bin. * 'linear_interp' Discretize model by performing a bilinear interpolation between the values at the corners of the bin. * 'oversample' Discretize model by taking the average on an oversampled grid. * 'integrate' Discretize model by integrating the model over the bin. factor : number, optional Factor of oversampling. Default factor = 10. Raises ------ TypeError If model is not an instance of ~astropy.modeling.Fittable2DModel See also -------- Model1DKernel : Create kernel from ~astropy.modeling.Fittable1DModel CustomKernel : Create kernel from list or array Examples -------- Define a Gaussian2D model: >>> from astropy.modeling.models import Gaussian2D >>> from astropy.convolution.kernels import Model2DKernel >>> gauss = Gaussian2D(1, 0, 0, 2, 2) And create a custom two dimensional kernel from it: >>> gauss_kernel = Model2DKernel(gauss, x_size=9) This kernel can now be used like a usual astropy kernel. """ _is_bool = False _separable = False def __init__(self, model, **kwargs): self._separable = False if isinstance(model, Fittable2DModel): self._model = model else: raise TypeError("Must be Fittable2DModel") super().__init__(**kwargs)