[python-dtcwt] 05/497: forward transform implemented

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Tue Jul 21 18:05:42 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch debian/sid
in repository python-dtcwt.

commit ab0b40741e2b125c7a655b3ba2a6460cda296695
Author: Rich Wareham <rjw57 at cam.ac.uk>
Date:   Tue Aug 6 16:10:18 2013 +0100

    forward transform implemented
---
 dtcwt/__init__.py         |   4 +-
 dtcwt/coeffs.py           |  55 +++++++++++
 dtcwt/data/antonini.mat   | Bin 0 -> 608 bytes
 dtcwt/data/legall.mat     | Bin 0 -> 480 bytes
 dtcwt/data/lenna.mat      | Bin 0 -> 77847 bytes
 dtcwt/data/near_sym_a.mat | Bin 0 -> 544 bytes
 dtcwt/data/near_sym_b.mat | Bin 0 -> 864 bytes
 dtcwt/data/qshift_06.mat  | Bin 0 -> 1216 bytes
 dtcwt/data/qshift_32.mat  | Bin 0 -> 2728 bytes
 dtcwt/data/qshift_a.mat   | Bin 0 -> 1216 bytes
 dtcwt/data/qshift_b.mat   | Bin 0 -> 1472 bytes
 dtcwt/data/qshift_c.mat   | Bin 0 -> 1600 bytes
 dtcwt/data/qshift_d.mat   | Bin 0 -> 1728 bytes
 dtcwt/lowlevel.py         | 245 ++++++++++++++++++++++++++++++++++++++++++++++
 dtcwt/reflect.py          |  29 ------
 dtcwt/transform2d.py      | 189 +++++++++++++++++++++++++++++++++++
 setup.py                  |   2 +-
 tests/colifilt.py         |  37 +++++++
 tests/lena.npz            | Bin 0 -> 279987 bytes
 tests/testcoeffs.py       |  79 +++++++++++++++
 tests/testcoldfilt.py     |  40 ++++++++
 tests/testcolfilter.py    |  49 ++++++++++
 tests/testcolifilt.py     |  53 ++++++++++
 tests/testxfm2.py         |  33 +++++++
 24 files changed, 784 insertions(+), 31 deletions(-)

diff --git a/dtcwt/__init__.py b/dtcwt/__init__.py
index d2ac8df..4dd830d 100644
--- a/dtcwt/__init__.py
+++ b/dtcwt/__init__.py
@@ -1 +1,3 @@
-from .reflect import reflect
+from coeffs import biort, qshift
+from lowlevel import colfilter, coldfilt, colifilt, reflect
+from transform2d import dtwavexfm2
diff --git a/dtcwt/coeffs.py b/dtcwt/coeffs.py
new file mode 100644
index 0000000..66697a7
--- /dev/null
+++ b/dtcwt/coeffs.py
@@ -0,0 +1,55 @@
+import os
+from scipy.io import loadmat
+
+DATADIR = os.path.join(os.path.dirname(__file__), 'data')
+
+def _load_from_file(basename, varnames):
+    filename = os.path.join(DATADIR, basename + '.mat')
+    mat = loadmat(filename)
+    try:
+        return tuple(mat[k] for k in varnames)
+    except KeyError:
+        raise ValueError('Wavelet does not define ({0}) coefficients'.format(', '.join(varnames)))
+
+def biort(name):
+    """Load level 1 wavelet by name:
+
+    'antonini'   => Antonini 9,7 tap filters.
+    'legall'     => LeGall 5,3 tap filters.
+    'near_sym_a' => Near-Symmetric 5,7 tap filters.
+    'near_sym_b' => Near-Symmetric 13,19 tap filters.
+
+    Return a tuple whose elements are a vector specifying the h0o, g0o, h1o and
+    g1o coefficients.
+
+    Raises IOError if name does not correspond to a set of wavelets known to
+    the library.
+
+    Raises ValueError if name specifies a qshift wavelet.
+
+    """
+    return _load_from_file(name, ('h0o', 'g0o', 'h1o', 'g1o'))
+
+def qshift(name):
+    """Load level >=2 wavelet by name:
+
+    'qshift_06' => Quarter Sample Shift Orthogonal (Q-Shift) 10,10 tap filters, 
+                   (only 6,6 non-zero taps).
+    'qshift_a'  => Q-shift 10,10 tap filters,
+                   (with 10,10 non-zero taps, unlike qshift_06).
+    'qshift_b'  => Q-Shift 14,14 tap filters.
+    'qshift_c'  => Q-Shift 16,16 tap filters.
+    'qshift_d'  => Q-Shift 18,18 tap filters.
+
+    Return a tuple whose elements are a vector specifying the h0a, h0b, g0a,
+    g0b, h1a, h1b, g1a and g1b coefficients.
+
+    Raises IOError if name does not correspond to a set of wavelets known to
+    the library.
+
+    Raises ValueError if name specifies a biort wavelet.
+
+    """
+    return _load_from_file(name, ('h0a', 'h0b', 'g0a', 'g0b', 'h1a', 'h1b', 'g1a', 'g1b'))
+
+# vim:sw=4:sts=4:et
diff --git a/dtcwt/data/antonini.mat b/dtcwt/data/antonini.mat
new file mode 100644
index 0000000..01f1067
Binary files /dev/null and b/dtcwt/data/antonini.mat differ
diff --git a/dtcwt/data/legall.mat b/dtcwt/data/legall.mat
new file mode 100644
index 0000000..ccd070e
Binary files /dev/null and b/dtcwt/data/legall.mat differ
diff --git a/dtcwt/data/lenna.mat b/dtcwt/data/lenna.mat
new file mode 100644
index 0000000..d3579da
Binary files /dev/null and b/dtcwt/data/lenna.mat differ
diff --git a/dtcwt/data/near_sym_a.mat b/dtcwt/data/near_sym_a.mat
new file mode 100644
index 0000000..2ebb9b8
Binary files /dev/null and b/dtcwt/data/near_sym_a.mat differ
diff --git a/dtcwt/data/near_sym_b.mat b/dtcwt/data/near_sym_b.mat
new file mode 100644
index 0000000..8fb0882
Binary files /dev/null and b/dtcwt/data/near_sym_b.mat differ
diff --git a/dtcwt/data/qshift_06.mat b/dtcwt/data/qshift_06.mat
new file mode 100644
index 0000000..7a3f484
Binary files /dev/null and b/dtcwt/data/qshift_06.mat differ
diff --git a/dtcwt/data/qshift_32.mat b/dtcwt/data/qshift_32.mat
new file mode 100644
index 0000000..f95a592
Binary files /dev/null and b/dtcwt/data/qshift_32.mat differ
diff --git a/dtcwt/data/qshift_a.mat b/dtcwt/data/qshift_a.mat
new file mode 100644
index 0000000..62c06a3
Binary files /dev/null and b/dtcwt/data/qshift_a.mat differ
diff --git a/dtcwt/data/qshift_b.mat b/dtcwt/data/qshift_b.mat
new file mode 100644
index 0000000..d28e855
Binary files /dev/null and b/dtcwt/data/qshift_b.mat differ
diff --git a/dtcwt/data/qshift_c.mat b/dtcwt/data/qshift_c.mat
new file mode 100644
index 0000000..e528e75
Binary files /dev/null and b/dtcwt/data/qshift_c.mat differ
diff --git a/dtcwt/data/qshift_d.mat b/dtcwt/data/qshift_d.mat
new file mode 100644
index 0000000..9de6cdf
Binary files /dev/null and b/dtcwt/data/qshift_d.mat differ
diff --git a/dtcwt/lowlevel.py b/dtcwt/lowlevel.py
new file mode 100644
index 0000000..baba922
--- /dev/null
+++ b/dtcwt/lowlevel.py
@@ -0,0 +1,245 @@
+import numpy as np
+from scipy.signal import convolve2d
+
+def to_vertical_vector(v):
+    """Return v as a 2d vertical vector."""
+    v = np.atleast_2d(v)
+    if v.shape[0] == 1:
+        return v.T
+    else:
+        return v
+
+def reflect(x, minx, maxx):
+    """Reflect the values in matrix x about the scalar values minx and maxx.
+    Hence a vector x containing a long linearly increasing series is converted
+    into a waveform which ramps linearly up and down between minx and maxx.  If
+    x contains integers and minx and maxx are (integers + 0.5), the ramps will
+    have repeated max and min samples.
+   
+    Nick Kingsbury, Cambridge University, January 1999.
+    
+    """
+
+    # Copy x to avoid in-place modification
+    y = np.array(x, copy=True)
+
+    # Reflect y in maxx.
+    y[y > maxx] = 2*maxx - y[y > maxx]
+
+    while np.any(y < minx):
+        # Reflect y in minx.
+        y[y < minx] = 2*minx - y[y < minx]
+
+        # Reflect y in maxx.
+        y[y > maxx] = 2*maxx - y[y > maxx]
+
+    return y
+
+def colfilter(X, h):
+    """Filter the columns of image X using filter vector h, without decimation.
+    If length(h) is odd, each output sample is aligned with each input sample
+    and Y is the same size as X.  If length(h) is even, each output sample is
+    aligned with the mid point of each pair of input samples, and size(Y) =
+    size(X) + [1 0]; 
+
+    Cian Shaffrey, Nick Kingsbury Cambridge University, August 2000
+
+    """
+    
+    # Interpret all inputs as arrays
+    X = np.array(X)
+    h = to_vertical_vector(h)
+
+    r, c = X.shape
+    m = h.shape[0]
+    m2 = np.fix(m*0.5)
+
+    if np.any(np.nonzero(X[:])[0]):
+        # Symmetrically extend with repeat of end samples.
+	# Use 'reflect' so r < m2 works OK.
+        xe = reflect(np.arange(-m2, r+m2, dtype=np.int), -0.5, r-0.5)
+
+        # Perform filtering on the columns of the extended matrix X(xe,:), keeping
+        # only the 'valid' output samples, so Y is the same size as X if m is odd.
+        Y = convolve2d(X[xe,:], h, 'valid')
+    else:
+        Y = np.zeros((r+1-(m%2), c))
+
+    return Y
+
+def coldfilt(X, ha, hb):
+    """Filter the columns of image X using the two filters ha and hb =
+    reverse(ha).  ha operates on the odd samples of X and hb on the even
+    samples.  Both filters should be even length, and h should be approx linear
+    phase with a quarter sample advance from its mid pt (ie |h(m/2)| > |h(m/2 +
+    1)|).
+
+                      ext        top edge                     bottom edge       ext
+    Level 1:        !               |               !               |               !
+    odd filt on .    b   b   b   b   a   a   a   a   a   a   a   a   b   b   b   b   
+    odd filt on .      a   a   a   a   b   b   b   b   b   b   b   b   a   a   a   a
+    Level 2:        !               |               !               |               !
+    +q filt on x      b       b       a       a       a       a       b       b       
+    -q filt on o          a       a       b       b       b       b       a       a
+
+    The output is decimated by two from the input sample rate and the results
+    from the two filters, Ya and Yb, are interleaved to give Y.  Symmetric
+    extension with repeated end samples is used on the composite X columns
+    before each filter is applied.
+
+    Raises ValueError if the number of rows in X is not a multiple of 4, the
+    length of ha does not match hb or the lengths of ha or hb are non-even.
+
+    Cian Shaffrey, Nick Kingsbury Cambridge University, August 2000
+
+    """
+    # Make sure all inputs are arrays
+    X = np.array(X)
+    ha = np.array(ha)
+    hb = np.array(hb)
+
+    r, c = X.shape
+    if r % 4 != 0:
+        raise ValueError('No. of rows in X must be a multiple of 4')
+
+    if ha.shape != hb.shape:
+        raise ValueError('Shapes of ha and hb must be the same')
+
+    if ha.shape[0] % 2 != 0:
+        raise ValueError('Lengths of ha and hb must be even')
+
+    m = ha.shape[0]
+    m2 = np.fix(m*0.5)
+
+    # Set up vector for symmetric extension of X with repeated end samples.
+    xe = reflect(np.arange(-m, r+m), -0.5, r-0.5)
+
+    # Select odd and even samples from ha and hb. Note that due to 0-indexing
+    # 'odd' and 'even' are not perhaps what you might expect them to be.
+    hao = to_vertical_vector(ha[0:m:2])
+    hae = to_vertical_vector(ha[1:m:2])
+    hbo = to_vertical_vector(hb[0:m:2])
+    hbe = to_vertical_vector(hb[1:m:2])
+    t = np.arange(5, r+2*m-2, 4)
+    r2 = r/2;
+    Y = np.zeros((r2,c))
+
+    if np.sum(ha*hb) > 0:
+       s1 = np.arange(0, r2, 2)
+       s2 = s1 + 1
+    else:
+       s2 = np.arange(0, r2, 2)
+       s1 = s2 + 1
+    
+    # Perform filtering on columns of extended matrix X(xe,:) in 4 ways. 
+    Y[s1,:] = convolve2d(X[xe[t-1],:],hao,'valid') + convolve2d(X[xe[t-3],:],hae,'valid')
+    Y[s2,:] = convolve2d(X[xe[t],:],hbo,'valid') + convolve2d(X[xe[t-2],:],hbe,'valid')
+
+    return Y
+
+def colifilt(X, ha, hb):
+    """ Filter the columns of image X using the two filters ha and hb =
+    reverse(ha).  ha operates on the odd samples of X and hb on the even
+    samples.  Both filters should be even length, and h should be approx linear
+    phase with a quarter sample advance from its mid pt (ie |h(m/2)| > |h(m/2 +
+    1)|).
+    
+                      ext       left edge                      right edge       ext
+    Level 2:        !               |               !               |               !
+    +q filt on x      b       b       a       a       a       a       b       b       
+    -q filt on o          a       a       b       b       b       b       a       a
+    Level 1:        !               |               !               |               !
+    odd filt on .    b   b   b   b   a   a   a   a   a   a   a   a   b   b   b   b   
+    odd filt on .      a   a   a   a   b   b   b   b   b   b   b   b   a   a   a   a
+   
+    The output is interpolated by two from the input sample rate and the
+    results from the two filters, Ya and Yb, are interleaved to give Y.
+    Symmetric extension with repeated end samples is used on the composite X
+    columns before each filter is applied.
+   
+    Cian Shaffrey, Nick Kingsbury Cambridge University, August 2000
+    
+    Modified to be fast if X = 0, May 2002.
+
+    """
+    # Make sure all inputs are arrays
+    X = np.array(X)
+    ha = np.array(ha)
+    hb = np.array(hb)
+
+    r, c = X.shape
+    if r % 2 != 0:
+        raise ValueError('No. of rows in X must be a multiple of 2')
+
+    if ha.shape != hb.shape:
+        raise ValueError('Shapes of ha and hb must be the same')
+
+    if ha.shape[0] % 2 != 0:
+        raise ValueError('Lengths of ha and hb must be even')
+
+    m = ha.shape[0]
+    m2 = np.fix(m*0.5)
+
+    Y = np.zeros((r*2,c))
+    if not np.any(np.nonzero(X[:])[0]):
+        return Y
+
+    if m2 % 2 == 0:
+        # m/2 is even, so set up t to start on d samples.
+        # Set up vector for symmetric extension of X with repeated end samples.
+        # Use 'reflect' so r < m2 works OK.
+        xe = reflect(np.arange(-m2, r+m2, dtype=np.int), -0.5, r-0.5)
+       
+        t = np.arange(3, r+m, 2)
+        if np.sum(ha*hb) > 0:
+            ta = t
+            tb = t - 1
+        else:
+            ta = t - 1
+            tb = t
+       
+        # Select odd and even samples from ha and hb. Note that due to 0-indexing
+        # 'odd' and 'even' are not perhaps what you might expect them to be.
+        hao = to_vertical_vector(ha[0:m:2])
+        hae = to_vertical_vector(ha[1:m:2])
+        hbo = to_vertical_vector(hb[0:m:2])
+        hbe = to_vertical_vector(hb[1:m:2])
+       
+        s = np.arange(0,r*2,4)
+       
+        Y[s,:]   = convolve2d(X[xe[tb-2],:],hae,'valid')
+        Y[s+1,:] = convolve2d(X[xe[ta-2],:],hbe,'valid')
+        Y[s+2,:] = convolve2d(X[xe[tb  ],:],hao,'valid')
+        Y[s+3,:] = convolve2d(X[xe[ta  ],:],hbo,'valid')
+    else:
+        # m/2 is odd, so set up t to start on b samples.
+        # Set up vector for symmetric extension of X with repeated end samples.
+        # Use 'reflect' so r < m2 works OK.
+        xe = reflect(np.arange(-m2, r+m2, dtype=np.int), -0.5, r-0.5)
+
+        t = np.arange(2, r+m-1, 2)
+        if np.sum(ha*hb) > 0:
+            ta = t
+            tb = t - 1
+        else:
+            ta = t - 1
+            tb = t
+       
+        # Select odd and even samples from ha and hb. Note that due to 0-indexing
+        # 'odd' and 'even' are not perhaps what you might expect them to be.
+        hao = to_vertical_vector(ha[0:m:2])
+        hae = to_vertical_vector(ha[1:m:2])
+        hbo = to_vertical_vector(hb[0:m:2])
+        hbe = to_vertical_vector(hb[1:m:2])
+       
+        s = np.arange(0,r*2,4)
+       
+        Y[s,:]   = convolve2d(X[xe[tb],:],hao,'valid')
+        Y[s+1,:] = convolve2d(X[xe[ta],:],hbo,'valid')
+        Y[s+2,:] = convolve2d(X[xe[tb],:],hae,'valid')
+        Y[s+3,:] = convolve2d(X[xe[ta],:],hbe,'valid')
+
+    return Y
+
+# vim:sw=4:sts=4:et
+
diff --git a/dtcwt/reflect.py b/dtcwt/reflect.py
deleted file mode 100644
index 990e995..0000000
--- a/dtcwt/reflect.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import numpy as np
-
-def reflect(x, minx, maxx):
-    """Reflect the values in matrix x about the scalar values minx and maxx.
-    Hence a vector x containing a long linearly increasing series is converted
-    into a waveform which ramps linearly up and down between minx and maxx.  If
-    x contains integers and minx and maxx are (integers + 0.5), the ramps will
-    have repeated max and min samples.
-   
-    Nick Kingsbury, Cambridge University, January 1999.
-    
-    """
-
-    # Copy x to avoid in-place modification
-    y = np.array(x, copy=True)
-
-    # Reflect y in maxx.
-    y[y > maxx] = 2*maxx - y[y > maxx]
-
-    while np.any(y < minx):
-        # Reflect y in minx.
-        y[y < minx] = 2*minx - y[y < minx]
-
-        # Reflect y in maxx.
-        y[y > maxx] = 2*maxx - y[y > maxx]
-
-    return y
-
-# vim:sw=4:sts=4:et
diff --git a/dtcwt/transform2d.py b/dtcwt/transform2d.py
new file mode 100644
index 0000000..82bb2d3
--- /dev/null
+++ b/dtcwt/transform2d.py
@@ -0,0 +1,189 @@
+import numpy as np
+import logging
+
+from dtcwt import biort as _biort, qshift as _qshift, colfilter, coldfilt
+
+def dtwavexfm2(X, nlevels=3, biort='near_sym_a', qshift='qshift_a', include_scale=False):
+    """Function to perform a n-level DTCWT-2D decompostion on a 2D matrix X
+
+    Yl, Yh = dtwavexfm2(X, nlevels, biort, qshift)
+    Yl, Yh, Yscale = dtwavexfm2(X, nlevels, biort, qshift, include_scale=True)
+
+        X -> 2D real matrix/Image of shape (N, M)
+
+        nlevels -> No. of levels of wavelet decomposition
+
+        biort ->  'antonini'   => Antonini 9,7 tap filters.
+                  'legall'     => LeGall 5,3 tap filters.
+                  'near_sym_a' => Near-Symmetric 5,7 tap filters.
+                  'near_sym_b' => Near-Symmetric 13,19 tap filters.
+
+        qshift -> 'qshift_06' => Quarter Sample Shift Orthogonal (Q-Shift) 10,10 tap filters, 
+                                 (only 6,6 non-zero taps).
+                  'qshift_a' =>  Q-shift 10,10 tap filters,
+                                 (with 10,10 non-zero taps, unlike qshift_06).
+                  'qshift_b' => Q-Shift 14,14 tap filters.
+                  'qshift_c' => Q-Shift 16,16 tap filters.
+                  'qshift_d' => Q-Shift 18,18 tap filters.
+
+
+        Yl     -> The real lowpass image from the final level
+        Yh     -> A tuple containing the (N, M, 6) shape complex highpass subimages for each level.
+        Yscale -> This is an OPTIONAL output argument, that is a tuple containing 
+                  real lowpass coefficients for every scale. Only returned if include_scale
+                  is True.
+
+    If biort or qshift are not strings, there are interpreted as tuples of
+    vectors giving filter coefficients. In the biort case, this shold be (h0o,
+    g0o, h1o, g1o). In the qshift case, this should be (h0a, h0b, g0a, g0b,
+    h1a, h1b, g1a, g1b).
+
+    Example: Yl,Yh = dtwavexfm2(X,3,'near_sym_b','qshift_b')
+    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.
+
+    Nick Kingsbury and Cian Shaffrey
+    Cambridge University, Sept 2001
+
+    """
+
+    # Try to load coefficients if biort is a string parameter
+    if isinstance(biort, basestring):
+        h0o, g0o, h1o, g1o = _biort(biort)
+    else:
+        h0o, g0o, h1o, g1o = biort
+
+    # Try to load coefficients if qshift is a string parameter
+    if isinstance(qshift, basestring):
+        h0a, h0b, g0a, g0b, h1a, h1b, g1a, g1b = _qshift(qshift)
+    else:
+        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(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
+
+    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]/2, LoLo.shape[1]/2, 6), dtype=np.complex64)
+
+        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
+
+    if nlevels >= 2:
+        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]/2, LoLo.shape[1]/2, 6), dtype=np.complex64)
+            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(extended_size), 'x'.join(orginal_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(extended_size), 'x'.join(orginal_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(extended_size), 'x'.join(orginal_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)
+
+#==========================================================================================
+#                       **********    INTERNAL FUNCTION    **********
+#==========================================================================================
+
+def q2c(y):
+    """Convert from quads in y to complex numbers in z.
+
+    """
+    j2 = np.sqrt(0.5) * np.array([1, 1j])
+
+    # Arrange pixels from the corners of the quads into
+    # 2 subimages of alternate real and imag pixels.
+    #  a----b
+    #  |    |
+    #  |    |
+    #  c----d
+
+    # Combine (a,b) and (d,c) to form two complex subimages. 
+    p = y[0::2, 0::2]*j2[0] + y[0::2, 1::2]*j2[1]     # p = (a + jb) / sqrt(2)
+    q = y[1::2, 1::2]*j2[0] - y[1::2, 0::2]*j2[1] # q = (d - jc) / sqrt(2)
+
+    # Form the 2 subbands in z.
+    z = np.dstack((p-q,p+q))
+
+    return z
+
+# vim:sw=4:sts=4:et
diff --git a/setup.py b/setup.py
index ba39862..12f8abb 100644
--- a/setup.py
+++ b/setup.py
@@ -28,5 +28,5 @@ setup(
 
     setup_requires=['nose>=1.0',],
 
-    install_requires=['numpy',],
+    install_requires=['numpy','scipy',],
 )
diff --git a/tests/colifilt.py b/tests/colifilt.py
new file mode 100644
index 0000000..20f5071
--- /dev/null
+++ b/tests/colifilt.py
@@ -0,0 +1,37 @@
+import os
+
+import numpy as np
+from dtcwt import coldfilt
+
+from nose.tools import raises
+
+def setup():
+    global lena
+    lena = np.load(os.path.join(os.path.dirname(__file__), 'lena.npz'))['lena']
+
+def test_lena_loaded():
+    assert lena.shape == (512, 512)
+    assert lena.min() >= 0
+    assert lena.max() <= 1
+    assert lena.dtype == np.float32
+
+ at raises(ValueError)
+def test_odd_filter_ha():
+    coldfilt(lena, (-1,2,-1), (-1, 1))
+
+ at raises(ValueError)
+def test_odd_filter_hb():
+    coldfilt(lena, (-1,1), (-1,2,-1))
+
+ at raises(ValueError)
+def test_bad_input_size():
+    coldfilt(lena[:511,:], (-1,1), (1,-1))
+
+def test_good_input_size():
+    coldfilt(lena[:,:511], (-1,1), (1,-1))
+
+def test_output_size():
+    Y = coldfilt(lena, (-1,1), (1,-1))
+    assert Y.shape == (lena.shape[0]/2, lena.shape[1])
+
+# vim:sw=4:sts=4:et
diff --git a/tests/lena.npz b/tests/lena.npz
new file mode 100644
index 0000000..663b876
Binary files /dev/null and b/tests/lena.npz differ
diff --git a/tests/testcoeffs.py b/tests/testcoeffs.py
new file mode 100644
index 0000000..36e2719
--- /dev/null
+++ b/tests/testcoeffs.py
@@ -0,0 +1,79 @@
+from dtcwt import biort, qshift
+
+from nose.tools import raises
+
+def test_antonini():
+    h0o, g0o, h1o, g1o = biort('antonini')
+    assert h0o.shape[0] == 9
+    assert g0o.shape[0] == 7
+    assert h1o.shape[0] == 7
+    assert g1o.shape[0] == 9
+
+def test_legall():
+    h0o, g0o, h1o, g1o = biort('legall')
+    assert h0o.shape[0] == 5
+    assert g0o.shape[0] == 3
+    assert h1o.shape[0] == 3
+    assert g1o.shape[0] == 5
+
+def test_near_sym_a():
+    h0o, g0o, h1o, g1o = biort('near_sym_a')
+    assert h0o.shape[0] == 5
+    assert g0o.shape[0] == 7
+    assert h1o.shape[0] == 7
+    assert g1o.shape[0] == 5
+
+def test_near_sym_a():
+    h0o, g0o, h1o, g1o = biort('near_sym_b')
+    assert h0o.shape[0] == 13
+    assert g0o.shape[0] == 19
+    assert h1o.shape[0] == 19
+    assert g1o.shape[0] == 13
+
+def test_qshift_06():
+    coeffs = qshift('qshift_06')
+    assert len(coeffs) == 8
+    for v in coeffs:
+        assert v.shape[0] == 10
+
+def test_qshift_a():
+    coeffs = qshift('qshift_a')
+    assert len(coeffs) == 8
+    for v in coeffs:
+        assert v.shape[0] == 10
+
+def test_qshift_b():
+    coeffs = qshift('qshift_b')
+    assert len(coeffs) == 8
+    for v in coeffs:
+        assert v.shape[0] == 14
+
+def test_qshift_c():
+    coeffs = qshift('qshift_c')
+    assert len(coeffs) == 8
+    for v in coeffs:
+        assert v.shape[0] == 16
+
+def test_qshift_d():
+    coeffs = qshift('qshift_d')
+    assert len(coeffs) == 8
+    for v in coeffs:
+        assert v.shape[0] == 18
+
+ at raises(IOError)
+def test_non_exist_biort():
+    biort('this-does-not-exist')
+
+ at raises(IOError)
+def test_non_exist_qshift():
+    qshift('this-does-not-exist')
+
+ at raises(ValueError)
+def test_wrong_type_a():
+    biort('qshift_06')
+
+ at raises(ValueError)
+def test_wrong_type_b():
+    qshift('antonini')
+
+# vim:sw=4:sts=4:et
diff --git a/tests/testcoldfilt.py b/tests/testcoldfilt.py
new file mode 100644
index 0000000..c4dd3b9
--- /dev/null
+++ b/tests/testcoldfilt.py
@@ -0,0 +1,40 @@
+import os
+
+import numpy as np
+from dtcwt import coldfilt
+
+from nose.tools import raises
+
+def setup():
+    global lena
+    lena = np.load(os.path.join(os.path.dirname(__file__), 'lena.npz'))['lena']
+
+def test_lena_loaded():
+    assert lena.shape == (512, 512)
+    assert lena.min() >= 0
+    assert lena.max() <= 1
+    assert lena.dtype == np.float32
+
+ at raises(ValueError)
+def test_odd_filter():
+    coldfilt(lena, (-1,2,-1), (-1,2,1))
+
+ at raises(ValueError)
+def test_different_size():
+    coldfilt(lena, (-0.5,-1,2,1,0.5), (-1,2,-1))
+
+ at raises(ValueError)
+def test_bad_input_size():
+    coldfilt(lena[:511,:], (-1,1), (1,-1))
+
+def test_good_input_size():
+    coldfilt(lena[:,:511], (-1,1), (1,-1))
+
+def test_good_input_size_non_orthogonal():
+    coldfilt(lena[:,:511], (1,1), (1,1))
+
+def test_output_size():
+    Y = coldfilt(lena, (-1,1), (1,-1))
+    assert Y.shape == (lena.shape[0]/2, lena.shape[1])
+
+# vim:sw=4:sts=4:et
diff --git a/tests/testcolfilter.py b/tests/testcolfilter.py
new file mode 100644
index 0000000..17905cf
--- /dev/null
+++ b/tests/testcolfilter.py
@@ -0,0 +1,49 @@
+import os
+
+import numpy as np
+from dtcwt import colfilter, biort, qshift
+
+def setup():
+    global lena
+    lena = np.load(os.path.join(os.path.dirname(__file__), 'lena.npz'))['lena']
+
+def test_lena_loaded():
+    assert lena.shape == (512, 512)
+    assert lena.min() >= 0
+    assert lena.max() <= 1
+    assert lena.dtype == np.float32
+
+def test_odd_size():
+    y = colfilter(lena, (-1,2,-1))
+    assert y.shape == lena.shape
+
+def test_even_size():
+    y = colfilter(lena, (-1,1))
+    assert y.shape == (lena.shape[0]+1, lena.shape[1])
+
+def test_odd_size():
+    y = colfilter(lena, (-1,2,-1))
+    assert y.shape == lena.shape
+
+def test_qshift():
+    y = colfilter(lena, qshift('qshift_a')[0])
+    assert y.shape == (lena.shape[0]+1, lena.shape[1])
+
+def test_biort():
+    y = colfilter(lena, biort('antonini')[0])
+    assert y.shape == lena.shape
+
+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)
+
+def test_odd_size_non_array():
+    y = colfilter(lena.tolist(), (-1,2,-1))
+    assert y.shape == lena.shape
+
+def test_even_size_non_array():
+    y = colfilter(lena.tolist(), (-1,1))
+    assert y.shape == (lena.shape[0]+1, lena.shape[1])
+	
+# vim:sw=4:sts=4:et
diff --git a/tests/testcolifilt.py b/tests/testcolifilt.py
new file mode 100644
index 0000000..536c8e9
--- /dev/null
+++ b/tests/testcolifilt.py
@@ -0,0 +1,53 @@
+import os
+
+import numpy as np
+from dtcwt import colifilt
+
+from nose.tools import raises
+
+def setup():
+    global lena
+    lena = np.load(os.path.join(os.path.dirname(__file__), 'lena.npz'))['lena']
+
+def test_lena_loaded():
+    assert lena.shape == (512, 512)
+    assert lena.min() >= 0
+    assert lena.max() <= 1
+    assert lena.dtype == np.float32
+
+ at raises(ValueError)
+def test_odd_filter():
+    colifilt(lena, (-1,2,-1), (-1,2,1))
+
+ at raises(ValueError)
+def test_different_size_h():
+    colifilt(lena, (-1,2,1), (-0.5,-1,2,-1,0.5))
+
+def test_zero_input():
+    Y = colifilt(np.zeros_like(lena), (-1,1), (1,-1))
+    assert np.all(Y[:0] == 0)
+
+ at raises(ValueError)
+def test_bad_input_size():
+    colifilt(lena[:511,:], (-1,1), (1,-1))
+
+def test_good_input_size():
+    colifilt(lena[:,:511], (-1,1), (1,-1))
+
+def test_output_size():
+    Y = colifilt(lena, (-1,1), (1,-1))
+    assert Y.shape == (lena.shape[0]*2, lena.shape[1])
+
+def test_non_orthogonal_input():
+    Y = colifilt(lena, (1,1), (1,1))
+    assert Y.shape == (lena.shape[0]*2, lena.shape[1])
+
+def test_output_size_non_mult_4():
+    Y = colifilt(lena, (-1,0,0,1), (1,0,0,-1))
+    assert Y.shape == (lena.shape[0]*2, lena.shape[1])
+
+def test_non_orthogonal_input_non_mult_4():
+    Y = colifilt(lena, (1,0,0,1), (1,0,0,1))
+    assert Y.shape == (lena.shape[0]*2, lena.shape[1])
+
+# vim:sw=4:sts=4:et
diff --git a/tests/testxfm2.py b/tests/testxfm2.py
new file mode 100644
index 0000000..4747f70
--- /dev/null
+++ b/tests/testxfm2.py
@@ -0,0 +1,33 @@
+import os
+
+import numpy as np
+from dtcwt import dtwavexfm2
+
+def setup():
+    global lena
+    lena = np.load(os.path.join(os.path.dirname(__file__), 'lena.npz'))['lena']
+
+def test_lena_loaded():
+    assert lena.shape == (512, 512)
+    assert lena.min() >= 0
+    assert lena.max() <= 1
+    assert lena.dtype == np.float32
+
+def test_simple():
+    Yl, Yh = dtwavexfm2(lena)
+
+def test_simple_w_scale():
+    Yl, Yh, Yscale = dtwavexfm2(lena, include_scale=True)
+
+def test_0_levels():
+    Yl, Yh = dtwavexfm2(lena, nlevels=0)
+    assert np.all(np.abs(Yl - lena) < 1e-5)
+    assert len(Yh) == 0
+
+def test_0_levels_w_scale():
+    Yl, Yh, Yscale = dtwavexfm2(lena, nlevels=0, include_scale=True)
+    assert np.all(np.abs(Yl - lena) < 1e-5)
+    assert len(Yh) == 0
+    assert len(Yscale) == 0
+
+# vim:sw=4:sts=4:et

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/python-dtcwt.git



More information about the debian-science-commits mailing list