def dtwaveifm(Yl, Yh, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 1D reconstruction. :param Yl: The real lowpass subband from the final level :param Yh: A sequence containing the complex highpass subband for each level. :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :param gain_mask: Gain to be applied to each subband. :returns Z: 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. 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). Example:: # Performs a reconstruction from Yl,Yh using the 13,19-tap filters # for level 1 and the Q-shift 14-tap filters for levels >= 2. Z = dtwaveifm(Yl, Yh, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ 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 dtwaveifm3(Yl, Yh, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, ext_mode=4): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 3D reconstruction. :param Yl: The real lowpass subband from the final level :param Yh: A sequence containing the complex highpass subband for each level. :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :param ext_mode: Extension mode. See below. :returns Z: Reconstructed real image matrix. 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). There are two values for *ext_mode*, either 4 or 8. If *ext_mode* = 4, check whether 1st level is divisible by 2 (if not we raise a ``ValueError``). Also check whether from 2nd level onwards, the coefs can be divided by 4. If any dimension size is not a multiple of 4, append extra coefs by repeating the edges. If *ext_mode* = 8, check whether 1st level is divisible by 4 (if not we raise a ``ValueError``). Also check whether from 2nd level onwards, the coeffs can be divided by 8. If any dimension size is not a multiple of 8, append extra coeffs by repeating the edges twice. Example:: # Performs a 3-level reconstruction from Yl,Yh using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Z = dtwaveifm3(Yl, Yh, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Huizhong Chen, Jan 2009 .. codeauthor:: Nick Kingsbury, Cambridge University, July 1999. """ # 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 X = Yl nlevels = len(Yh) # level is 0-indexed but interpreted starting from the *last* level for level in xrange(nlevels): # Transform if level == nlevels-1: # non-obviously this is the 'first' level if Yh[-level-1] is None: Yl = _level1_ifm_no_highpass(Yl, g0o, g1o) else: Yl = _level1_ifm(Yl, Yh[-level-1], g0o, g1o) else: # Gracefully handle the Yh[0] is None case. if Yh[-level-2] is not None: prev_shape = Yh[-level-2].shape else: prev_shape = np.array(Yh[-level-1].shape) * 2 Yl = _level2_ifm(Yl, Yh[-level-1], g0a, g0b, g1a, g1b, ext_mode, prev_shape) return Yl
def dtwavexfm(X, nlevels=3, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, 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 :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :returns Yl: The real lowpass image from the final level :returns Yh: A tuple containing the (N, M, 6) shape complex highpass subimages for each level. :returns Yscale: If *include_scale* is True, a tuple containing real lowpass coefficients for every scale. 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). Example:: # Performs a 5-level transform on the real image X using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Yl, Yh = dtwavexfm(X,5,'near_sym_b','qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # 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 X, (), () else: return 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 Yl, Yh, Yscale else: return Yl, Yh
def dtwavexfm(X, nlevels=3, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, 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 :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :returns Yl: The real lowpass image from the final level :returns Yh: A tuple containing the (N, M, 6) shape complex highpass subimages for each level. :returns Yscale: If *include_scale* is True, a tuple containing real lowpass coefficients for every scale. 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). Example:: # Performs a 5-level transform on the real image X using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Yl, Yh = dtwavexfm(X,5,'near_sym_b','qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ # 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 X, (), () else: return 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 Yl, Yh, Yscale else: return Yl, Yh
def dtwavexfm3(X, nlevels=3, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, ext_mode=4, discard_level_1=False): """Perform a *n*-level DTCWT-3D decompostion on a 3D matrix *X*. :param X: 3D real array-like object :param nlevels: Number of levels of wavelet decomposition :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :param ext_mode: Extension mode. See below. :param discard_level_1: True if level 1 high-pass bands are to be discarded. :returns Yl: The real lowpass image from the final level :returns Yh: A tuple containing the complex highpass subimages for each level. Each element of *Yh* is a 4D complex array with the 4th dimension having size 28. The 3D slice ``Yh[l][:,:,:,d]`` corresponds to the complex higpass coefficients for direction d at level l where d and l are both 0-indexed. 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). There are two values for *ext_mode*, either 4 or 8. If *ext_mode* = 4, check whether 1st level is divisible by 2 (if not we raise a ``ValueError``). Also check whether from 2nd level onwards, the coefs can be divided by 4. If any dimension size is not a multiple of 4, append extra coefs by repeating the edges. If *ext_mode* = 8, check whether 1st level is divisible by 4 (if not we raise a ``ValueError``). Also check whether from 2nd level onwards, the coeffs can be divided by 8. If any dimension size is not a multiple of 8, append extra coeffs by repeating the edges twice. If *discard_level_1* is True the highpass coefficients at level 1 will be discarded. (And, in fact, will never be calculated.) This turns the transform from being 8:1 redundant to being 1:1 redundant at the cost of no-longer allowing perfect reconstruction. If this option is selected then `Yh[0]` will be `None`. Note that :py:func:`dtwaveifm3` will accepts `Yh[0]` being `None` and will treat it as being zero. Example:: # Performs a 3-level transform on the real 3D array X using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Yl, Yh = dtwavexfm3(X, 3, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Huizhong Chen, Jan 2009 .. codeauthor:: Nick Kingsbury, Cambridge University, July 1999. """ X = np.atleast_3d(asfarray(X)) # 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 value of ext_mode. TODO: this should really be an enum :S if ext_mode != 4 and ext_mode != 8: raise ValueError('ext_mode must be one of 4 or 8') Yl = X Yh = [None,] * nlevels # level is 0-indexed for level in xrange(nlevels): # Transform if level == 0 and discard_level_1: Yl = _level1_xfm_no_highpass(Yl, h0o, h1o, ext_mode) elif level == 0 and not discard_level_1: Yl, Yh[level] = _level1_xfm(Yl, h0o, h1o, ext_mode) else: Yl, Yh[level] = _level2_xfm(Yl, h0a, h0b, h1a, h1b, ext_mode) return Yl, tuple(Yh)
def dtwaveifm(Yl, Yh, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 1D reconstruction. :param Yl: The real lowpass subband from the final level :param Yh: A sequence containing the complex highpass subband for each level. :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :param gain_mask: Gain to be applied to each subband. :returns Z: 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. 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). Example:: # Performs a reconstruction from Yl,Yh using the 13,19-tap filters # for level 1 and the Q-shift 14-tap filters for levels >= 2. Z = dtwaveifm(Yl, Yh, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ 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 dtwavexfm2(X, nlevels=3, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, include_scale=False): """Perform a *n*-level DTCWT-2D decompostion on a 2D matrix *X*. :param X: 2D real array :param nlevels: Number of levels of wavelet decomposition :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :returns Yl: The real lowpass image from the final level :returns Yh: A tuple containing the complex highpass subimages for each level. :returns Yscale: If *include_scale* is True, a tuple containing real lowpass coefficients for every scale. 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). Example:: # Performs a 3-level transform on the real image X using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Yl, Yh = dtwavexfm2(X, 3, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, Sept 2001 .. codeauthor:: Cian Shaffrey, Cambridge University, Sept 2001 """ X = np.atleast_2d(asfarray(X)) # 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 original_size = X.shape if len(X.shape) >= 3: raise ValueError('The entered image is {0}, please enter each image slice separately.'. format('x'.join(list(str(s) for s in X.shape)))) # 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 #initialise initial_col_extend = 0 if original_size[0] % 2 != 0: # if X.shape[0] is not divisable by 2 then we need to extend X by adding a row at the bottom X = np.vstack((X, X[[-1],:])) # Any further extension will be done in due course. initial_row_extend = 1 if original_size[1] % 2 != 0: # if X.shape[1] is not divisable by 2 then we need to extend X by adding a col to the left X = np.hstack((X, X[:,[-1]])) initial_col_extend = 1 extended_size = X.shape if nlevels == 0: if include_scale: return X, (), () else: return X, () # initialise Yh = [None,] * nlevels if include_scale: # this is only required if the user specifies a third output component. Yscale = [None,] * nlevels complex_dtype = appropriate_complex_type_for(X) if nlevels >= 1: # Do odd top-level filters on cols. Lo = colfilter(X,h0o).T Hi = colfilter(X,h1o).T # Do odd top-level filters on rows. LoLo = colfilter(Lo,h0o).T Yh[0] = np.zeros((LoLo.shape[0] >> 1, LoLo.shape[1] >> 1, 6), dtype=complex_dtype) Yh[0][:,:,[0, 5]] = q2c(colfilter(Hi,h0o).T) # Horizontal pair Yh[0][:,:,[2, 3]] = q2c(colfilter(Lo,h1o).T) # Vertical pair Yh[0][:,:,[1, 4]] = q2c(colfilter(Hi,h1o).T) # Diagonal pair if include_scale: Yscale[0] = LoLo for level in xrange(1, nlevels): row_size, col_size = LoLo.shape if row_size % 4 != 0: # Extend by 2 rows if no. of rows of LoLo are not divisable by 4 LoLo = np.vstack((LoLo[[0],:], LoLo, LoLo[[-1],:])) if col_size % 4 != 0: # Extend by 2 cols if no. of cols of LoLo are not divisable by 4 LoLo = np.hstack((LoLo[:,[0]], LoLo, LoLo[:,[-1]])) # Do even Qshift filters on rows. Lo = coldfilt(LoLo,h0b,h0a).T Hi = coldfilt(LoLo,h1b,h1a).T # Do even Qshift filters on columns. LoLo = coldfilt(Lo,h0b,h0a).T Yh[level] = np.zeros((LoLo.shape[0]>>1, LoLo.shape[1]>>1, 6), dtype=complex_dtype) Yh[level][:,:,[0, 5]] = q2c(coldfilt(Hi,h0b,h0a).T) # Horizontal Yh[level][:,:,[2, 3]] = q2c(coldfilt(Lo,h1b,h1a).T) # Vertical Yh[level][:,:,[1, 4]] = q2c(coldfilt(Hi,h1b,h1a).T) # Diagonal if include_scale: Yscale[0] = LoLo Yl = LoLo if initial_row_extend == 1 and initial_col_extend == 1: logging.warn('The image entered is now a {0} NOT a {1}.'.format( 'x'.join(list(str(s) for s in extended_size)), 'x'.join(list(str(s) for s in original_size)))) logging.warn( 'The bottom row and rightmost column have been duplicated, prior to decomposition.') if initial_row_extend == 1 and initial_col_extend == 0: logging.warn('The image entered is now a {0} NOT a {1}.'.format( 'x'.join(list(str(s) for s in extended_size)), 'x'.join(list(str(s) for s in original_size)))) logging.warn( 'The bottom row has been duplicated, prior to decomposition.') if initial_row_extend == 0 and initial_col_extend == 1: logging.warn('The image entered is now a {0} NOT a {1}.'.format( 'x'.join(list(str(s) for s in extended_size)), 'x'.join(list(str(s) for s in original_size)))) logging.warn( 'The rightmost column has been duplicated, prior to decomposition.') if include_scale: return Yl, tuple(Yh), tuple(Yscale) else: return Yl, tuple(Yh)
def dtwaveifm2(Yl,Yh,biort=DEFAULT_BIORT,qshift=DEFAULT_QSHIFT,gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 2D reconstruction. :param Yl: The real lowpass subband from the final level :param Yh: A sequence containing the complex highpass subband for each level. :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :param gain_mask: Gain to be applied to each subband. :returns Z: Reconstructed real array The (*d*, *l*)-th element of *gain_mask* is gain for subband with direction *d* at level *l*. If gain_mask[d,l] == 0, no computation is performed for band (d,l). Default *gain_mask* is all ones. Note that both *d* and *l* are zero-indexed. 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). Example:: # Performs a 3-level reconstruction from Yl,Yh using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Z = dtwaveifm2(Yl, Yh, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ a = len(Yh) # No of levels. if gain_mask is None: gain_mask = np.ones((6,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 current_level = a Z = Yl while current_level >= 2: # this ensures that for level 1 we never do the following lh = c2q(Yh[current_level-1][:,:,[0, 5]], gain_mask[[0, 5], current_level-1]) hl = c2q(Yh[current_level-1][:,:,[2, 3]], gain_mask[[2, 3], current_level-1]) hh = c2q(Yh[current_level-1][:,:,[1, 4]], gain_mask[[1, 4], current_level-1]) # Do even Qshift filters on columns. y1 = colifilt(Z,g0b,g0a) + colifilt(lh,g1b,g1a) y2 = colifilt(hl,g0b,g0a) + colifilt(hh,g1b,g1a) # Do even Qshift filters on rows. Z = (colifilt(y1.T,g0b,g0a) + colifilt(y2.T,g1b,g1a)).T # Check size of Z and crop as required [row_size, col_size] = Z.shape S = 2*np.array(Yh[current_level-2].shape) if row_size != S[0]: # check to see if this result needs to be cropped for the rows Z = Z[1:-1,:] if col_size != S[1]: # check to see if this result needs to be cropped for the cols Z = Z[:,1:-1] if np.any(np.array(Z.shape) != S[:2]): raise ValueError('Sizes of subbands are not valid for DTWAVEIFM2') current_level = current_level - 1 if current_level == 1: lh = c2q(Yh[current_level-1][:,:,[0, 5]],gain_mask[[0, 5],current_level-1]) hl = c2q(Yh[current_level-1][:,:,[2, 3]],gain_mask[[2, 3],current_level-1]) hh = c2q(Yh[current_level-1][:,:,[1, 4]],gain_mask[[1, 4],current_level-1]) # Do odd top-level filters on columns. y1 = colfilter(Z,g0o) + colfilter(lh,g1o) y2 = colfilter(hl,g0o) + colfilter(hh,g1o) # Do odd top-level filters on rows. Z = (colfilter(y1.T,g0o) + colfilter(y2.T,g1o)).T return Z
def dtwaveifm2(Yl, Yh, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, gain_mask=None): """Perform an *n*-level dual-tree complex wavelet (DTCWT) 2D reconstruction. :param Yl: The real lowpass subband from the final level :param Yh: A sequence containing the complex highpass subband for each level. :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :param gain_mask: Gain to be applied to each subband. :returns Z: Reconstructed real array The (*d*, *l*)-th element of *gain_mask* is gain for subband with direction *d* at level *l*. If gain_mask[d,l] == 0, no computation is performed for band (d,l). Default *gain_mask* is all ones. Note that both *d* and *l* are zero-indexed. 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). Example:: # Performs a 3-level reconstruction from Yl,Yh using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Z = dtwaveifm2(Yl, Yh, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, May 2002 .. codeauthor:: Cian Shaffrey, Cambridge University, May 2002 """ a = len(Yh) # No of levels. if gain_mask is None: gain_mask = np.ones((6, 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 current_level = a Z = Yl while current_level >= 2: # this ensures that for level 1 we never do the following lh = c2q(Yh[current_level - 1][:, :, [0, 5]], gain_mask[[0, 5], current_level - 1]) hl = c2q(Yh[current_level - 1][:, :, [2, 3]], gain_mask[[2, 3], current_level - 1]) hh = c2q(Yh[current_level - 1][:, :, [1, 4]], gain_mask[[1, 4], current_level - 1]) # Do even Qshift filters on columns. y1 = colifilt(Z, g0b, g0a) + colifilt(lh, g1b, g1a) y2 = colifilt(hl, g0b, g0a) + colifilt(hh, g1b, g1a) # Do even Qshift filters on rows. Z = (colifilt(y1.T, g0b, g0a) + colifilt(y2.T, g1b, g1a)).T # Check size of Z and crop as required [row_size, col_size] = Z.shape S = 2 * np.array(Yh[current_level - 2].shape) if row_size != S[0]: # check to see if this result needs to be cropped for the rows Z = Z[1:-1, :] if col_size != S[1]: # check to see if this result needs to be cropped for the cols Z = Z[:, 1:-1] if np.any(np.array(Z.shape) != S[:2]): raise ValueError("Sizes of subbands are not valid for DTWAVEIFM2") current_level = current_level - 1 if current_level == 1: lh = c2q(Yh[current_level - 1][:, :, [0, 5]], gain_mask[[0, 5], current_level - 1]) hl = c2q(Yh[current_level - 1][:, :, [2, 3]], gain_mask[[2, 3], current_level - 1]) hh = c2q(Yh[current_level - 1][:, :, [1, 4]], gain_mask[[1, 4], current_level - 1]) # Do odd top-level filters on columns. y1 = colfilter(Z, g0o) + colfilter(lh, g1o) y2 = colfilter(hl, g0o) + colfilter(hh, g1o) # Do odd top-level filters on rows. Z = (colfilter(y1.T, g0o) + colfilter(y2.T, g1o)).T return Z
def dtwavexfm2(X, nlevels=3, biort=DEFAULT_BIORT, qshift=DEFAULT_QSHIFT, include_scale=False): """Perform a *n*-level DTCWT-2D decompostion on a 2D matrix *X*. :param X: 2D real array :param nlevels: Number of levels of wavelet decomposition :param biort: Level 1 wavelets to use. See :py:func:`biort`. :param qshift: Level >= 2 wavelets to use. See :py:func:`qshift`. :returns Yl: The real lowpass image from the final level :returns Yh: A tuple containing the complex highpass subimages for each level. :returns Yscale: If *include_scale* is True, a tuple containing real lowpass coefficients for every scale. 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). Example:: # Performs a 3-level transform on the real image X using the 13,19-tap # filters for level 1 and the Q-shift 14-tap filters for levels >= 2. Yl, Yh = dtwavexfm2(X, 3, 'near_sym_b', 'qshift_b') .. codeauthor:: Rich Wareham <*****@*****.**>, Aug 2013 .. codeauthor:: Nick Kingsbury, Cambridge University, Sept 2001 .. codeauthor:: Cian Shaffrey, Cambridge University, Sept 2001 """ X = np.atleast_2d(asfarray(X)) # 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 original_size = X.shape if len(X.shape) >= 3: raise ValueError( "The entered image is {0}, please enter each image slice separately.".format( "x".join(list(str(s) for s in X.shape)) ) ) # 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 # initialise initial_col_extend = 0 if original_size[0] % 2 != 0: # if X.shape[0] is not divisable by 2 then we need to extend X by adding a row at the bottom X = np.vstack((X, X[[-1], :])) # Any further extension will be done in due course. initial_row_extend = 1 if original_size[1] % 2 != 0: # if X.shape[1] is not divisable by 2 then we need to extend X by adding a col to the left X = np.hstack((X, X[:, [-1]])) initial_col_extend = 1 extended_size = X.shape if nlevels == 0: if include_scale: return X, (), () else: return X, () # initialise Yh = [None] * nlevels if include_scale: # this is only required if the user specifies a third output component. Yscale = [None] * nlevels complex_dtype = appropriate_complex_type_for(X) if nlevels >= 1: # Do odd top-level filters on cols. Lo = colfilter(X, h0o).T Hi = colfilter(X, h1o).T # Do odd top-level filters on rows. LoLo = colfilter(Lo, h0o).T Yh[0] = np.zeros((LoLo.shape[0] >> 1, LoLo.shape[1] >> 1, 6), dtype=complex_dtype) Yh[0][:, :, [0, 5]] = q2c(colfilter(Hi, h0o).T) # Horizontal pair Yh[0][:, :, [2, 3]] = q2c(colfilter(Lo, h1o).T) # Vertical pair Yh[0][:, :, [1, 4]] = q2c(colfilter(Hi, h1o).T) # Diagonal pair if include_scale: Yscale[0] = LoLo for level in xrange(1, nlevels): row_size, col_size = LoLo.shape if row_size % 4 != 0: # Extend by 2 rows if no. of rows of LoLo are not divisable by 4 LoLo = np.vstack((LoLo[[0], :], LoLo, LoLo[[-1], :])) if col_size % 4 != 0: # Extend by 2 cols if no. of cols of LoLo are not divisable by 4 LoLo = np.hstack((LoLo[:, [0]], LoLo, LoLo[:, [-1]])) # Do even Qshift filters on rows. Lo = coldfilt(LoLo, h0b, h0a).T Hi = coldfilt(LoLo, h1b, h1a).T # Do even Qshift filters on columns. LoLo = coldfilt(Lo, h0b, h0a).T Yh[level] = np.zeros((LoLo.shape[0] >> 1, LoLo.shape[1] >> 1, 6), dtype=complex_dtype) Yh[level][:, :, [0, 5]] = q2c(coldfilt(Hi, h0b, h0a).T) # Horizontal Yh[level][:, :, [2, 3]] = q2c(coldfilt(Lo, h1b, h1a).T) # Vertical Yh[level][:, :, [1, 4]] = q2c(coldfilt(Hi, h1b, h1a).T) # Diagonal if include_scale: Yscale[0] = LoLo Yl = LoLo if initial_row_extend == 1 and initial_col_extend == 1: logging.warn( "The image entered is now a {0} NOT a {1}.".format( "x".join(list(str(s) for s in extended_size)), "x".join(list(str(s) for s in original_size)) ) ) logging.warn("The bottom row and rightmost column have been duplicated, prior to decomposition.") if initial_row_extend == 1 and initial_col_extend == 0: logging.warn( "The image entered is now a {0} NOT a {1}.".format( "x".join(list(str(s) for s in extended_size)), "x".join(list(str(s) for s in original_size)) ) ) logging.warn("The bottom row has been duplicated, prior to decomposition.") if initial_row_extend == 0 and initial_col_extend == 1: logging.warn( "The image entered is now a {0} NOT a {1}.".format( "x".join(list(str(s) for s in extended_size)), "x".join(list(str(s) for s in original_size)) ) ) logging.warn("The rightmost column has been duplicated, prior to decomposition.") if include_scale: return Yl, tuple(Yh), tuple(Yscale) else: return Yl, tuple(Yh)