Skip to content

Instantly share code, notes, and snippets.

@101arrowz
Last active March 27, 2023 08:50
Show Gist options
  • Save 101arrowz/89e0caa0ab0894e8335ae2d97a3c5562 to your computer and use it in GitHub Desktop.
Save 101arrowz/89e0caa0ab0894e8335ae2d97a3c5562 to your computer and use it in GitHub Desktop.
Le Gall 5/3 Discrete Wavelet Transform
# Lifting scheme version of the discrete wavelet transform in JPEG 2000
# The approximation and detail coefficients are interleaved in the output of dwt (even
# indices for approx, odd for detail). In practice you may need to separate them afterwards
# idwt is esentially reversing the order of the lifting scheme steps in dwt and
# flipping the sign of operations(i.e. addition becomes subtraction and vice versa)
# approx_len = approximation coefficients length = ceil(total_series_len / 2)
# detail_len = detail coefficients length = floor(total_series_len / 2)
# If you do out the math, the equivalent 1D convolution filters are:
#
# approx analysis: (-1/8, 2/8, 6/8, 2/8, -1/8)
# detail analysis: (-1/2, 1, -1/2)
#
# approx synthesis: (1/2, 1, 1/2)
# detail synthesis: (-1/8, -2/8, 6/8, -2/8, -1/8)
#
# These don't actually work due to the weird use of rounding though.
# Le Gall seems designed specifically for use in a lifting scheme.
import numpy as np
def slow_dwt(seq):
seq = np.copy(seq)
n = seq.shape[0]
detail_len = n >> 1
approx_len = n - detail_len
for i in range(detail_len):
seq[(i << 1) + 1] -= (seq[i << 1] + seq[min((i << 1) + 2, (approx_len - 1) << 1)]) >> 1
for i in range(approx_len):
seq[i << 1] += (seq[max((i << 1) - 1, 1)] + seq[min((i << 1) + 1, ((detail_len - 1) << 1) + 1)] + 2) >> 2
return seq
def slow_idwt(seq):
seq = np.copy(seq)
n = seq.shape[0]
detail_len = n >> 1
approx_len = n - detail_len
for i in range(approx_len):
seq[i << 1] -= (seq[max((i << 1) - 1, 1)] + seq[min((i << 1) + 1, ((detail_len - 1) << 1) + 1)] + 2) >> 2
for i in range(detail_len):
seq[(i << 1) + 1] += (seq[i << 1] + seq[min((i << 1) + 2, (approx_len - 1) << 1)]) >> 1
return seq
def dwt(seq):
seq = np.copy(seq)
n = seq.shape[0]
detail_len = n >> 1
approx_len = n - detail_len
for i in range(1, detail_len):
seq[(i << 1) - 1] -= (seq[(i - 1) << 1] + seq[i << 1]) >> 1
seq[(detail_len << 1) - 1] -= (seq[(detail_len - 1) << 1] + seq[(approx_len - 1) << 1]) >> 1
seq[0] += (seq[1] + seq[1] + 2) >> 2
for i in range(1, approx_len - 1):
seq[i << 1] += (seq[(i << 1) - 1] + seq[(i << 1) + 1] + 2) >> 2
seq[(approx_len - 1) << 1] += (seq[(approx_len << 1) - 3] + seq[(detail_len << 1) - 1] + 2) >> 2
return seq
def idwt(seq):
seq = np.copy(seq)
n = seq.shape[0]
detail_len = n >> 1
approx_len = n - detail_len
seq[0] -= (seq[1] + seq[1] + 2) >> 2
for i in range(1, approx_len - 1):
seq[i << 1] -= (seq[(i << 1) - 1] + seq[(i << 1) + 1] + 2) >> 2
seq[(approx_len - 1) << 1] -= (seq[(approx_len << 1) - 3] + seq[(detail_len << 1) - 1] + 2) >> 2
for i in range(1, detail_len):
seq[(i << 1) - 1] += (seq[(i - 1) << 1] + seq[i << 1]) >> 1
seq[(detail_len << 1) - 1] += (seq[(detail_len - 1) << 1] + seq[(approx_len - 1) << 1]) >> 1
return seq
seq = np.arange(11)
print(idwt(dwt(seq)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment