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
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
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
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])
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
def test_sinc_zero(self, dtype): a = cupy.sinc(cupy.zeros(1, dtype=dtype)) testing.assert_array_equal(a, cupy.ones(1, dtype=dtype))