I recently stumbled upon a bothering fact when using the pywavelet
library in Python. When we use the default "symmetric"
padding, the inverse wavelet transform is not the adjoint of the wavelet transform (and it's not the mathematical inverse of the wavelet transform, "only in one direction").
However, if you use the "zero"
padding the adjoint property is verified (not the inverse property). And if you use the "periodization"
padding then all the properties are verified.
I wanted to know if there was a theoretical reason behind why the padding has such a big influence on these properties or if it was down to implementation.
You can find a code below highlighting the said issue:
import numpy as np
import pywt
wavelet_type = "db4"
level = 4
mode = "symmetric"
coeffs_tpl = pywt.wavedecn(data=np.zeros((512, 512)), wavelet=wavelet_type, mode=mode, level=level)
coeffs_1d, coeff_slices, coeff_shapes = pywt.ravel_coeffs(coeffs_tpl)
coeffs_tpl_rec = pywt.unravel_coeffs(coeffs_1d, coeff_slices, coeff_shapes)
_ = pywt.waverecn(coeffs_tpl_rec, wavelet=wavelet_type, mode=mode)
def py_W(im):
alpha = pywt.wavedecn(data=im, wavelet=wavelet_type, mode=mode, level=level)
alpha, _, _ = pywt.ravel_coeffs(alpha)
return alpha
def py_Ws(alpha):
coeffs = pywt.unravel_coeffs(alpha, coeff_slices, coeff_shapes)
im = pywt.waverecn(coeffs, wavelet=wavelet_type, mode=mode)
return im
x_example = np.random.rand(*coeffs_1d.shape)
y_example = np.random.rand(512, 512)
print("Adjoint:")
x_Tadj_y = np.dot(x_example, np.conjugate(py_W(y_example)))
T_x_y = np.dot(py_Ws(x_example).flatten(), np.conjugate(y_example.flatten()))
print(np.allclose(x_Tadj_y, T_x_y))
print("\n Inverse from image to image:")
print(np.allclose(py_Ws(py_W(y_example)), y_example))
print("\n Inverse from coefficients to coefficients:")
print(np.allclose(py_W(py_Ws(x_example)), x_example))
EDIT: When reading the documentation about the different paddings, I could see that the problematic paddings compute a redundant representation of the original image (for example you have more coefficients than pixels in your original image). Therefore, it's normal that the inverse property is not verified from coefficients to coefficients (if taken at random without structure). However, this doesn't explain why the adjoint property is not verified.
Also I don't know whether this redundance is theoretical to ensure perfect reconstruction or is an implementation choice.