Ejemplo n.º 1
0
def _level1_xfm_no_highpass(X, h0o, h1o, ext_mode):
    """Perform level 1 of the 3d transform discarding highpass subbands.

    """
    # Check shape of input according to ext_mode. Note that shape of X is
    # double original input in each direction.
    if ext_mode == 4 and np.any(np.fmod(X.shape, 2) != 0):
        raise ValueError('Input shape should be a multiple of 2 in each direction when ext_mode == 4')
    elif ext_mode == 8 and np.any(np.fmod(X.shape, 4) != 0):
        raise ValueError('Input shape should be a multiple of 4 in each direction when ext_mode == 8')

    out = np.zeros_like(X)

    # Loop over 2nd dimension extracting 2D slice from first and 3rd dimensions
    for f in xrange(X.shape[1]):
        # extract slice
        y = X[:, f, :].T
        out[:, f, :] = colfilter(y, h0o).T

    # Loop over 3rd dimension extracting 2D slice from first and 2nd dimensions
    for f in xrange(X.shape[2]):
        y = colfilter(out[:, :, f].T, h0o).T
        out[:, :, f] = colfilter(y, h0o)

    return out
Ejemplo n.º 2
0
def _level1_ifm_no_highpass(Yl, g0o, g1o):
    """Perform level 1 of the inverse 3d transform assuming highpass
    coefficients are zero.

    """
    # Create work area
    output = np.zeros_like(Yl)

    for f in xrange(Yl.shape[2]):
        y = colfilter(Yl[:, :, f].T, g0o)
        output[:, :, f] = colfilter(y.T, g0o)

    for f in xrange(Yl.shape[1]):
        y = output[:, f, :].T.copy()
        output[:, f, :] = colfilter(y, g0o)

    return output
Ejemplo n.º 3
0
def _level1_ifm(Yl, Yh, g0o, g1o):
    """Perform level 1 of the inverse 3d transform.

    """
    # Create work area
    work = np.zeros(np.asanyarray(Yl.shape) * 2, dtype=Yl.dtype)

    # Work out shape of output
    Xshape = np.asanyarray(work.shape) >> 1
    if g0o.shape[0] % 2 == 0:
        # if we have an even length filter, we need to shrink the output by 1
        # to compensate for the addition of an extra row/column/slice in 
        # the forward transform
        Xshape -= 1

    # Form some useful slices
    s0a = slice(None, work.shape[0] >> 1)
    s1a = slice(None, work.shape[1] >> 1)
    s2a = slice(None, work.shape[2] >> 1)
    s0b = slice(work.shape[0] >> 1, None)
    s1b = slice(work.shape[1] >> 1, None)
    s2b = slice(work.shape[2] >> 1, None)

    x0a = slice(None, Xshape[0])
    x1a = slice(None, Xshape[1])
    x2a = slice(None, Xshape[2])
    x0b = slice(work.shape[0] >> 1, (work.shape[0] >> 1) + Xshape[0])
    x1b = slice(work.shape[1] >> 1, (work.shape[1] >> 1) + Xshape[1])
    x2b = slice(work.shape[2] >> 1, (work.shape[2] >> 1) + Xshape[2])

    # Assign regions of work area
    work[s0a, s1a, s2a] = Yl
    work[x0a, x1b, x2a] = c2cube(Yh[:,:,:, 0:4 ])
    work[x0b, x1a, x2a] = c2cube(Yh[:,:,:, 4:8 ])
    work[x0b, x1b, x2a] = c2cube(Yh[:,:,:, 8:12])
    work[x0a, x1a, x2b] = c2cube(Yh[:,:,:,12:16])
    work[x0a, x1b, x2b] = c2cube(Yh[:,:,:,16:20])
    work[x0b, x1a, x2b] = c2cube(Yh[:,:,:,20:24])
    work[x0b, x1b, x2b] = c2cube(Yh[:,:,:,24:28])

    for f in xrange(work.shape[2]):
        # Do odd top-level filters on rows.
        y = colfilter(work[:, x1a, f].T, g0o) + colfilter(work[:, x1b, f].T, g1o)

        # Do odd top-level filters on columns.
        work[s0a, s1a, f] = colfilter(y[:, x0a].T, g0o) + colfilter(y[:, x0b].T, g1o)

    for f in xrange(work.shape[1]>>1):
        # Do odd top-level filters on 3rd dim.
        y = work[s0a, f, :].T
        work[s0a, f, s2a] = (colfilter(y[x2a, :], g0o) + colfilter(y[x2b, :], g1o)).T

    if g0o.shape[0] % 2 == 0:
        return work[1:(work.shape[0]>>1), 1:(work.shape[1]>>1), 1:(work.shape[2]>>1)]
    else:
        return work[s0a, s1a, s2a]
Ejemplo n.º 4
0
def test_odd_size_non_array():
    y = colfilter(lena.tolist(), (-1, 2, -1))
    assert y.shape == lena.shape
Ejemplo n.º 5
0
def test_even_size():
    y = colfilter(np.zeros_like(lena), (-1, 1))
    assert y.shape == (lena.shape[0] + 1, lena.shape[1])
    assert not np.any(y[:] != 0.0)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
def test_odd_size_non_array():
    y = colfilter(lena.tolist(), (-1,2,-1))
    assert y.shape == lena.shape
Ejemplo n.º 9
0
def test_biort():
    y = colfilter(lena, biort('antonini')[0])
    assert y.shape == lena.shape
Ejemplo n.º 10
0
def test_odd_size():
    y = colfilter(lena, (-1,2,-1))
    assert y.shape == lena.shape
Ejemplo n.º 11
0
def _level1_xfm(X, h0o, h1o, ext_mode):
    """Perform level 1 of the 3d transform.

    """
    # Check shape of input according to ext_mode. Note that shape of X is
    # double original input in each direction.
    if ext_mode == 4 and np.any(np.fmod(X.shape, 2) != 0):
        raise ValueError('Input shape should be a multiple of 2 in each direction when ext_mode == 4')
    elif ext_mode == 8 and np.any(np.fmod(X.shape, 4) != 0):
        raise ValueError('Input shape should be a multiple of 4 in each direction when ext_mode == 8')

    # Create work area
    work_shape = np.asanyarray(X.shape) * 2

    # We need one extra row per octant if filter length is even
    if h0o.shape[0] % 2 == 0:
        work_shape += 2

    work = np.zeros(work_shape, dtype=X.dtype)

    # Form some useful slices
    s0a = slice(None, work.shape[0] >> 1)
    s1a = slice(None, work.shape[1] >> 1)
    s2a = slice(None, work.shape[2] >> 1)
    s0b = slice(work.shape[0] >> 1, None)
    s1b = slice(work.shape[1] >> 1, None)
    s2b = slice(work.shape[2] >> 1, None)

    x0a = slice(None, X.shape[0])
    x1a = slice(None, X.shape[1])
    x2a = slice(None, X.shape[2])
    x0b = slice(work.shape[0] >> 1, (work.shape[0] >> 1) + X.shape[0])
    x1b = slice(work.shape[1] >> 1, (work.shape[1] >> 1) + X.shape[1])
    x2b = slice(work.shape[2] >> 1, (work.shape[2] >> 1) + X.shape[2])

    # Assign input
    if h0o.shape[0] % 2 == 0:
        work[:X.shape[0], :X.shape[1], :X.shape[2]] = X
        
        # Copy last rows/cols/slices
        work[ X.shape[0], :X.shape[1], :X.shape[2]] = X[-1, :, :]
        work[:X.shape[0],  X.shape[1], :X.shape[2]] = X[:, -1, :]
        work[:X.shape[0], :X.shape[1],  X.shape[2]] = X[:, :, -1]
        work[X.shape[0], X.shape[1], X.shape[2]] = X[-1,-1,-1]
    else:
        work[s0a, s1a, s2a] = X

    # Loop over 2nd dimension extracting 2D slice from first and 3rd dimensions
    for f in xrange(work.shape[1] >> 1):
        # extract slice
        y = work[s0a, f, x2a].T

        # Do odd top-level filters on 3rd dim. The order here is important
        # since the second filtering will modify the elements of y as well
        # since y is merely a view onto work.
        work[s0a, f, s2b] = colfilter(y, h1o).T
        work[s0a, f, s2a] = colfilter(y, h0o).T

    # Loop over 3rd dimension extracting 2D slice from first and 2nd dimensions
    for f in xrange(work.shape[2]):
        # Do odd top-level filters on rows.
        y1 = work[x0a, x1a, f].T
        y2 = np.vstack((colfilter(y1, h0o), colfilter(y1, h1o))).T

        # Do odd top-level filters on columns.
        work[s0a, :, f] = colfilter(y2, h0o)
        work[s0b, :, f] = colfilter(y2, h1o)

    # Return appropriate slices of output
    return (
        work[s0a, s1a, s2a],                # LLL
        np.concatenate((
            cube2c(work[x0a, x1b, x2a]),    # HLL
            cube2c(work[x0b, x1a, x2a]),    # LHL
            cube2c(work[x0b, x1b, x2a]),    # HHL
            cube2c(work[x0a, x1a, x2b]),    # LLH
            cube2c(work[x0a, x1b, x2b]),    # HLH
            cube2c(work[x0b, x1a, x2b]),    # LHH
            cube2c(work[x0b, x1b, x2b]),    # HLH
        ), axis=3)
    )
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
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)
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
def test_even_size_non_array():
    y = colfilter(lena.tolist(), (-1, 1))
    assert y.shape == (lena.shape[0] + 1, lena.shape[1])
Ejemplo n.º 17
0
def test_even_size():
    y = colfilter(lena, (-1,1))
    assert y.shape == (lena.shape[0]+1, lena.shape[1])
Ejemplo n.º 18
0
def test_even_size():
    y = colfilter(lena, (-1, 1))
    assert y.shape == (lena.shape[0] + 1, lena.shape[1])
Ejemplo n.º 19
0
def test_qshift():
    y = colfilter(lena, qshift('qshift_a')[0])
    assert y.shape == (lena.shape[0]+1, lena.shape[1])
Ejemplo n.º 20
0
def test_odd_size():
    y = colfilter(lena, (-1, 2, -1))
    assert y.shape == lena.shape
Ejemplo n.º 21
0
def test_even_size():
    y = colfilter(np.zeros_like(lena), (-1,1))
    assert y.shape == (lena.shape[0]+1, lena.shape[1])
    assert not np.any(y[:] != 0.0)
Ejemplo n.º 22
0
def test_qshift():
    y = colfilter(lena, qshift('qshift_a')[0])
    assert y.shape == (lena.shape[0] + 1, lena.shape[1])
Ejemplo n.º 23
0
def test_even_size_non_array():
    y = colfilter(lena.tolist(), (-1,1))
    assert y.shape == (lena.shape[0]+1, lena.shape[1])
Ejemplo n.º 24
0
def test_biort():
    y = colfilter(lena, biort('antonini')[0])
    assert y.shape == lena.shape
Ejemplo n.º 25
0
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
Ejemplo n.º 26
0
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)