def __init__(self, space, wavelet, nlevels, variant, pad_mode='constant', pad_const=0, impl='pywt', axes=None): """Initialize a new instance. Parameters ---------- space : `DiscreteLp` Domain of the forward wavelet transform (the "image domain"). In the case of ``variant in ('inverse', 'adjoint')``, this space is the range of the operator. wavelet : string or `pywt.Wavelet` Specification of the wavelet to be used in the transform. If a string is given, it is converted to a `pywt.Wavelet`. Use `pywt.wavelist` to get a list of available wavelets. Possible wavelet families are: ``'haar'``: Haar ``'db'``: Daubechies ``'sym'``: Symlets ``'coif'``: Coiflets ``'bior'``: Biorthogonal ``'rbio'``: Reverse biorthogonal ``'dmey'``: Discrete FIR approximation of the Meyer wavelet variant : {'forward', 'inverse', 'adjoint'} Wavelet transform variant to be created. nlevels : positive int, optional Number of scaling levels to be used in the decomposition. The maximum number of levels can be calculated with `pywt.dwtn_max_level`. Default: Use maximum number of levels. pad_mode : string, optional Method to be used to extend the signal. ``'constant'``: Fill with ``pad_const``. ``'symmetric'``: Reflect at the boundaries, not repeating the outmost values. ``'periodic'``: Fill in values from the other side, keeping the order. ``'order0'``: Extend constantly with the outmost values (ensures continuity). ``'order1'``: Extend with constant slope (ensures continuity of the first derivative). This requires at least 2 values along each axis where padding is applied. ``'pywt_per'``: like ``'periodic'``-padding but gives the smallest possible number of decomposition coefficients. Only available with ``impl='pywt'``, See ``pywt.Modes.modes``. ``'reflect'``: Reflect at the boundary, without repeating the outmost values. ``'antisymmetric'``: Anti-symmetric variant of ``symmetric``. ``'antireflect'``: Anti-symmetric variant of ``reflect``. For reference, the following table compares the naming conventions for the modes in ODL vs. PyWavelets:: ======================= ================== ODL PyWavelets ======================= ================== symmetric symmetric reflect reflect order1 smooth order0 constant constant, pad_const=0 zero periodic periodic pywt_per periodization antisymmetric antisymmetric antireflect antireflect ======================= ================== See `signal extension modes`_ for an illustration of the modes (under the PyWavelets naming conventions). pad_const : float, optional Constant value to use if ``pad_mode == 'constant'``. Ignored otherwise. Constants other than 0 are not supported by the ``pywt`` back-end. impl : {'pywt'}, optional Back-end for the wavelet transform. axes : sequence of ints, optional Axes over which the DWT that created ``coeffs`` was performed. The default value of ``None`` corresponds to all axes. When not all axes are included this is analagous to a batch transform in ``len(axes)`` dimensions looped over the non-transformed axes. In orther words, filtering and decimation does not occur along any axes not in ``axes``. References ---------- .. _signal extension modes: https://pywavelets.readthedocs.io/en/latest/ref/signal-extension-modes.html """ if not isinstance(space, DiscreteLp): raise TypeError('`space` {!r} is not a `DiscreteLp` instance.' ''.format(space)) self.__impl, impl_in = str(impl).lower(), impl if self.impl not in _SUPPORTED_WAVELET_IMPLS: raise ValueError("`impl` '{}' not supported".format(impl_in)) if axes is None: axes = tuple(range(space.ndim)) elif np.isscalar(axes): axes = (axes, ) elif len(axes) > space.ndim: raise ValueError("Too many axes.") self.axes = tuple(axes) if nlevels is None: nlevels = pywt.dwtn_max_level(space.shape, wavelet, self.axes) self.__nlevels, nlevels_in = int(nlevels), nlevels if self.nlevels != nlevels_in: raise ValueError('`nlevels` must be integer, got {}' ''.format(nlevels_in)) self.__impl, impl_in = str(impl).lower(), impl if self.impl not in _SUPPORTED_WAVELET_IMPLS: raise ValueError("`impl` '{}' not supported".format(impl_in)) self.__wavelet = getattr(wavelet, 'name', str(wavelet).lower()) self.__pad_mode = str(pad_mode).lower() self.__pad_const = space.field.element(pad_const) if self.impl == 'pywt': self.pywt_pad_mode = pywt_pad_mode(pad_mode, pad_const) self.pywt_wavelet = pywt_wavelet(self.wavelet) # determine coefficient shapes (without running wavedecn) self._coeff_shapes = pywt.wavedecn_shapes(space.shape, wavelet, mode=self.pywt_pad_mode, level=self.nlevels, axes=self.axes) # precompute slices into the (raveled) coeffs self._coeff_slices = precompute_raveled_slices(self._coeff_shapes) coeff_size = pywt.wavedecn_size(self._coeff_shapes) coeff_space = space.tspace_type(coeff_size, dtype=space.dtype) else: raise RuntimeError("bad `impl` '{}'".format(self.impl)) variant, variant_in = str(variant).lower(), variant if variant not in ('forward', 'inverse', 'adjoint'): raise ValueError("`variant` '{}' not understood" "".format(variant_in)) self.__variant = variant if variant == 'forward': super(WaveletTransformBase, self).__init__(domain=space, range=coeff_space, linear=True) else: super(WaveletTransformBase, self).__init__(domain=coeff_space, range=space, linear=True)
def __init__(self, space, wavelet, nlevels, variant, pad_mode='constant', pad_const=0, impl='pywt'): """Initialize a new instance. Parameters ---------- space : `DiscreteLp` Domain of the forward wavelet transform (the "image domain"). In the case of ``variant in ('inverse', 'adjoint')``, this space is the range of the operator. wavelet : string or `pywt.Wavelet` Specification of the wavelet to be used in the transform. If a string is given, it is converted to a `pywt.Wavelet`. Use `pywt.wavelist` to get a list of available wavelets. Possible wavelet families are: ``'haar'``: Haar ``'db'``: Daubechies ``'sym'``: Symlets ``'coif'``: Coiflets ``'bior'``: Biorthogonal ``'rbio'``: Reverse biorthogonal ``'dmey'``: Discrete FIR approximation of the Meyer wavelet variant : {'forward', 'inverse', 'adjoint'} Wavelet transform variant to be created. nlevels : positive int, optional Number of scaling levels to be used in the decomposition. The maximum number of levels can be calculated with `pywt.dwt_max_level`. Default: Use maximum number of levels. pad_mode : string, optional Method to be used to extend the signal. ``'constant'``: Fill with ``pad_const``. ``'symmetric'``: Reflect at the boundaries, not doubling the outmost values. ``'periodic'``: Fill in values from the other side, keeping the order. ``'order0'``: Extend constantly with the outmost values (ensures continuity). ``'order1'``: Extend with constant slope (ensures continuity of the first derivative). This requires at least 2 values along each axis where padding is applied. ``'pywt_per'``: like ``'periodic'``-padding but gives the smallest possible number of decomposition coefficients. Only available with ``impl='pywt'``, See `pywt.MODES.modes`. pad_const : float, optional Constant value to use if ``pad_mode == 'constant'``. Ignored otherwise. Constants other than 0 are not supported by the ``pywt`` back-end. impl : {'pywt'}, optional Back-end for the wavelet transform. """ if not isinstance(space, DiscreteLp): raise TypeError('`space` {!r} is not a `DiscreteLp` instance.' ''.format(space)) if nlevels is None: nlevels = pywt_max_nlevels(space.shape, wavelet) self.__nlevels, nlevels_in = int(nlevels), nlevels if self.nlevels != nlevels_in: raise ValueError('`nlevels` must be integer, got {}' ''.format(nlevels_in)) self.__impl, impl_in = str(impl).lower(), impl if self.impl not in _SUPPORTED_WAVELET_IMPLS: raise ValueError("`impl` '{}' not supported".format(impl_in)) self.__wavelet = getattr(wavelet, 'name', str(wavelet).lower()) self.__pad_mode = str(pad_mode).lower() self.__pad_const = space.field.element(pad_const) if self.impl == 'pywt': self.pywt_pad_mode = pywt_pad_mode(pad_mode, pad_const) self.pywt_wavelet = pywt_wavelet(self.wavelet) coeff_size = pywt_flat_coeff_size(space.shape, wavelet, self.nlevels, self.pywt_pad_mode) coeff_space = space.dspace_type(coeff_size, dtype=space.dtype) else: raise RuntimeError("bad `impl` '{}'".format(self.impl)) variant, variant_in = str(variant).lower(), variant if variant not in ('forward', 'inverse', 'adjoint'): raise ValueError("`variant` '{}' not understood" "".format(variant_in)) self.__variant = variant if variant == 'forward': super().__init__(domain=space, range=coeff_space, linear=True) else: super().__init__(domain=coeff_space, range=space, linear=True)
def test_pywt_pad_errors(): with pytest.raises(ValueError): pywt_pad_mode('constant', pad_const=1.) with pytest.raises(ValueError): pywt_pad_mode('invalid mode')
def __init__(self, space, wavelet, nlevels, variant, pad_mode='constant', pad_const=0, impl='pywt'): """Initialize a new instance. Parameters ---------- space : `DiscreteLp` Domain of the forward wavelet transform (the "image domain"). In the case of ``variant in ('inverse', 'adjoint')``, this space is the range of the operator. wavelet : string or `pywt.Wavelet` Specification of the wavelet to be used in the transform. If a string is given, it is converted to a `pywt.Wavelet`. Use `pywt.wavelist` to get a list of available wavelets. Possible wavelet families are: ``'haar'``: Haar ``'db'``: Daubechies ``'sym'``: Symlets ``'coif'``: Coiflets ``'bior'``: Biorthogonal ``'rbio'``: Reverse biorthogonal ``'dmey'``: Discrete FIR approximation of the Meyer wavelet nlevels : positive int Number of scaling levels to be used in the decomposition. The maximum number of levels can be calculated with `pywt.dwt_max_level`. variant : {'forward', 'inverse', 'adjoint'} Wavelet transform variant to be created. pad_mode : string, optional Method to be used to extend the signal. ``'constant'``: Fill with ``pad_const``. ``'symmetric'``: Reflect at the boundaries, not doubling the outmost values. ``'periodic'``: Fill in values from the other side, keeping the order. ``'order0'``: Extend constantly with the outmost values (ensures continuity). ``'order1'``: Extend with constant slope (ensures continuity of the first derivative). This requires at least 2 values along each axis where padding is applied. ``'pywt_per'``: like ``'periodic'``-padding but gives the smallest possible number of decomposition coefficients. Only available with ``impl='pywt'``, See `pywt.MODES.modes`. pad_const : float, optional Constant value to use if ``pad_mode == 'constant'``. Ignored otherwise. Constants other than 0 are not supported by the ``pywt`` back-end. impl : {'pywt'}, optional Back-end for the wavelet transform. """ if not isinstance(space, DiscreteLp): raise TypeError('`space` {!r} is not a `DiscreteLp` instance.' ''.format(space)) self.__nlevels, nlevels_in = int(nlevels), nlevels if self.nlevels != nlevels_in: raise ValueError('`nlevels` must be integer, got {}' ''.format(nlevels_in)) self.__impl, impl_in = str(impl).lower(), impl if self.impl not in _SUPPORTED_WAVELET_IMPLS: raise ValueError("`impl` '{}' not supported".format(impl_in)) self.__wavelet = getattr(wavelet, 'name', str(wavelet).lower()) self.__pad_mode = str(pad_mode).lower() self.__pad_const = space.field.element(pad_const) if self.impl == 'pywt': self.pywt_pad_mode = pywt_pad_mode(pad_mode, pad_const) self.pywt_wavelet = pywt_wavelet(self.wavelet) coeff_size = pywt_flat_coeff_size(space.shape, wavelet, self.nlevels, self.pywt_pad_mode) coeff_space = space.dspace_type(coeff_size, dtype=space.dtype) else: raise RuntimeError("bad `impl` '{}'".format(self.impl)) variant, variant_in = str(variant).lower(), variant if variant not in ('forward', 'inverse', 'adjoint'): raise ValueError("`variant` '{}' not understood" "".format(variant_in)) self.__variant = variant if variant == 'forward': super().__init__(domain=space, range=coeff_space, linear=True) else: super().__init__(domain=coeff_space, range=space, linear=True)
def test_pywt_pad_mode(odl_mode): pywt_mode = pywt_pad_mode(odl_mode) assert pywt_mode in list(PAD_MODES_ODL2PYWT.values())