[python-dtcwt] 111/497: add specialised two-times upsample functions

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Tue Jul 21 18:05:55 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 b76e9b9601911f8c1f4761961fa9a5b234fe6c32
Author: Rich Wareham <rjw57 at cam.ac.uk>
Date:   Tue Aug 20 13:31:56 2013 +0100

    add specialised two-times upsample functions
---
 dtcwt/sampling.py | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 117 insertions(+), 1 deletion(-)

diff --git a/dtcwt/sampling.py b/dtcwt/sampling.py
index c6a5bf4..641d883 100644
--- a/dtcwt/sampling.py
+++ b/dtcwt/sampling.py
@@ -3,9 +3,12 @@
 """
 
 __all__ = (
-    'sample', 'sample_highpass', 'scale', 'scale_highpass'
+    'sample', 'sample_highpass', 'scale', 'scale_highpass',
+    'upsample', 'upsample_highpass',
 )
 
+from dtcwt.lowlevel import reflect, asfarray
+
 import numpy as np
 
 _W0 = -3*np.pi/2.0
@@ -209,4 +212,117 @@ def scale_highpass(im, shape, method=DEFAULT_SAMPLE_METHOD):
     # re-wrap
     return im_sampled * _phase_image(sxs, sys, False)
 
+def _upsample_columns(X, method=None):
+    """
+    The centre of columns of X, an M-columned matrix, are assumed to have co-ordinates
+    { 0, 1, 2, ... , M-1 } which means that the up-sampled matrix's columns should sample
+    from { -0.25, 0.25, 0.75, ... , M-1.25 }. We can view that as an interleaved set of teo
+    *convolutions* of X. The first, A, using a kernel equivalent to sampling the { -0.25, 0.75,
+    1.75, 2.75, ... M-1.25 } columns and the second, B, sampling the { 0.25, 1.25, ... , M-0.75 }
+    columns.
+    """
+    if method is None:
+        method = 'lanczos'
+    
+    X = np.atleast_2d(asfarray(X))
+    
+    out_shape = list(X.shape)
+    out_shape[1] *= 2
+    output = np.zeros(out_shape, dtype=X.dtype)
+    
+    # Centres of sampling for A and B convolutions
+    M = X.shape[1]
+    A_columns = np.linspace(-0.25, M-1.25, M)
+    B_columns = A_columns + 0.5
+    
+    # For A columns sample at x = ceil(x) - 0.25 with ceil(x) = { 0, 1, 2, ..., M-1 }
+    # For B columns sample at x = floor(x) + 0.25 with floor(x) = { 0, 1, 2, ..., M-1 }
+    int_columns = np.linspace(0, M-1, M)
+    
+    if method == 'lanczos':
+        # Lanczos kernel width
+        a = 3.0
+        sample_offsets = np.arange(-a, a+1)
+       
+        # For A: if i = ceil(x) + di, => ceil(x) - i = -0.25 - di
+        # For B: if i = floor(x) + di, => floor(x) - i = 0.25 - di
+        l_as = np.sinc(-0.25-sample_offsets)*np.sinc((-0.25-sample_offsets)/a)   
+        l_bs = np.sinc(0.25-sample_offsets)*np.sinc((0.25-sample_offsets)/a)
+    elif method == 'nearest':
+        # Nearest neighbour kernel width is 1
+        sample_offsets = [0,]
+        l_as = l_bs = [1,]
+    elif method == 'bilinear':
+        # Bilinear kernel width is technically 2 but we need to offset the kernels differently
+        # for A and B columns:
+        sample_offsets = [-1,0,1]
+        l_as = [0.25, 0.75, 0]
+        l_bs = [0, 0.75, 0.25]
+    else:
+        raise ValueError('Unknown interpolation mode: {0}'.format(mode))
+    
+    # Convolve
+    for di, l_a, l_b in zip(sample_offsets, l_as, l_bs):
+        columns = reflect(int_columns + di, -0.5, M-0.5).astype(np.int)
+        
+        output[:,0::2,...] += l_a * X[:,columns,...]
+        output[:,1::2,...] += l_b * X[:,columns,...]
+    
+    return output
+    
+def upsample(image, method=None):
+    """Specialised function to upsample an image by a factor of two using
+    a specified sampling method. If *image* is an array of shape (NxMx...) then
+    the output will have shape (2Nx2Mx...). Only rows and columns are
+    upsampled, depth axes and greater are interpolated but are not upsampled.
+
+    :param image: an array containing the image to upsample
+    :param method: if non-None, a string specifying the sampling method to use.
+
+    If *method* is ``None``, the default sampling method ``'lanczos'`` is used.
+    The following sampling methods are supported:
+
+    =========== ===========
+    Name        Description 
+    =========== ===========
+    nearest     Nearest-neighbour sampling
+    bilinear    Bilinear sampling
+    lanczos     Lanczos sampling with window radius of 3
+    =========== ===========
+    """
+    image = np.atleast_2d(asfarray(image))
+
+    # The default '.T' operator doesn't quite do what we want since it
+    # reverses the axes rather than only swapping the first two
+    def _t(X):
+        axes = np.arange(len(X.shape))
+        axes[:2] = (1,0)
+        return np.transpose(X, axes)
+
+    return _upsample_columns(_t(_upsample_columns(_t(image), method)), method)
+
+def upsample_highpass(im, method=None):
+    """As :py:func:`upsample` except that the highpass image is first phase
+    rolled so that the filter has approximate DC centre frequency. The upshot
+    is that this is the function to use when re-sampling complex subband
+    images.
+
+    """
+    im = np.atleast_2d(asfarray(im))
+
+    # Sampled co-ordinates
+    dxs, dys = np.meshgrid(np.arange(im.shape[1]*2), np.arange(im.shape[0]*2))
+    sxs = 0.5 * (dxs + 0.5) - 0.5
+    sys = 0.5 * (dys + 0.5) - 0.5
+
+    # phase unwrap
+    X, Y = np.meshgrid(np.arange(im.shape[1]), np.arange(im.shape[0]))
+    im_unwrap = im * _phase_image(X, Y, True)
+    
+    # sample
+    im_sampled = upsample(im_unwrap, method)
+    
+    # re-wrap
+    return im_sampled * _phase_image(sxs, sys, False)
+
 # 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