2d signal module#
This module provides lazy linear operators associated to fast linear transforms commonly used in image processing. ..
This currently includes the Discrete Cosine Transform (
dct2d()), Discrete Sine Transform (dst2d()), Modified Discrete Cosine Transform (mdct2d()), Discrete Fourier Transform (dft2d()) and the Discrete Wavelet Transform (dwt2d()), and we also provide a lazy linear operator for convolution with a given (2D) filter.
List of transforms#
lazylinop.signal2d.convolve2d()Convolution with a given (2D) filter.lazylinop.signal2d.dwt2d()Discrete Wavelet Transformlazylinop.signal2d.idwt2d()Inverse of Discrete Wavelet transformlazylinop.signal2d.dft2d()Discrete Fourier Transformlazylinop.signal2d.dct2d()Discrete Cosine Transform of types I to IVlazylinop.signal2d.dst2d()Discrete Sine Transform of types I to IVlazylinop.signal2d.mdct2d()Modified DCT
Padding or cropping#
Traditional implementations of image processing transforms offer the possibility to either crop or zero-pad the analyzed image. We choose not to include this in our implementation, as mimicing this feature is simple with the generic lazylinop interface.
Consider for the example F2 = dft2d(in_shape=(N, N)), the operator associated to the 2D DFT matrix on \(N\times N\) images.
To apply it to an image X of size \(N\times N\), we can define G = eye(N, n), G2 = kron(G, G) and observe that F2 @ G2 does exactly what we need:
padding: if \(n<N\), by definition of the Kronecker product
G2 @ colvec(X) = (G @ X @ G.T)is a (flattened) zero padded version ofX, of size \(N\times N\), so thatH = F2 @ G2is the lazy linear operator that computes the 2D DFT after zero padding.cropping: if \(n>N\), similarly
G2 @ colvec(X)is a (flattened) cropped version ofXof size N x N, andH = F2 @ G2is again exactly what you need.
For convenience, we provide an operator padder2d(in_shape, width, mode) to pad a 2D array (provided “of course” in a flattened form) with specific boundary conditions zero, periodic, symmetric, antisymmetric and reflect.
padder2d() is obtained from the Kronecker product kron(L1, L2) of two operators L1 = padder(in_shape[0], width[0], mode) and L2 = padder(in_shape[1], width[1], mode).
Warning
Do not confuse padder2d with pad (see Construction for more details).
Inverse transforms#
As in the signal module Signal module, most of our 2D transforms are orthonormal, and their inverse is thus their adjoint, e.g., with F the DFT, the adjoint F.H is the lazy linear operator associated to the inverse transform (appropriately taking into account all parameters of the original transform).
The main exceptions are convolve2d(), mdct2d() (this operator satisfies L @ L.T = L @ L.H = Id but not L.T @ L = Id) and dwt2d() (see its documentation for details on parameters ensuring that L = dwt2d(...) satisfies L @ L.T = L.T @ L = Id or only L.T @ L = Id when L is rectangular).
Note
This is because of most our 2D transforms are Kronecker product \(K=L_1\otimes L_2\) of two 1D transforms \(L_1\) and \(L_2\). The matrix product of the adjoint \(K^H\) with \(K\) is given by \(K^HK=\left(L_1^H\otimes L_2^H\right)\left(L_1\otimes L_2\right)\) and we have \(K^HK=\left(L_1^HL\right)\otimes\left(L_2^HL_2\right)\) (mixed-product property). If \(L_1\) and \(L_2\) are orthogonal, \(K^HK\) is equal to the identity matrix. Therefore, the 2D transform associated to \(K\) is orthogonal.
Non-orthonormal versions of these transforms correspond to alternative normalizations described below.
Various normalizations#
Traditional implementations of image processing transforms offer various normalization (e.g., with division by \(N\), \(\sqrt{N}\), or no division).
They can all be mimicked (if really needed) by pre- or post-composing the transform F.
As an illustration, SciPy’s fft2d() and ifft2d() with the default normalization is mimicked as follows.
>>> import numpy as np
>>> from scipy.fft import fft2 as sp_fft2d
>>> from scipy.fft import ifft2 as sp_ifft2d
>>> from lazylinop.signal2d import dft2d as lz_dft2d
>>> from lazylinop.signal2d import colvec
>>> from lazylinop.signal2d import uncolvec
>>> N = 32
>>> X = np.random.randn(N, N)
>>> F2 = lz_dft2d((N, N))
>>> scale = N
>>> y = scale * F2 @ colvec(X)
>>> Y = sp_fft2d(X)
>>> np.allclose(colvec(y, (N, N)), Y)
>>> True
>>> x_ = F2.H @ y / scale
>>> X_ = sp_ifft2d(Y)
>>> np.allclose(colvec(x_, (N, N)), X_)
>>> True
To mimick SciPy’s DCT/DST called with orthogonalize=True, the same trick holds where scale depends on the transform’s type (I,II,III,IV) and the choice of norm ('backward' or 'forward'; NB: scale = 1 if norm = 'ortho').
Mimicking the DCT/DST with orthogonalize=False requires pre- and/or post-composing by diagonal operators that depend on the type.
For example, the default DCT-II behavior (norm = 'ortho'):
>>> from lazylinop.signal2d import dst2d as lz_dst2d
>>> from scipy.fft import dstn as sp_dstn
>>> import numpy as np
>>> M, N = 32, 32
>>> X = np.random.randn(M, N)
>>> L = lz_dst2d(X.shape)
>>> Y = L @ colvec(X)
>>> from lazylinop.basicops import diag
>>> v = np.full(N, 1.0)
>>> v[-1] = np.sqrt(2.0)
>>> D = diag(v)
>>> Z = sp_dstn(X, 2, (M, N), (0, 1), 'ortho', False, 1, orthogonalize=False)
>>> np.allclose(D @ Y.reshape(M, N) @ D, Z)
True
Transforms#
- lazylinop.signal2d.convolve2d(in_shape, filter, mode='full', boundary='fill', backend='auto')#
Returns a
LazyLinOpLfor the 2D convolution of a 2D signal of shapein_shape=(M, N)(provided in flattened version) with a 2Dfilter.Shape of
Lis \((M'N',~MN)\) where(M, N)=in_shapeandout_shape=(M', N')depends onmode. After applying the operator asy = L @ colvec(X), a 2D output can be obtained viauncolvec(y, out_shape).- Args:
- in_shape:
tuple, Shape \((M,~N)\) of the signal to convolve with kernel.
- filter: NumPy array, CuPy array or torch tensor
Kernel to use for the convolution, shape is \((K,~L)\).
- mode:
str, optional 'full': compute full convolution including at points of non-complete overlapping of inputs (default). Yieldsout_shape=(M', N')withM'=M + K - 1andN'=N + L - 1.'valid': compute only fully overlapping part of the convolution. This is the ‘full’ center part of (output) shape(M - K + 1, N - L + 1)(K <= MandL <= Nmust be satisfied). Yieldsout_shape=(M', N')withM' = M - K + 1andN' = N - L + 1.'same': compute only the center part of'full'to obtain an output sizeMequal to the input sizeN. Yieldsout_shape=(M', N')withM' = MandN' = N.
- boundary:
str, optional 'fill'pads input array with zeros (default).'wrap'periodic boundary conditions.'symm'symmetrical boundary conditions.
- backend:
str, optional 'auto': use the best backend according to the kernel and input array dimensions.'scipy encapsulation': encapsulate(cupyx).scipy.signal.convolve. If the filter and the input are CuPy arrays the function usescupyx.scipy.signal.convolve.‘toeplitz’`: encapsulate
(cupyx).scipy.linalg.toeplitzifN < 2048,(cupyx).scipy.linalg.matmul_toeplitzotherwise. Of note, there is no torch implementation for Toeplitz matrix.``’scipy fft’`: use Fast-Fourier-Transform to compute convolution.
'direct': direct computation using nested for-loops with Numba and parallelization. It does not work if the input is CuPy array or torch tensor.
- in_shape:
- Returns:
- Examples:
>>> from lazylinop.signal2d import convolve2d, colvec, uncolvec >>> import numpy as np >>> import scipy as sp >>> X = np.random.randn(6, 6) >>> H = np.random.randn(3, 3) >>> L = convolve2d(X.shape, H, mode='same') >>> y1 = uncolvec(L @ colvec(X), X.shape) >>> y2 = sp.signal.convolve2d(X, H, mode='same') >>> np.allclose(y1, y2) True
See also
`SciPy convolve2d function <https://docs.scipy.org/doc/scipy/
reference/generated/scipy.signal.convolve2d.html>`_, - CuPy convolve2d function.
- lazylinop.signal2d.dwt2d(in_shape, wavelet='haar', mode='zero', level=None, backend='pywavelets')#
Returns a
LazyLinOpLfor the 2D Discrete-Wavelet-Transform (DWT) of a 2D signal of shapein_shape = (M, N)(provided in flattened version).L @ xwill return a 1d NumPy/CuPy array or torch tensor as the concatenation of the DWT coefficients in the form[cAn, cHn, cVn, cDn, ..., cH1, cV1, cD1]wherenis the decomposition level.cAiare the approximation coefficients for leveli.cHiare the horizontal coefficients for leveli.cViare the vertical coefficients for leveli.cDiare the detail coefficients for leveli.
cAi,cHi,cViandcDimatrices have been flattened.Shape of
Lis \((P,~MN)\) where \(P>=MN\). The value of \(P\) depends on themode. In general,Lis not orthogonal.- Args:
- in_shape:
tuple Shape of the 2d input array \((M,~N)\).
wavelet:
stror tuple of(dec_lo, dec_hi), optionalIf a
stris provided, the wavelet name from Pywavelets libraryIf a tuple
(dec_lo, dec_hi)of two NumPy/CuPy arrays or torch tensors is provided, the low and high-pass filters (for decomposition) used to define the wavelet.The
dwt2d()function does not test whether these two filters are actually Quadrature-Mirror-Filters.
mode:
str, optional'zero', signal is padded with zeros (default).'periodic', signal is treated as periodic signal.'symmetric', use mirroring to pad the signal.'antisymmetric', signal is extended by mirroring and multiplying elements by minus one.'reflect', signal is extended by reflecting elements.'periodization', signal is extended like'periodic'extension mode. Only the smallest possible number of coefficients is returned. Odd-length signal is extended first by replicating the last value.
- level:
int, optional If level is None compute full decomposition (default).
- backend:
str, optional 'pywavelets'(default) or'lazylinop'for the underlying computation of the DWT.
- in_shape:
- Returns:
- Examples:
>>> from lazylinop.signal2d import dwt2d, colvec >>> import numpy as np >>> import pywt >>> X = np.array([[1., 2.], [3., 4.]]) >>> L = dwt2d(X.shape, wavelet='db1', level=1) >>> y = L @ colvec(X) >>> cA, (cH, cV, cD) = pywt.wavedec2(X, wavelet='db1', level=1) >>> z = np.concatenate([cA, cH, cV, cD], axis=1) >>> np.allclose(y, z) True
See also
lazylinop.signal.idwt2d().
- lazylinop.signal2d.idwt2d(out_shape, wavelet='haar', mode='zero', level=None, backend='pywavelets')#
Returns a
LazyLinOpiLfor the 2D inverse Discrete-Wavelet-Transform (iDWT) of a 2D signal of shape \((M',~N')\) (provided in flattened version).If
L = dwt2d(out_shape, wavelet, mode, level, backend)is the 2D DWT operator of shape \((M'N',~MN)\) (out_shapeis \((M,~N)\)), theniL = idwt2d(out_shape, wavelet, mode, level, backend)is the 2D iDWT operator such thatiL @ L = Id. As a result, ify = L @ xis the coefficients at level decompositionlevel, then the \((M,~N)\)-dimensionnal signalxcan be reconstructed from the \((M',~N')\)-dimensionnal vectoryasiL @ y.Shape of
iLis \((MN,~M'N')\) where \(M'N'>=MN\). The value of \(M'N'\) depends on themode. In general,iLis not orthogonal.- Args:
- out_shape:
tuple Shape of the output array \((M,~N)\) (i.e., shape of the input array of the associated DWT
LazyLinOp, see above).
wavelet:
stror tuple of(np.ndarray, np.ndarray), optionalIf a
stris provided, the wavelet name from Pywavelets libraryIf a tuple
(rec_lo, rec_hi)of twonp.ndarrayis provided, the low and high-pass filters (for reconstruction) used to define the wavelet.The
idwt2d()function does not test whether these two filters are actually Quadrature-Mirror-Filters.
mode:
str, optional'zero', signal is padded with zeros (default).'periodic', signal is treated as periodic signal.'symmetric', use mirroring to pad the signal.'antisymmetric', signal is extended by mirroring and multiplying elements by minus one.'reflect', signal is extended by reflecting elements.'periodization', signal is extended like'periodic'extension mode. Only the smallest possible number of coefficients is returned. Odd-length signal is extended first by replicating the last value.
- level:
int, optional If level is None compute full decomposition (default).
- backend:
str, optional 'pywavelets'(default) or'lazylinop'for the underlying computation of the DWT.
- out_shape:
- Returns:
- Examples:
>>> from lazylinop.signal2d import dwt2d, idwt2d >>> from lazylinop.signal2d import colvec, uncolvec >>> import numpy as np >>> M, N = 2, 3 >>> x = np.arange(M * N).reshape(M, N) >>> x array([[0, 1, 2], [3, 4, 5]]) >>> W = dwt2d(x.shape, wavelet='db1', level=1) >>> y = W @ colvec(x) >>> L = idwt2d(x.shape, wavelet='db1', level=1) >>> z = L @ y >>> np.allclose(x, uncolvec(z, (M, N))) True
See also
lazylinop.signal.dwt2d().
- lazylinop.signal2d.dft2d(in_shape)#
Returns a
LazyLinOpLfor the orthogonal 2D Discrete-Fourier-Transform (DFT) of a 2D signal of shapein_shape = (M, N)(provided in flattened version).Shape of
Lis \((MN,~MN)\) with \((M,~N)= ext{in_shape}\). After applying the operator asy = L @ colvec(X), a 2D output can be obtained viauncolvec(y, out_shape)without_shape = in_shape.Lis orthogonal.- Args:
- in_shape:
tuple Shape of the 2d input array \((M,~N)\).
- in_shape:
- Returns:
- Example:
>>> from lazylinop.signal2d import dft2d, colvec, uncolvec >>> import numpy as np >>> import scipy as sp >>> # Check the 2d DFT >>> N = 32 >>> F = dft2d((N, N)) >>> x = np.random.rand(N, N) >>> ly = F @ colvec(x) >>> sy = sp.fft.fft2(x, norm='ortho') >>> np.allclose(uncolvec(ly, (N, N)), sy) True >>> # Check the inverse DFT >>> lx_ = F.H @ ly >>> sx_ = sp.fft.ifft2(sy, norm='ortho') >>> np.allclose(lx_, colvec(sx_)) True >>> # Orthogonal DFT >>> A = F.toarray() >>> H = F.H.toarray() >>> np.allclose(A @ H, np.eye(N ** 2)) True
See also
- lazylinop.signal2d.fft2d(in_shape)#
Alias for
dft2d(in_shape: tuple)function.
- lazylinop.signal2d.dct2d(in_shape, type=2, backend='scipy')#
Returns a
LazyLinOp`Lfor the 2D Direct Cosine Transform (DCT) of a 2D signal of shapein_shape=(M, N)(provided in flattened version).Shape of
Lis \((MN,~MN)\) with \((M,~N)=\text{in_shape}\). After applying the operator asy = L @ colvec(X), a 2D output can be obtained viauncolvec(y, out_shape)without_shape = in_shape.Lis orthogonal.- Args:
- in_shape:
tuple Shape of the 2d input array \((M,~N)\).
- type:
int, optional 1, 2, 3, 4 (I, II, III, IV). Defaut is 2. See SciPy DCT for more details.
- backend:
str, optional 'scipy'(default) usesscipy.fft.dctto compute the DCT.'lazylinop'uses a composition of basic Lazylinop operators to compute the DCT (fft(),vstack()etc.).
- in_shape:
- Returns:
- Examples:
>>> from lazylinop.signal2d import dct2d as lz_dct2d, colvec, uncolvec >>> from scipy.fft import dctn as sp_dctn >>> import numpy as np >>> M, N = 32, 32 >>> X = np.random.randn(M, N) >>> L = lz_dct2d(X.shape) >>> Y = L @ colvec(X) >>> Z = sp_dctn(X, 2, (M, N), (0, 1), norm='ortho') >>> np.allclose(Y, colvec(Z)) True >>> # compute the inverse DCT >>> X_ = L.T @ Y >>> np.allclose(X_, colvec(X)) True >>> # To mimick SciPy DCT II norm='ortho' and orthogonalize=False >>> # Because of Kronecker vec trick we apply diagonal operator D >>> # on the left and on the right after reshaping of Y. >>> from lazylinop.basicops import diag >>> v = np.full(N, 1.0) >>> v[0] = np.sqrt(2.0) >>> D = diag(v) >>> Z = sp_dctn(X, 2, (M, N), (0, 1), 'ortho', False, 1, orthogonalize=False) >>> np.allclose(D @ uncolvec(Y, (M, N)) @ D, Z) True
See also
- lazylinop.signal2d.dst2d(in_shape, type=2, backend='scipy')#
Returns a
LazyLinOpLfor the 2D Direct Sine Transform (DST) of a 2D signal of shapein_shape=(M, N)(provided in flattened version).Shape of
Lis \((MN,~MN)\) with \((M,~N)=\text{in_shape}\). After applying the operator asy = L @ colvec(X), a 2D output can be obtained viauncolvec(y, out_shape)without_shape = in_shape.Lis orthogonal.- Args:
- in_shape:
tuple Shape of the 2d input array \((M,~N)\).
- type:
int, optional 1, 2, 3, 4 (I, II, III, IV). Defaut is 2. See SciPy DST for more details.
- backend: str, optional
'scipy'(default) usesscipy.fft.dstto compute the DST.'lazylinop'Uses a composition of basic Lazylinop operators to compute the DST (fft(),vstack()etc.).
- in_shape:
- Returns:
- Example:
>>> from lazylinop.signal2d import dst2d as lz_dst2d, colvec, uncolvec >>> from scipy.fft import dstn as sp_dstn >>> import numpy as np >>> M, N = 32, 32 >>> X = np.random.randn(M, N) >>> L = lz_dst2d(X.shape) >>> Y = L @ colvec(X) >>> Z = sp_dstn(X, 2, (M, N), (0, 1), norm='ortho') >>> np.allclose(Y, colvec(Z)) True >>> # compute the inverse DST >>> X_ = L.T @ Y >>> np.allclose(uncolvec(X_, (M, N)), X) True >>> # To mimick SciPy DST II norm='ortho' and orthogonalize=False >>> # Because of Kronecker vec trick we apply diagonal operator D >>> # on the left and on the right after reshaping of Y. >>> from lazylinop.basicops import diag >>> v = np.full(N, 1.0) >>> v[-1] = np.sqrt(2.0) >>> D = diag(v) >>> Z = sp_dstn(X, 2, (M, N), (0, 1), 'ortho', False, 1, orthogonalize=False) >>> np.allclose(D @ uncolvec(Y, (M, N)) @ D, Z) True
See also
- lazylinop.signal2d.mdct2d(in_shape, windows=(('vorbis', 128), ('vorbis', 128)), backend='scipy')#
Returns a
LazyLinOpLfor the 2D Modified Direct Cosine Transform (MDCT) of a 2D signal of shapein_shape=(M, N)(provided in flattened version).Shape of
Lis \((PQ,~MN)\) with \(P=n_1\frac{W_1}{2}\) and \(Q=n_2\frac{W_2}{2}\).\(n_i\) is the number of chunks and \(W_i\) is the window size along axis \(i\).
After applying the operator as
y = L @ colvec(X), a 2D output can be obtained viauncolvec(y, out_shape)without_shape = (P / 2, Q / 2).Lis not orthogonal (as it is rectangular with fewer rows than columns, it is not left invertible) but it is right-invertible and real-valued, withL @ L.T = L @ L.H = Id. Thus,L.Tcan be used as a right-inverse.- Args:
- in_shape:
tuple Shape of the 2d input array \((M,~N)\).
- windows:
tupleof(str, int)or(str, int, float), optional Windows, a tuple
((name: str, win_size: int), (name: str, win_size: int))or((name: str, win_size: int, beta: float), (name: str, win_size: int, beta: float)). Window size must be a mutliple of 4. Default is(('vorbis', 128), ('vorbis', 128)).betahas no effect excepts for'kaiser_bessel_derived'window. Possible windows are:'None'corresponds to a rectangular window with a scale \(\frac{1}{\sqrt{2}}\).'kaiser_bessel_derived'see scipy.signal.window.kaiser_bessel_derived for more details.'vorbis'(default) or'sin'see https://en.wikipedia.org/wiki/Modified_discrete_cosine_transform for more details.
- backend: str, optional
'scipy'(default) usesscipy.fft.dctencapsulation for the underlying computation of the DCT.'lazylinop'uses pre-built Lazylinop operators (Lazylinopfft(),eye(),vstack()etc.) to build the pipeline that will compute the MDCT.
- in_shape:
- Returns:
- Example:
>>> from lazylinop.signal2d import mdct2d, colvec >>> import numpy as np >>> M, N = 128, 128 >>> X = np.random.randn(M, N) >>> L = mdct2d(X.shape) >>> Y = L @ colvec(X) >>> Y.shape[0] == (M // 2) * (N // 2) True >>> X_ = L.T @ Y >>> X_.shape[0] == M * N True
- References:
[1] Xuancheng Shao, Steven G. Johnson, Type-IV DCT, DST, and MDCT algorithms with reduced numbers of arithmetic operations, Signal Processing, Volume 88, Issue 6, 2008, Pages 1313-1326, ISSN 0165-1684, https://doi.org/10.1016/j.sigpro.2007.11.024.
- lazylinop.signal2d.padder2d(in_shape, width=((0, 0), (0, 0)), mode='zero')#
Returns a
LazyLinOpLthat extend a 2D signal of shapein_shape=(M, N)(provided in flattened version) with either zero, periodic, symmetric, antisymmetric or reflect boundary conditions.Shape of
Lis \((M'N',~MN)\). \(M'\) and \(N'\) are determined bywidth. By default \(M'=M\) and \(N'=N\).After applying the operator as
y = L @ colvec(X), a 2D output can be obtained viauncolvec(y, out_shape)without_shape = (M', N').padder2duse the pre-builtLazyLinOppadderand the Kronecker vector product trick to computeL @ x.- Args:
- in_shape:
tuple Shape of the 2D input array \((M,~N)\).
- width:
tuple, optional widthargument expects atuplelike((b_0, a_0), (b_1, a_1)). Number of values padded on both side of the first axis is(b_0, a_0). Number of values padded on both side of the second axis is(b_1, a_1).b_0stands for before whilea_0stands for after. By default it is equal to((0, 0), (0, 0)).The size of the output is \(M'N'\) with
M'N' = (b_0 + M + a_0) * (b_1 + N + a_1).- mode:
str, optional 'zero'(default) or'wrap'/'periodic'or'symm'/'symmetric'or'antisymmetric'or'reflect'boundary condition. See the documentation of the.lazylinop.basicops.padderfor more details.
- in_shape:
- Returns:
LazyLinOpof shape \((M'N',~MN)\) where \(M'N' = (b_0 + M + a_0)(b_1 + N + a_1)\).- Examples:
>>> from lazylinop.signal2d import padder2d, colvec, uncolvec >>> import numpy as np >>> M, N = 2, 2 >>> X = np.arange(4).astype('float').reshape(M, N) >>> X array([[0., 1.], [2., 3.]]) >>> L = padder2d(X.shape, ((M, M), (N, N)), mode='periodic') >>> uncolvec(L @ colvec(X), (3 * M, 3 * N)) array([[0., 1., 0., 1., 0., 1.], [2., 3., 2., 3., 2., 3.], [0., 1., 0., 1., 0., 1.], [2., 3., 2., 3., 2., 3.], [0., 1., 0., 1., 0., 1.], [2., 3., 2., 3., 2., 3.]]) >>> M, N = 3, 2 >>> X = np.arange(1, 7).astype('float').reshape(M, N) >>> X array([[1., 2.], [3., 4.], [5., 6.]]) >>> L = padder2d(X.shape, ((0, 1), (3, 5)), mode='symmetric') >>> uncolvec(L @ colvec(X), (0 + M + 1, 3 + N + 5)) array([[2., 2., 1., 1., 2., 2., 1., 1., 2., 2.], [4., 4., 3., 3., 4., 4., 3., 3., 4., 4.], [6., 6., 5., 5., 6., 6., 5., 5., 6., 6.], [6., 6., 5., 5., 6., 6., 5., 5., 6., 6.]])
See also
lazylinop.basicops.padder()
Utility functions#
lazylinop.flatten()lazylinop.unflatten()lazylinop.colvec()lazylinop.uncolvec()
- lazylinop.signal2d.flatten(X)#
Returns a flatten version of X along its first two dimensions.
This utility function is provided to flatten an image or a batch of images to be used as input of LazyLinOp signal2d’s functions.
- Args:
X:
arraywith 2 dimensions for a single image or 3 dimensions for a batch of images.- Returns:
Flattened version of X.
- Examples:
>>> import numpy as np >>> from lazylinop.signal2d import flatten >>> X = np.arange(90).reshape(3, 3, 10) >>> X.shape (3, 3, 10) >>> flatten(X).shape (9, 10)
See also
- lazylinop.signal2d.unflatten(X, shape)#
Returns a un-flatten version of X, where its first dimension is expanded on two dimensions with shape shape.
This utility function is provided to un-flatten an image or a batch of images as returned by LazyLinOp signal2d’s functions, to be manipulated as usual 2D images.
- Args:
X:
arraywith 1 dimension for a single image or 2 dimensions for a batch of images. shape: the 2D dimensions of image.- Returns:
Un-flattened version of X
- Examples:
>>> import numpy as np >>> from lazylinop.signal2d import unflatten >>> X = np.arange(90).reshape(9, 10) >>> X.shape (9, 10) >>> unflatten(X, (3, 3)).shape (3, 3, 10)
See also
- lazylinop.signal2d.dwt2d_to_pywt_coeffs(x, in_shape, wavelet='haar', level=None, mode='zero')#
Returns Pywavelets compatible
[cAn, (cHn, cVn, cDn), ..., (cH1, cV1, cD1)]built from the 1d arrayxof flattened coefficients[cAn, cHn, cVn, cDn, ..., cH1, cV1, cD1]wherenis the decomposition level.- Args:
- x:
np.ndarray List of coefficients
[cAn, cHn, cVn, cDn, ..., cH1, cV1, cD1].- in_shape, wavelet, level, mode:
See
dwt2d()for more details.
- x:
- Returns:
Pywavelets compatible
list[cAn, (cHn, cVn, cDn), ..., (cH1, cV1, cD1)].- Examples:
>>> import numpy as np >>> from lazylinop.signal2d import dwt2d, colvec, dwt2d_to_pywt_coeffs >>> import pywt >>> M, N = 5, 6 >>> x = np.arange(M * N).reshape(M, N) >>> L = dwt2d((M, N), wavelet='haar', level=2, mode='zero') >>> y = L @ colvec(x) >>> y = dwt2d_to_pywt_coeffs(y, (M, N), 'haar', level=2, mode='zero') >>> z = pywt.wavedec2(x, wavelet='haar', level=2, mode='zero') >>> np.allclose(y[0], z[0]) True >>> np.allclose(y[0][0], z[0][0]) True
- lazylinop.signal2d.dwt2d_coeffs_shapes(in_shape, wavelet='haar', level=None, mode='zero')#
Return a
listoftuplethat gives the shape of the flattened coefficients[cAn, cHn, cVn, cDn, ..., cH1, cV1, cD1].- Args:
- in_shape, wavelet, level, mode:
See
dwt2d()for more details.
- Returns:
listoftuple.- Examples:
>>> from lazylinop.signal2d import dwt2d_coeffs_shapes >>> dwt2d_coeffs_shapes((5, 6), 'haar', level=2) [(2, 2), (2, 2), (2, 2), (2, 2), (3, 3), (3, 3), (3, 3)]
- lazylinop.signal2d.colvec(X)#
Returns a flatten version of X along its first two dimensions. Importantly here,
colvec(X)stacks the columns ofX.This utility function is provided to flatten an image or a batch of images to be used as input of LazyLinOp signal2d’s functions.
- Args:
- X:
np.ndarray Array with 2 dimensions for a single image or 3 dimensions for a batch of images.
- X:
- Returns:
Stack of columns version of X (
np.ndarray).- Examples:
>>> import numpy as np >>> from lazylinop.signal2d import colvec >>> X = np.arange(90).reshape(3, 3, 10) >>> X.shape (3, 3, 10) >>> colvec(X).shape (9, 10)
- lazylinop.signal2d.uncolvec(X, shape)#
Returns a un-flatten version of
X(assumingXhas been obtained usingcolvecfunction), where its first dimension is expanded on two dimensions with shapeshape.This utility function is provided to un-flatten an image or a batch of images as returned by LazyLinOp signal2d’s functions, to be manipulated as usual 2D images.
If
x = colvec(X)is the stack of columns ofX,y = uncolvec(x, X.shape)is equal toX.- Args:
- X:
np.ndarray Array with 1 dimension for a single image or 2 dimensions for a batch of images.
- shape:
tuple The 2D dimensions of image.
- X:
- Returns:
Un-flattened version of X (
np.ndarray).- Examples:
>>> import numpy as np >>> from lazylinop.signal2d import colvec, uncolvec >>> X = np.arange(90).reshape(9, 10) >>> X.shape (9, 10) >>> uncolvec(X, (3, 3)).shape (3, 3, 10) >>> # Check that X = uncolvec(colvec(X), shape=X.shape). >>> X = np.arange(2 * 3).reshape(2, 3) >>> X array([[0, 1, 2], [3, 4, 5]]) >>> x = colvec(X) >>> Y = uncolvec(x, shape=X.shape) >>> np.allclose(X, Y) True
version 1.20.10 documentation