卷积核#

导言和概念#

卷积模块提供了几个内置内核,以涵盖天文学中最常见的应用。也可以从数组中定义自定义内核,或者组合现有内核来匹配特定的应用程序。

每个滤波器内核都有其响应函数的特征。对于时间序列,我们说的是“脉冲响应函数”,或者我们称之为“点扩散函数”,这个响应函数是由 FittableModel ,在网格上使用 discretize_model() 得到一个可用于对二进制数据进行离散卷积的核数组。

实例#

一维核#

滤波的一个应用是平滑噪声数据。在这种情况下,我们考虑一个有噪声的洛伦兹曲线:

>>> import numpy as np
>>> from astropy.modeling.models import Lorentz1D
>>> from astropy.convolution import convolve, Gaussian1DKernel, Box1DKernel
>>> rng = np.random.default_rng()
>>> lorentz = Lorentz1D(1, 0, 1)
>>> x = np.linspace(-5, 5, 100)
>>> data_1D = lorentz(x) + 0.1 * (rng.random(100) - 0.5)

Gaussian1DKernel 标准偏差为2像素:

>>> gauss_kernel = Gaussian1DKernel(2)
>>> smoothed_data_gauss = convolve(data_1D, gauss_kernel)

Box1DKernel 宽度为5像素:

>>> box_kernel = Box1DKernel(5)
>>> smoothed_data_box = convolve(data_1D, box_kernel)

下图说明了结果:

(png, svg, pdf)

../_images/kernels-1.png

astropy 卷积函数 convolveconvolve_fft ,也可以将内核与 numpyscipy 卷积 array 属性。这在大多数情况下比 astropy 卷积,但如果数据中存在NaN值,则无法正常工作。

>>> smoothed = np.convolve(data_1D, box_kernel.array)

二维核#

由于所有的二维核都是对称的,只需指定一个方向的宽度就足够了。因此,2D内核的使用与1D内核的用法基本相同。这里,我们考虑图像中间一个振幅为1的小高斯形源,并添加10%的噪声:

>>> import numpy as np
>>> from astropy.convolution import convolve, Gaussian2DKernel, Tophat2DKernel
>>> from astropy.modeling.models import Gaussian2D
>>> gauss = Gaussian2D(1, 0, 0, 3, 3)
>>> # Fake image data including noise
>>> rng = np.random.default_rng()
>>> x = np.arange(-100, 101)
>>> y = np.arange(-100, 101)
>>> x, y = np.meshgrid(x, y)
>>> data_2D = gauss(x, y) + 0.1 * (rng.random((201, 201)) - 0.5)

Gaussian2DKernel 标准偏差为2像素:

>>> gauss_kernel = Gaussian2DKernel(2)
>>> smoothed_data_gauss = convolve(data_2D, gauss_kernel)

Tophat2DKernel 宽度为5像素:

>>> tophat_kernel = Tophat2DKernel(5)
>>> smoothed_data_tophat = convolve(data_2D, tophat_kernel)

原始图像如下所示:

(png, svg, pdf)

../_images/kernels-2.png

下图说明了应用于模拟数据的几个二维核之间的差异。请注意,与原始图像相比,它的色阶略有不同。

(png, svg, pdf)

../_images/kernels-3.png

高斯核与Box和Top-Hat相比具有更好的平滑特性。长方体过滤器不是各向同性的,会产生伪影(源显示为矩形)。Ricker小波滤波器去除噪声和缓慢变化的结构(即背景),但在源周围产生负环。过滤器的最佳选择很大程度上取决于应用。

可用内核#

AiryDisk2DKernel(radius, **kwargs)

2D Airy磁盘内核。

Box1DKernel(width, **kwargs)

1D盒过滤器内核。

Box2DKernel(width, **kwargs)

二维盒过滤器内核。

CustomKernel \(数组)

从列表或数组创建筛选器内核。

Gaussian1DKernel(stddev, **kwargs)

一维高斯滤波器核。

Gaussian2DKernel(x_stddev[, y_stddev, theta])

二维高斯滤波核。

RickerWavelet1DKernel(width, **kwargs)

一维Ricker小波滤波器核(有时称为“墨西哥帽”核)。

RickerWavelet2DKernel(width, **kwargs)

二维Ricker小波滤波器核(有时称为“墨西哥帽”核)。

Model1DKernel(model, **kwargs)

从1D模型创建内核。

Model2DKernel(model, **kwargs)

从二维模型创建内核。

Moffat2DKernel(gamma, alpha, **kwargs)

二维Moffat内核。

Ring2DKernel(radius_in, width, **kwargs)

二维环形滤波器内核。

Tophat2DKernel(radius, **kwargs)

2D Tophat过滤器内核。

Trapezoid1DKernel(width[, slope])

一维梯形核。

TrapezoidDisk2DKernel(radius[, slope])

二维梯形核。

核算法#

加减法#

由于卷积是一种线性运算,核可以相互加减。它们也可以与某个数相乘。

实例#

减去核的一个基本例子是高斯滤波器差分的定义:

>>> from astropy.convolution import Gaussian1DKernel
>>> gauss_1 = Gaussian1DKernel(10)
>>> gauss_2 = Gaussian1DKernel(16)
>>> DoG = gauss_2 - gauss_1

另一个应用是用仪器响应函数模型卷积伪数据。例如,如果响应函数可以用两个高斯函数的加权和来描述:

>>> gauss_1 = Gaussian1DKernel(10)
>>> gauss_2 = Gaussian1DKernel(16)
>>> SoG = 4 * gauss_1 + gauss_2

大多数情况下,需要通过显式调用来规范化生成的内核:

>>> SoG.normalize()

卷积#

此外,两个核可以相互卷积,这在用两种不同的核来过滤数据或创建一个新的、特殊的内核时非常有用。

实例#

将两个核相互卷积:

>>> from astropy.convolution import Gaussian1DKernel, convolve
>>> gauss_1 = Gaussian1DKernel(10)
>>> gauss_2 = Gaussian1DKernel(16)
>>> broad_gaussian = convolve(gauss_2,  gauss_1)  

或多级平滑:

>>> import numpy as np
>>> from astropy.modeling.models import Lorentz1D
>>> from astropy.convolution import convolve, Gaussian1DKernel, Box1DKernel
>>> rng = np.random.default_rng()
>>> lorentz = Lorentz1D(1, 0, 1)
>>> x = np.linspace(-5, 5, 100)
>>> data_1D = lorentz(x) + 0.1 * (rng.random(100) - 0.5)
>>> gauss = Gaussian1DKernel(3)
>>> box = Box1DKernel(5)
>>> smoothed_gauss = convolve(data_1D, gauss)
>>> smoothed_gauss_box = convolve(smoothed_gauss, box)

您宁愿执行以下操作:

>>> gauss = Gaussian1DKernel(3)
>>> box = Box1DKernel(5)
>>> smoothed_gauss_box = convolve(data_1D, convolve(box, gauss))  

在大多数情况下,这种方法也比第一种方法快,因为只需要对通常大几倍的数据数组进行一次卷积。

离散化#

为了得到离散卷积的核阵列,在网格上计算核的响应函数 discretize_model() . 对于离散化步骤,以下模式可用:

  • 模式 'center' (默认)通过获取bin中心的值来计算网格上的响应函数。

    >>> from astropy.convolution import Gaussian1DKernel
    >>> gauss_center = Gaussian1DKernel(3, mode='center')
    
  • 模式 'linear_interp' 获取存储箱拐角处的值并线性插值中心的值:

    >>> gauss_interp = Gaussian1DKernel(3, mode='linear_interp')
    
  • 模式 'oversample' 通过取过采样网格上的平均值来计算响应函数。过采样系数可以用 factor 争论。如果过采样因子过大,评估会变慢。

>>> gauss_oversample = Gaussian1DKernel(3, mode='oversample', factor=10)
  • 模式 'integrate' 使用在像素上集成函数 scipy.integrate.quadscipy.integrate.dblquad . 此模式非常慢,仅当需要最高精度时才建议使用。

>>> gauss_integrate = Gaussian1DKernel(3, mode='integrate')

特别是在核宽度仅为几个像素的范围内,使用模式是有利的 oversampleintegrate 在亚像素尺度上保持积分。

归一化#

默认情况下,内核模型是标准化的(即。, \(\int_{{-\infty}}^{{\infty}} f(x) dx = 1\) ). 但是由于内核数组的大小有限,具有无限响应的内核的规范化可能与一个不同。这个偏差的值存储在内核的 truncation 属性。

由于离散化步骤,规范化也可能与一个不同,特别是对于小核函数。这可以部分地由 mode 参数,初始化内核时。(另请参见 discretize_model() .)设置 mode'oversample' 即使在亚像素尺度上也能保持标准化。

可以通过调用 normalize() 方法或通过设置 normalize_kernel 论证中 convolve()convolve_fft() 功能。后一种方法保持内核本身不变,但使用内核的内部规范化版本。

请注意 RickerWavelet1DKernelRickerWavelet2DKernel\(\int_{{-\infty}}^{{\infty}} f(x) dx = 0\) . 为了定义一个适当的归一化,两个滤波器都是从归一化高斯函数导出的。