def __init__(self, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT): try: self.biort = _biort(biort) except TypeError: self.biort = biort # Load quarter sample shift wavelets try: self.qshift = _qshift(qshift) except TypeError: self.qshift = qshift
def __init__(self, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT): # Load bi-orthogonal wavelets try: self.biort = _biort(biort) except TypeError: self.biort = biort # Load quarter sample shift wavelets try: self.qshift = _qshift(qshift) except TypeError: self.qshift = qshift
def __init__(self, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, ext_mode=4): # Load bi-orthogonal wavelets try: self.biort = _biort(biort) except TypeError: self.biort = biort # Load quarter sample shift wavelets try: self.qshift = _qshift(qshift) except TypeError: self.qshift = qshift self.ext_mode = ext_mode
def __init__(self, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, ext_mode=4, discard_level_1=False): """ Constructor for the 3D DT-CWT transform class (NumPy). :param biort: Level 1 wavelets to use. See :py:func:`dtcwt.coeffs.biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`dtcwt.coeffs.qshift`. :param discard_level_1: True if level 1 high-pass bands are to be discarded. """ # Load bi-orthogonal wavelets try: self.biort = _biort(biort) except TypeError: self.biort = biort # Load quarter sample shift wavelets try: self.qshift = _qshift(qshift) except TypeError: self.qshift = qshift self.ext_mode = ext_mode self.discard_level_1 = discard_level_1
def forward(self, X, nlevels=3, include_scale=False): """Perform a *n*-level DTCWT decompostion on a 1D column vector *X* (or on the columns of a matrix *X*). :param X: 1D real array or 2D real array whose columns are to be transformed :param nlevels: Number of levels of wavelet decomposition :returns: A :py:class:`DTCWT.Pyramid`-like object representing the transform result. If *biort* or *qshift* are strings, they are used as an argument to the :py:func:`biort` or :py:func:`qshift` functions. Otherwise, they are interpreted as tuples of vectors giving filter coefficients. In the *biort* case, this should be (h0o, g0o, h1o, g1o). In the *qshift* case, this should be (h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b). .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # Which wavelets are to be used? biort = self.biort qshift = self.qshift # Need this because colfilter and friends assumes input is 2d X = asfarray(X) if len(X.shape) == 1: X = np.atleast_2d(X).T # Try to load coefficients if biort is a string parameter try: h0o, g0o, h1o, g1o = _biort(biort) except TypeError: h0o, g0o, h1o, g1o = biort # Try to load coefficients if qshift is a string parameter try: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift) except TypeError: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift L = np.asanyarray(X.shape) # ensure that X is an even length, thus enabling it to be extended if needs be. if X.shape[0] % 2 != 0: raise ValueError('Size of input X must be a multiple of 2') if nlevels == 0: if include_scale: return Pyramid(X, (), ()) else: return Pyramid(X, ()) # initialise Yh = [ None, ] * nlevels if include_scale: # This is only required if the user specifies scales are to be outputted Yscale = [ None, ] * nlevels # Level 1. Hi = colfilter(X, h1o) Lo = colfilter(X, h0o) Yh[0] = Hi[::2, :] + 1j * Hi[1::2, :] # Convert Hi to complex form. if include_scale: Yscale[0] = Lo # Levels 2 and above. for level in xrange(1, nlevels): # Check to see if height of Lo is divisable by 4, if not extend. if Lo.shape[0] % 4 != 0: Lo = np.vstack((Lo[0, :], Lo, Lo[-1, :])) Hi = coldfilt(Lo, h1b, h1a) Lo = coldfilt(Lo, h0b, h0a) Yh[level] = Hi[::2, :] + 1j * Hi[ 1::2, :] # Convert Hi to complex form. if include_scale: Yscale[level] = Lo Yl = Lo if include_scale: return Pyramid(Yl, Yh, Yscale) else: return Pyramid(Yl, Yh)
def inverse_hu(self, pyramid, gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 1D reconstruction. :param pyramid: A :py:class:`DTCWT.Pyramid`-like object containing the transformed signal. :param gain_mask: Gain to be applied to each subband. :returns: Reconstructed real array. The *l*-th element of *gain_mask* is gain for wavelet subband at level l. If gain_mask[l] == 0, no computation is performed for band *l*. Default *gain_mask* is all ones. Note that *l* is 0-indexed. .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # Which wavelets are to be used? biort = self.biort qshift = self.qshift Yl = pyramid.lowpass Yh = pyramid.highpasses a = len(Yh) # No of levels. if gain_mask is None: gain_mask = np.ones(a) # Default gain_mask. # Try to load coefficients if biort is a string parameter try: h0o, g0o, h1o, g1o = _biort(biort) except TypeError: h0o, g0o, h1o, g1o = biort # Try to load coefficients if qshift is a string parameter try: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift) except TypeError: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift level = a - 1 # No of levels = no of rows in L. if level < 0: # if there are no levels in the input, just return the Yl value return Yl """ 此处可以将 hi Lo 拆开 逐层恢复,考虑到卷积是可拆分的 (x1 + x2) * k = x1 * k + x2 * k """ low_band_signal = np.copy(Yl) high_band_signals = [c2q1d(np.copy(item)) for item in Yh[::-1]] for i in range(level): low_band_signal = colifilt(low_band_signal, g0b, g0a) high_band_signals[i] = colifilt(high_band_signals[i], g1b, g1a) if low_band_signal.shape[0] != high_band_signals[i + 1].shape[0]: low_band_signal = low_band_signal[1:-1, ...] if high_band_signals[i].shape[0] != high_band_signals[i + 1].shape[0]: high_band_signals[i] = high_band_signals[i][1:-1, ...] for j in range(i): high_band_signals[j] = colifilt(high_band_signals[j], g0b, g0a) if high_band_signals[j].shape[0] != high_band_signals[ i + 1].shape[0]: high_band_signals[j] = high_band_signals[j][1:-1, ...] low_band_signal = colfilter(low_band_signal, g0o) high_band_signals[-1] = colfilter(high_band_signals[-1], g1o) for i in range(level): high_band_signals[i] = colfilter(high_band_signals[i], g0o) return low_band_signal, high_band_signals
def _inverse_ops(self, Yl, Yh, gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 1D reconstruction. :param Yl: The lowpass output from a forward transform. Should be a tensorflow variable. :param Yh: The tuple of highpass outputs from a forward transform. Should be tensorflow variables. :param gain_mask: Gain to be applied to each subband. :returns: A tf.Variable holding the output The *l*-th element of *gain_mask* is gain for wavelet subband at level l. If gain_mask[l] == 0, no computation is performed for band *l*. Default *gain_mask* is all ones. Note that *l* is 0-indexed. .. codeauthor:: Fergal Cotter <*****@*****.**>, Sep 2017 .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # Which wavelets are to be used? biort = self.biort qshift = self.qshift a = len(Yh) # No of levels. if gain_mask is None: gain_mask = np.ones(a) # Default gain_mask. gain_mask = np.array(gain_mask) # Try to load coefficients if biort is a string parameter try: h0o, g0o, h1o, g1o = _biort(biort) except TypeError: h0o, g0o, h1o, g1o = biort # Try to load coefficients if qshift is a string parameter try: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift) except TypeError: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift level = a-1 # No of levels = no of rows in L. if level < 0: # if there are no levels in the input, just return the Yl value return Yl # Reconstruct levels 2 and above in reverse order. Lo = Yl while level >= 1: Hi = c2q1d(Yh[level]*gain_mask[level]) Lo = colifilt(Lo, g0b, g0a) + colifilt(Hi, g1b, g1a) # If Lo is not the same length as the next Therefore we have to clip # Lo so it is the same height as the next Yh. Yh => t1 was extended. Lo_shape = Lo.get_shape().as_list() next_shape = Yh[level-1].get_shape().as_list() if Lo_shape[1] != 2 * next_shape[1]: Lo = Lo[:,1:-1] Lo_shape = Lo.get_shape().as_list() # Check the row shapes across the entire matrix if (np.any(np.asanyarray(Lo_shape[1:]) != np.asanyarray(next_shape[1:] * np.array((2,1))))): raise ValueError('Yh sizes are not valid for DTWAVEIFM') level -= 1 # Reconstruct level 1. if level == 0: Hi = c2q1d(Yh[level]*gain_mask[level]) Z = colfilter(Lo,g0o) + colfilter(Hi,g1o) return Z
def _forward_ops(self, X, nlevels=3): """ Perform a *n*-level DTCWT-2D decompostion on a 2D matrix *X*. For column inputs, we still need the input shape to be 3D, but with 1 as the last dimension. :param X: 3D real array of size [batch, h, w] :param nlevels: Number of levels of wavelet decomposition :param extended: True if a singleton dimension was added at the beginning of the input. Signal to remove afterwards. :returns: A tuple of Yl, Yh, Yscale """ biort = self.biort qshift = self.qshift # Try to load coefficients if biort is a string parameter try: h0o, g0o, h1o, g1o = _biort(biort) except TypeError: h0o, g0o, h1o, g1o = biort # Try to load coefficients if qshift is a string parameter try: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift) except TypeError: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift # Check the shape and form of the input if X.dtype not in tf_dtypes: raise ValueError('X needs to be a tf variable or placeholder') original_size = X.get_shape().as_list()[1:] # ############################ Resize ################################# # The next few lines of code check to see if the image is odd in size, # if so an extra ... row/column will be added to the bottom/right of the # image # initial_row_extend = 0 # initial_col_extend = 0 # If the row count of X is not divisible by 2 then we need to # extend X by adding a row at the bottom if original_size[0] % 2 != 0: # X = tf.pad(X, [[0, 0], [0, 1], [0, 0]], 'SYMMETRIC') raise ValueError('Size of input X must be a multiple of 2') # extended_size = X.get_shape().as_list()[1:] if nlevels == 0: return X, (), () # ########################### Initialise ############################### Yh = [None, ] * nlevels # This is only required if the user specifies a third output # component. Yscale = [None, ] * nlevels # ############################ Level 1 ################################# # Uses the biorthogonal filters if nlevels >= 1: # Do odd top-level filters on cols. Hi = colfilter(X, h1o) Lo = colfilter(X, h0o) # Convert Hi to complex form by taking alternate rows Yh[0] = tf.cast(Hi[:,::2,:], tf.complex64) + \ 1j*tf.cast(Hi[:,1::2,:], tf.complex64) Yscale[0] = Lo # ############################ Level 2+ ################################ # Uses the qshift filters for level in xrange(1, nlevels): # If the row count of Lo is not divisible by 4 (it will be # divisible by 2), add 2 extra rows to make it so if Lo.get_shape().as_list()[1] % 4 != 0: Lo = tf.pad(Lo, [[0, 0], [1, 1], [0, 0]], 'SYMMETRIC') # Do even Qshift filters on cols. Hi = coldfilt(Lo, h1b, h1a) Lo = coldfilt(Lo, h0b, h0a) # Convert Hi to complex form by taking alternate rows Yh[level] = tf.cast(Hi[:,::2,:], tf.complex64) + \ 1j * tf.cast(Hi[:,1::2,:], tf.complex64) Yscale[level] = Lo Yl = Lo return Yl, tuple(Yh), tuple(Yscale)
def forward(self, X, nlevels=3, include_scale=False): """Perform a *n*-level DTCWT decompostion on a 1D column vector *X* (or on the columns of a matrix *X*). :param X: 1D real array or 2D real array whose columns are to be transformed :param nlevels: Number of levels of wavelet decomposition :returns: A :py:class:`dtcwt.Pyramid`-like object representing the transform result. If *biort* or *qshift* are strings, they are used as an argument to the :py:func:`biort` or :py:func:`qshift` functions. Otherwise, they are interpreted as tuples of vectors giving filter coefficients. In the *biort* case, this should be (h0o, g0o, h1o, g1o). In the *qshift* case, this should be (h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b). .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # Which wavelets are to be used? biort = self.biort qshift = self.qshift # Need this because colfilter and friends assumes input is 2d X = asfarray(X) if len(X.shape) == 1: X = np.atleast_2d(X).T # Try to load coefficients if biort is a string parameter try: h0o, g0o, h1o, g1o = _biort(biort) except TypeError: h0o, g0o, h1o, g1o = biort # Try to load coefficients if qshift is a string parameter try: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift) except TypeError: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift L = np.asanyarray(X.shape) # ensure that X is an even length, thus enabling it to be extended if needs be. if X.shape[0] % 2 != 0: raise ValueError("Size of input X must be a multiple of 2") if nlevels == 0: if include_scale: return Pyramid(X, (), ()) else: return Pyramid(X, ()) # initialise Yh = [None] * nlevels if include_scale: # This is only required if the user specifies scales are to be outputted Yscale = [None] * nlevels # Level 1. Hi = colfilter(X, h1o) Lo = colfilter(X, h0o) Yh[0] = Hi[::2, :] + 1j * Hi[1::2, :] # Convert Hi to complex form. if include_scale: Yscale[0] = Lo # Levels 2 and above. for level in xrange(1, nlevels): # Check to see if height of Lo is divisable by 4, if not extend. if Lo.shape[0] % 4 != 0: Lo = np.vstack((Lo[0, :], Lo, Lo[-1, :])) Hi = coldfilt(Lo, h1b, h1a) Lo = coldfilt(Lo, h0b, h0a) Yh[level] = Hi[::2, :] + 1j * Hi[1::2, :] # Convert Hi to complex form. if include_scale: Yscale[level] = Lo Yl = Lo if include_scale: return Pyramid(Yl, Yh, Yscale) else: return Pyramid(Yl, Yh)
def inverse(self, pyramid, gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 1D reconstruction. :param pyramid: A :py:class:`dtcwt.Pyramid`-like object containing the transformed signal. :param gain_mask: Gain to be applied to each subband. :returns: Reconstructed real array. The *l*-th element of *gain_mask* is gain for wavelet subband at level l. If gain_mask[l] == 0, no computation is performed for band *l*. Default *gain_mask* is all ones. Note that *l* is 0-indexed. .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # Which wavelets are to be used? biort = self.biort qshift = self.qshift Yl = pyramid.lowpass Yh = pyramid.highpasses a = len(Yh) # No of levels. if gain_mask is None: gain_mask = np.ones(a) # Default gain_mask. # Try to load coefficients if biort is a string parameter try: h0o, g0o, h1o, g1o = _biort(biort) except TypeError: h0o, g0o, h1o, g1o = biort # Try to load coefficients if qshift is a string parameter try: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift) except TypeError: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift level = a - 1 # No of levels = no of rows in L. if level < 0: # if there are no levels in the input, just return the Yl value return Yl Lo = Yl while level >= 1: # Reconstruct levels 2 and above in reverse order. Hi = c2q1d(Yh[level] * gain_mask[level]) Lo = colifilt(Lo, g0b, g0a) + colifilt(Hi, g1b, g1a) if ( Lo.shape[0] != 2 * Yh[level - 1].shape[0] ): # If Lo is not the same length as the next Yh => t1 was extended. Lo = Lo[1:-1, ...] # Therefore we have to clip Lo so it is the same height as the next Yh. if np.any(np.asanyarray(Lo.shape) != np.asanyarray(Yh[level - 1].shape * np.array((2, 1)))): raise ValueError("Yh sizes are not valid for DTWAVEIFM") level -= 1 if level == 0: # Reconstruct level 1. Hi = c2q1d(Yh[level] * gain_mask[level]) Z = colfilter(Lo, g0o) + colfilter(Hi, g1o) # Return a 1d vector or a column vector if Z.shape[1] == 1: return Z.flatten() else: return Z
def inverse(self, pyramid, gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 1D reconstruction. :param pyramid: A :py:class:`dtcwt.Pyramid`-like object containing the transformed signal. :param gain_mask: Gain to be applied to each subband. :returns: Reconstructed real array. The *l*-th element of *gain_mask* is gain for wavelet subband at level l. If gain_mask[l] == 0, no computation is performed for band *l*. Default *gain_mask* is all ones. Note that *l* is 0-indexed. .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # Which wavelets are to be used? biort = self.biort qshift = self.qshift Yl = pyramid.lowpass Yh = pyramid.highpasses a = len(Yh) # No of levels. if gain_mask is None: gain_mask = np.ones(a) # Default gain_mask. # Try to load coefficients if biort is a string parameter try: h0o, g0o, h1o, g1o = _biort(biort) except TypeError: h0o, g0o, h1o, g1o = biort # Try to load coefficients if qshift is a string parameter try: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift) except TypeError: h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = qshift level = a - 1 # No of levels = no of rows in L. if level < 0: # if there are no levels in the input, just return the Yl value return Yl Lo = Yl while level >= 1: # Reconstruct levels 2 and above in reverse order. Hi = c2q1d(Yh[level] * gain_mask[level]) Lo = colifilt(Lo, g0b, g0a) + colifilt(Hi, g1b, g1a) if Lo.shape[0] != 2 * Yh[level - 1].shape[ 0]: # If Lo is not the same length as the next Yh => t1 was extended. Lo = Lo[ 1:-1, ...] # Therefore we have to clip Lo so it is the same height as the next Yh. if np.any( np.asanyarray(Lo.shape) != np.asanyarray( Yh[level - 1].shape * np.array((2, 1)))): raise ValueError('Yh sizes are not valid for DTWAVEIFM') level -= 1 if level == 0: # Reconstruct level 1. Hi = c2q1d(Yh[level] * gain_mask[level]) Z = colfilter(Lo, g0o) + colfilter(Hi, g1o) # Return a 1d vector or a column vector if Z.shape[1] == 1: return Z.flatten() else: return Z