def test_non_array_input(): ramp = np.linspace(-100, 100, 500).tolist() reflected = reflect(ramp, 30, 40) # Check boundaries assert not np.any(reflected < 30) assert not np.any(reflected > 40)
def colfilter(X, h): """Filter the columns of image *X* using filter vector *h*, without decimation. If len(h) is odd, each output sample is aligned with each input sample and *Y* is the same size as *X*. If len(h) is even, each output sample is aligned with the mid point of each pair of input samples, and Y.shape = X.shape + [1 0]. :param X: an image whose columns are to be filtered :param h: the filter coefficients. :returns Y: the filtered image. .. codeauthor:: Rich Wareham <*****@*****.**>, August 2013 .. codeauthor:: Cian Shaffrey, Cambridge University, August 2000 .. codeauthor:: Nick Kingsbury, Cambridge University, August 2000 """ # Interpret all inputs as arrays X = asfarray(X) h = as_column_vector(h) r, c = X.shape m = h.shape[0] m2 = np.fix(m*0.5) # 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 = _column_convolve(X[xe,:], h) return Y
def colfilter(X, h): """Filter the columns of image *X* using filter vector *h*, without decimation. If len(h) is odd, each output sample is aligned with each input sample and *Y* is the same size as *X*. If len(h) is even, each output sample is aligned with the mid point of each pair of input samples, and Y.shape = X.shape + [1 0]. :param X: an image whose columns are to be filtered :param h: the filter coefficients. :returns Y: the filtered image. .. codeauthor:: Rich Wareham <*****@*****.**>, August 2013 .. codeauthor:: Cian Shaffrey, Cambridge University, August 2000 .. codeauthor:: Nick Kingsbury, Cambridge University, August 2000 """ # Interpret all inputs as arrays X = asfarray(X) h = as_column_vector(h) r, c = X.shape m = h.shape[0] m2 = np.fix(m * 0.5) # 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 = _column_convolve(X[xe, :], h) return Y
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 setup(): global ramp, reflected # Create a simple linear ramp and reflect it ramp = np.linspace(-100, 100, 500) reflected = reflect(ramp, 30, 40)
def _sample_clipped(im, xs, ys): """Truncated and symmetric sampling.""" sym_xs = reflect(xs, -0.5, im.shape[1] - 0.5).astype(np.int) sym_ys = reflect(ys, -0.5, im.shape[0] - 0.5).astype(np.int) return im[sym_ys, sym_xs, ...]
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 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 (i.e. :math:`|h(m/2)| > |h(m/2 + 1)|`). .. code-block:: text 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. .. codeauthor:: Rich Wareham <*****@*****.**>, August 2013 .. codeauthor:: Cian Shaffrey, Cambridge University, August 2000 .. codeauthor:: Nick Kingsbury, Cambridge University, August 2000 """ # Make sure all inputs are arrays X = asfarray(X) ha = asfarray(ha) hb = asfarray(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 = as_column_vector(ha[0:m:2]) hae = as_column_vector(ha[1:m:2]) hbo = as_column_vector(hb[0:m:2]) hbe = as_column_vector(hb[1:m:2]) t = np.arange(5, r+2*m-2, 4) r2 = r/2; Y = np.zeros((r2,c), dtype=X.dtype) if np.sum(ha*hb) > 0: s1 = slice(0, r2, 2) s2 = slice(1, r2, 2) else: s2 = slice(0, r2, 2) s1 = slice(1, r2, 2) # Perform filtering on columns of extended matrix X(xe,:) in 4 ways. Y[s1,:] = _column_convolve(X[xe[t-1],:],hao) + _column_convolve(X[xe[t-3],:],hae) Y[s2,:] = _column_convolve(X[xe[t],:],hbo) + _column_convolve(X[xe[t-2],:],hbe) 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 (i.e `:math:`|h(m/2)| > |h(m/2 + 1)|`). .. code-block:: text 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. .. codeauthor:: Rich Wareham <*****@*****.**>, August 2013 .. codeauthor:: Cian Shaffrey, Cambridge University, August 2000 .. codeauthor:: Nick Kingsbury, Cambridge University, August 2000 """ # Make sure all inputs are arrays X = asfarray(X) ha = asfarray(ha) hb = asfarray(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), dtype=X.dtype) 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 = as_column_vector(ha[0:m:2]) hae = as_column_vector(ha[1:m:2]) hbo = as_column_vector(hb[0:m:2]) hbe = as_column_vector(hb[1:m:2]) s = np.arange(0,r*2,4) Y[s,:] = _column_convolve(X[xe[tb-2],:],hae) Y[s+1,:] = _column_convolve(X[xe[ta-2],:],hbe) Y[s+2,:] = _column_convolve(X[xe[tb ],:],hao) Y[s+3,:] = _column_convolve(X[xe[ta ],:],hbo) 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 = as_column_vector(ha[0:m:2]) hae = as_column_vector(ha[1:m:2]) hbo = as_column_vector(hb[0:m:2]) hbe = as_column_vector(hb[1:m:2]) s = np.arange(0,r*2,4) Y[s,:] = _column_convolve(X[xe[tb],:],hao) Y[s+1,:] = _column_convolve(X[xe[ta],:],hbo) Y[s+2,:] = _column_convolve(X[xe[tb],:],hae) Y[s+3,:] = _column_convolve(X[xe[ta],:],hbe) return Y
def _sample_clipped(im, xs, ys): """Truncated and symmetric sampling.""" sym_xs = reflect(xs, -0.5, im.shape[1]-0.5).astype(np.int) sym_ys = reflect(ys, -0.5, im.shape[0]-0.5).astype(np.int) return im[sym_ys, sym_xs, ...]
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 (i.e. :math:`|h(m/2)| > |h(m/2 + 1)|`). .. code-block:: text 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. .. codeauthor:: Rich Wareham <*****@*****.**>, August 2013 .. codeauthor:: Cian Shaffrey, Cambridge University, August 2000 .. codeauthor:: Nick Kingsbury, Cambridge University, August 2000 """ # Make sure all inputs are arrays X = asfarray(X) ha = asfarray(ha) hb = asfarray(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 = as_column_vector(ha[0:m:2]) hae = as_column_vector(ha[1:m:2]) hbo = as_column_vector(hb[0:m:2]) hbe = as_column_vector(hb[1:m:2]) t = np.arange(5, r + 2 * m - 2, 4) r2 = r // 2 Y = np.zeros((r2, c), dtype=X.dtype) if np.sum(ha * hb) > 0: s1 = slice(0, r2, 2) s2 = slice(1, r2, 2) else: s2 = slice(0, r2, 2) s1 = slice(1, r2, 2) # Perform filtering on columns of extended matrix X(xe,:) in 4 ways. Y[s1, :] = _column_convolve(X[xe[t - 1], :], hao) + _column_convolve( X[xe[t - 3], :], hae) Y[s2, :] = _column_convolve(X[xe[t], :], hbo) + _column_convolve( X[xe[t - 2], :], hbe) 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 (i.e `:math:`|h(m/2)| > |h(m/2 + 1)|`). .. code-block:: text 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. .. codeauthor:: Rich Wareham <*****@*****.**>, August 2013 .. codeauthor:: Cian Shaffrey, Cambridge University, August 2000 .. codeauthor:: Nick Kingsbury, Cambridge University, August 2000 """ # Make sure all inputs are arrays X = asfarray(X) ha = asfarray(ha) hb = asfarray(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), dtype=X.dtype) 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 = as_column_vector(ha[0:m:2]) hae = as_column_vector(ha[1:m:2]) hbo = as_column_vector(hb[0:m:2]) hbe = as_column_vector(hb[1:m:2]) s = np.arange(0, r * 2, 4) Y[s, :] = _column_convolve(X[xe[tb - 2], :], hae) Y[s + 1, :] = _column_convolve(X[xe[ta - 2], :], hbe) Y[s + 2, :] = _column_convolve(X[xe[tb], :], hao) Y[s + 3, :] = _column_convolve(X[xe[ta], :], hbo) 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 = as_column_vector(ha[0:m:2]) hae = as_column_vector(ha[1:m:2]) hbo = as_column_vector(hb[0:m:2]) hbe = as_column_vector(hb[1:m:2]) s = np.arange(0, r * 2, 4) Y[s, :] = _column_convolve(X[xe[tb], :], hao) Y[s + 1, :] = _column_convolve(X[xe[ta], :], hbo) Y[s + 2, :] = _column_convolve(X[xe[tb], :], hae) Y[s + 3, :] = _column_convolve(X[xe[ta], :], hbe) return Y