예제 #1
0
def fourier_uniform(input, size, n=-1, axis=-1, output=None):
    """Multidimensional uniform shift filter.

    The array is multiplied with the Fourier transform of a box of given size.

    Args:
        input (cupy.ndarray): The input array.
        size (float or sequence of float):  The sigma 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 (only used when
            ``n > -1``).
        output (cupy.ndarray, optional):
            If given, the result of shifting the input is placed in this array.

    Returns:
        output (cupy.ndarray): The filtered output.
    """
    ndim = input.ndim
    output = _get_output_fourier(output, input)
    axis = internal._normalize_axis_index(axis, ndim)
    sizes = _util._fix_sequence_arg(size, ndim, 'size')

    output[...] = input
    for ax, (size, ax_size) in enumerate(zip(sizes, output.shape)):

        # compute the frequency grid in Hz
        if ax == axis and n > 0:
            arr = cupy.arange(ax_size, dtype=output.real.dtype)
            arr /= n
        else:
            arr = cupy.fft.fftfreq(ax_size)
        arr = arr.astype(output.real.dtype, copy=False)

        # compute the uniform filter weights
        arr *= size
        cupy.sinc(arr, out=arr)

        # reshape for broadcasting
        arr = _reshape_nd(arr, ndim=ndim, axis=ax)
        output *= arr

    return output
예제 #2
0
def take_filter(N, filter):
    os = 4
    d = 0.5
    Ne = os * N
    t = cp.arange(0, Ne / 2 + 1) / Ne

    if (filter == 'ramp'):
        wfa = Ne * 0.5 * wint(12, t)  # .*(t/(2*d)<=1)%compute the weigths
    elif (filter == 'shepp-logan'):
        wfa = Ne * 0.5 * wint(12, t) * cp.sinc(t / (2 * d)) * (t / d <= 2)
    elif (filter == 'cosine'):
        wfa = Ne * 0.5 * wint(12, t) * cp.cos(cp.pi * t /
                                              (2 * d)) * (t / d <= 1)
    elif (filter == 'cosine2'):
        wfa = Ne * 0.5 * wint(12, t) * (cp.cos(cp.pi * t /
                                               (2 * d)))**2 * (t / d <= 1)
    elif (filter == 'hamming'):
        wfa = Ne * 0.5 * wint(
            12, t) * (.54 + .46 * cp.cos(cp.pi * t / d)) * (t / d <= 1)
    elif (filter == 'hann'):
        wfa = Ne * 0.5 * wint(
            12, t) * (1 + np.cos(cp.pi * t / d)) / 2.0 * (t / d <= 1)
    elif (filter == 'parzen'):
        wfa = Ne * 0.5 * wint(12, t) * pow(1 - t / d, 3) * (t / d <= 1)

    wfa = wfa * (wfa >= 0)
    wfamid = cp.array([2 * wfa[0]])
    tmp = wfa
    wfa = cp.concatenate((cp.flipud(tmp[1:]), wfamid))
    wfa = cp.concatenate((wfa, tmp[1:]))
    wfa = wfa[:-1].astype('float32')
    return wfa
예제 #3
0
def generate_lanczos4_weights_lut() -> cp.array:
    """generate a look-up table of lanczos4 core function for further acceleration.
    lanczos4 stands for 4-order lanczos(四阶lanczos算法,常用于图像放大,缩小一般只用到3阶)
    the LUT provides an accuracy of 1/(2^8). since the order is 4, the range of x is from[-4,4]
    this LUT is about 3 times faster than function evaluation counterparts.
    func_lut[abs((x*1024).astype(int))] == lanczos4_core_function(x)
    """
    # 我们需要的是core_lut,即图片上任何一个非整数坐标,从周围采样点插值时,各采样点的权重的查找表
    # 它的下标(index)取值范围为[-3,5), 使用core_lut[(x*1024).astype(int)]来查表
    i = cp.hstack((cp.arange(0, 5, 1 / 1024, dtype=cp.float32),
                   cp.arange(-3, 0, 1 / 1024,
                             dtype=cp.float32)))  # this is the index of lut
    x = cp.zeros((len(i), 8), dtype=cp.float32)
    x -= cp.expand_dims(cp.arange(-3, 5), 0)
    x += cp.expand_dims(i, 1)
    core_lut = cp.sinc(x) * cp.sinc(x / 4)
    # normalize weights
    y = cp.mean(core_lut, axis=1, keepdims=True)
    return core_lut / y
예제 #4
0
    def deformation(self, prm):
        """
            Apply 2D Gaussian and Planar deformation.
            Computation is parallelized on GPU using cupy.
        """
        import cupy as cp
        xy_cp = cp.asarray(prm.xy)
        a_cp = cp.asarray(self.a)
        b_cp = cp.asarray(self.b)
        c_cp = cp.asarray(self.c)
        d_cp = cp.asarray(self.d)
        sigma_cp = cp.asarray(self.sigma)
        e_cp = cp.asarray(self.e)
        f_cp = cp.asarray(self.f)
        g_cp = cp.asarray(self.g)
        z_cp = cp.asarray(prm.z)

        func_planar = cp.ElementwiseKernel(
            in_params='T x, T y, T e, T f, T g',
            out_params='T z',
            operation= \
                '''
                z = e + f*x + g*y;
                ''',
            name='func_planar'
        )

        func_gauss2d = cp.ElementwiseKernel(
            in_params='T x, T y, T b, T c, T d, T sigma',
            out_params='T z',
            operation= \
                '''
                z = b*expf(-(powf(x-c,2) + powf(y-d,2))/(2*powf(sigma,2)));
                ''',
            name='func_gauss2d'
        )

        gauss_2d_cp = cp.zeros_like(xy_cp[:, 0])
        for i in range(len(self.b)):
            gauss_2d_cp += func_gauss2d(xy_cp[:, 0], xy_cp[:, 1], b_cp[i], c_cp[i], d_cp[i], sigma_cp[i])
        s1_cp = a_cp + (1.5 / z_cp) * cp.outer(cp.transpose(gauss_2d_cp), z_cp)
        s2_cp = func_planar(xy_cp[:, 0], xy_cp[:, 1], e_cp, f_cp, g_cp)

        refl_cp = cp.asarray(self.refl)
        for i in range(prm.nxy_tr):
            s = s1_cp[i, :] + s2_cp[i] + z_cp
            mat = cp.tile(z_cp, (len(s), 1)) - cp.tile(cp.expand_dims(s, 1), (1, len(z_cp)))
            refl_cp[i, :] = cp.dot(refl_cp[i, :], cp.sinc(mat))

        return np.reshape(cp.asnumpy(refl_cp), [prm.nxy_tr, prm.nz_tr])
예제 #5
0
def firwin(
    numtaps,
    cutoff,
    width=None,
    window="hamming",
    pass_zero=True,
    scale=True,
    nyq=1.0,
    fs=None,
):
    """
    FIR filter design using the window method.

    This function computes the coefficients of a finite impulse response
    filter.  The filter will have linear phase; it will be Type I if
    `numtaps` is odd and Type II if `numtaps` is even.

    Type II filters always have zero response at the Nyquist frequency, so a
    ValueError exception is raised if firwin is called with `numtaps` even and
    having a passband whose right end is at the Nyquist frequency.

    Parameters
    ----------
    numtaps : int
        Length of the filter (number of coefficients, i.e. the filter
        order + 1).  `numtaps` must be odd if a passband includes the
        Nyquist frequency.
    cutoff : float or 1D array_like
        Cutoff frequency of filter (expressed in the same units as `fs`)
        OR an array of cutoff frequencies (that is, band edges). In the
        latter case, the frequencies in `cutoff` should be positive and
        monotonically increasing between 0 and `fs/2`.  The values 0 and
        `fs/2` must not be included in `cutoff`.
    width : float or None, optional
        If `width` is not None, then assume it is the approximate width
        of the transition region (expressed in the same units as `fs`)
        for use in Kaiser FIR filter design.  In this case, the `window`
        argument is ignored.
    window : string or tuple of string and parameter values, optional
        Desired window to use. See `cusignal.get_window` for a list
        of windows and required parameters.
    pass_zero : {True, False, 'bandpass', 'lowpass', 'highpass', 'bandstop'},
        optional
        If True, the gain at the frequency 0 (i.e. the "DC gain") is 1.
        If False, the DC gain is 0. Can also be a string argument for the
        desired filter type (equivalent to ``btype`` in IIR design functions).

        .. versionadded:: 1.3.0
           Support for string arguments.
    scale : bool, optional
        Set to True to scale the coefficients so that the frequency
        response is exactly unity at a certain frequency.
        That frequency is either:

        - 0 (DC) if the first passband starts at 0 (i.e. pass_zero
          is True)
        - `fs/2` (the Nyquist frequency) if the first passband ends at
          `fs/2` (i.e the filter is a single band highpass filter);
          center of first passband otherwise

    nyq : float, optional
        *Deprecated.  Use `fs` instead.*  This is the Nyquist frequency.
        Each frequency in `cutoff` must be between 0 and `nyq`. Default
        is 1.
    fs : float, optional
        The sampling frequency of the signal.  Each frequency in `cutoff`
        must be between 0 and ``fs/2``.  Default is 2.

    Returns
    -------
    h : (numtaps,) ndarray
        Coefficients of length `numtaps` FIR filter.

    Raises
    ------
    ValueError
        If any value in `cutoff` is less than or equal to 0 or greater
        than or equal to ``fs/2``, if the values in `cutoff` are not strictly
        monotonically increasing, or if `numtaps` is even but a passband
        includes the Nyquist frequency.

    See Also
    --------
    firwin2
    firls
    minimum_phase
    remez

    Examples
    --------
    Low-pass from 0 to f:

    >>> import cusignal
    >>> numtaps = 3
    >>> f = 0.1
    >>> cusignal.firwin(numtaps, f)
    array([ 0.06799017,  0.86401967,  0.06799017])

    Use a specific window function:

    >>> cusignal.firwin(numtaps, f, window='nuttall')
    array([  3.56607041e-04,   9.99286786e-01,   3.56607041e-04])

    High-pass ('stop' from 0 to f):

    >>> cusignal.firwin(numtaps, f, pass_zero=False)
    array([-0.00859313,  0.98281375, -0.00859313])

    Band-pass:

    >>> f1, f2 = 0.1, 0.2
    >>> cusignal.firwin(numtaps, [f1, f2], pass_zero=False)
    array([ 0.06301614,  0.88770441,  0.06301614])

    Band-stop:

    >>> cusignal.firwin(numtaps, [f1, f2])
    array([-0.00801395,  1.0160279 , -0.00801395])

    Multi-band (passbands are [0, f1], [f2, f3] and [f4, 1]):

    >>> f3, f4 = 0.3, 0.4
    >>> cusignal.firwin(numtaps, [f1, f2, f3, f4])
    array([-0.01376344,  1.02752689, -0.01376344])

    Multi-band (passbands are [f1, f2] and [f3,f4]):

    >>> cusignal.firwin(numtaps, [f1, f2, f3, f4], pass_zero=False)
    array([ 0.04890915,  0.91284326,  0.04890915])

    """
    cutoff = cp.atleast_1d(cutoff) / float(nyq)

    # Check for invalid input.
    if cutoff.ndim > 1:
        raise ValueError(
            "The cutoff argument must be at most " "one-dimensional."
        )
    if cutoff.size == 0:
        raise ValueError("At least one cutoff frequency must be given.")
    if cutoff.min() <= 0 or cutoff.max() >= 1:
        raise ValueError(
            "Invalid cutoff frequency: frequencies must be "
            "greater than 0 and less than nyq."
        )
    if cp.any(cp.diff(cutoff) <= 0):
        raise ValueError(
            "Invalid cutoff frequencies: the frequencies "
            "must be strictly increasing."
        )

    if width is not None:
        # A width was given.  Find the beta parameter of the Kaiser window
        # and set `window`.  This overrides the value of `window` passed in.
        atten = kaiser_atten(numtaps, float(width) / nyq)
        beta = kaiser_beta(atten)
        window = ("kaiser", beta)

    pass_nyquist = bool(cutoff.size & 1) ^ pass_zero
    if pass_nyquist and numtaps % 2 == 0:
        raise ValueError(
            "A filter with an even number of coefficients must "
            "have zero response at the Nyquist rate."
        )

    # Insert 0 and/or 1 at the ends of cutoff so that the length of cutoff
    # is even, and each pair in cutoff corresponds to passband.
    cutoff = cp.hstack(([0.0] * pass_zero, cutoff, [1.0] * pass_nyquist))

    # `bands` is a 2D array; each row gives the left and right edges of
    # a passband.
    bands = cutoff.reshape(-1, 2)

    # Build up the coefficients.
    alpha = 0.5 * (numtaps - 1)
    m = cp.arange(0, numtaps) - alpha
    h = 0
    for left, right in bands:
        h += right * cp.sinc(right * m)
        h -= left * cp.sinc(left * m)

    # Get and apply the window function.
    win = get_window(window, numtaps, fftbins=False)
    h *= win

    # Now handle scaling if desired.
    if scale:
        # Get the first passband.
        left, right = bands[0]
        if left == 0:
            scale_frequency = 0.0
        elif right == 1:
            scale_frequency = 1.0
        else:
            scale_frequency = 0.5 * (left + right)
        c = cp.cos(cp.pi * m * scale_frequency)
        s = cp.sum(h * c)
        h /= s

    return h
예제 #6
0
 def test_sinc_zero(self, dtype):
     a = cupy.sinc(cupy.zeros(1, dtype=dtype))
     testing.assert_array_equal(a, cupy.ones(1, dtype=dtype))