Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First stage dual tree filters #36

Closed
1 of 3 tasks
niki200481 opened this issue Jul 14, 2021 · 5 comments
Closed
1 of 3 tasks

First stage dual tree filters #36

niki200481 opened this issue Jul 14, 2021 · 5 comments

Comments

@niki200481
Copy link

Version / Platform Info

  • scikit-ued Version: 2.1.5
  • Happens in latest version? (Yes/No): Yes
  • Known Operating System(s) affected__:
    • Windows
    • Linux
    • Mac OS

Expected Behavior

Hello. My question is about the function dt_first_stage(wavelet) in scikit-ued/skued/baseline/dtcwt.py module. To my best knowledge, for the two sets of the first filter banks it is necessary to translate one set of filters by one sample with respect to the other set.

Actual Behavior

As one can see from the minimal example below, the first stage real and imaginary filters are actually same as the filters for the normal DWT. Furthermore, the first stage real and imaginary filters are the same. If this is really true, the DTCWT cannot be realized.

Minimal Example of Issue

The function dt_first_stage(wavelet) is actually copied from the source code.

from pywt import Wavelet

wavelet = Wavelet("db2")
real_first, imag_first = dt_first_stage("db2") 
real_first.filter_bank == wavelet.filter_bank  # return True
imag_first.filter_bank == wavelet.filter_bank  # return True
real_first.filter_bank == imag_first.filter_bank  # return True
@LaurentRDC
Copy link
Owner

LaurentRDC commented Jul 14, 2021

Hi Nikola,

The first stage filters for the dual-tree complex wavelet transform is supposed to be a normal, DWT filter. So these lines are working as expected:

from pywt import Wavelet

wavelet = Wavelet("db2")
real_first, imag_first = dt_first_stage("db2") 
real_first.filter_bank == wavelet.filter_bank  # returns True as expected
imag_first.filter_bank == wavelet.filter_bank  # returns True as expected

As for the last line:

real_first.filter_bank == imag_first.filter_bank  # return True

I don't have access anymore to the reference paper on the dual-tree complex wavelet transform, but I remember following it closely. Based on that reference, what did you expect?

@niki200481
Copy link
Author

Hi Laurent,

Based on the reference paper :

image (30)

For the first stage, the condition (30) can be satisfied exactly by using the same set of filters in each of the two trees; it is necessary only to translate one set of filters by one sample with respect to the other set. Moreover, any set of PR filters can be used for the first stage.

where image is the decomposition low pass filter bank (or the analysis filter) for the first stage for the imaginary tree, and image is the decomposition low pass filter bank (or the analysis filter) for the first stage for the real tree.

So, according to me, the set of filters for the imaginary tree has to be shifted by one sample with respect to the set of filters for the real tree. My confusion is to the following lines :

import numpy as np
from pywt import Wavelet

db2 = Wavelet("db2")
filter_bank = [np.array(f, copy=True) for f in db2.filter_bank]
for filt in filter_bank:
    extended = np.zeros(shape=(filt.shape[0] + 2,), dtype=float)
    extended[1:-1] = filt
    filt = extended

I suppose that the every filter in the set of filters in filter_bank should be surrounded by one zero at the beginning and one zero at the end. But after the execution of the function, filter_bank is the same as the db2.filter_bank.

The following lines of code do this :

import numpy as np
from pywt import Wavelet

db2 = Wavelet("db2")

# extend filter bank with zeros
filter_bank = [np.array(f, copy=True) for f in db2.filter_bank]
for i, filt in enumerate(filter_bank):
    extended = np.zeros(shape=(filt.shape[0] + 2,), dtype=float)
    extended[1:-1] = filt
    filter_bank[i] = extended

After that :

In [5]: filter_bank
Out[5]: 
[array([ 0. , -0.12940952,  0.22414387,  0.8365163 ,  0.48296291, 0. ]),
 array([ 0. , -0.48296291,  0.8365163 , -0.22414387, -0.12940952, 0. ]),
 array([ 0. ,  0.48296291,  0.8365163 ,  0.22414387, -0.12940952, 0. ]),
 array([ 0. , -0.12940952, -0.22414387,  0.8365163 , -0.48296291, 0. ])]

In [6]: db2.filter_bank
Out[6]: 
([-0.12940952255126037,  0.2241438680420134,  0.8365163037378079,  0.48296291314453416],
 [-0.48296291314453416,  0.8365163037378079,  -0.2241438680420134,  -0.12940952255126037],
 [0.48296291314453416,  0.8365163037378079,  0.2241438680420134,  -0.12940952255126037],
 [-0.12940952255126037,  -0.2241438680420134,  0.8365163037378079,  -0.48296291314453416])

In [7]: filter_bank == db2.filter_bank
Out[7]: False

I suppose that this is specific to the numpy issue with the arrays. Similarly, the following lines of code do not change shifted_fb :

import numpy as np
from pywt import Wavelet

db2 = Wavelet("db2")

# Shift deconstruction filters to one side, and reconstruction
# to the other side
shifted_fb = [np.array(f, copy=True) for f in db2.filter_bank]
for filt in shifted_fb[::2]:  # Deconstruction filters
    filt = np.roll(filt, 1)
for filt in shifted_fb[2::]:  # Reconstruction filters
    filt = np.roll(filt, -1)

In [11]: db2.filter_bank
Out[11]: 
([-0.12940952255126037,  0.2241438680420134,  0.8365163037378079,  0.48296291314453416],
 [-0.48296291314453416,  0.8365163037378079,  -0.2241438680420134,  -0.12940952255126037],
 [0.48296291314453416,  0.8365163037378079,  0.2241438680420134,  -0.12940952255126037],
 [-0.12940952255126037,  -0.2241438680420134,  0.8365163037378079,  -0.48296291314453416])

In [12]: shifted_fb
Out[12]: 
[array([-0.12940952,  0.22414387,  0.8365163 ,  0.48296291]),
 array([-0.48296291,  0.8365163 , -0.22414387, -0.12940952]),
 array([ 0.48296291,  0.8365163 ,  0.22414387, -0.12940952]),
 array([-0.12940952, -0.22414387,  0.8365163 , -0.48296291])]

The following lines of code do change shifted_fb :

import numpy as np
from pywt import Wavelet

db2 = Wavelet("db2")
filter_bank = [
    np.array([ 0. , -0.12940952,  0.22414387,  0.8365163 ,  0.48296291, 0. ]),
    np.array([ 0. , -0.48296291,  0.8365163 , -0.22414387, -0.12940952, 0. ]),
    np.array([ 0. ,  0.48296291,  0.8365163 ,  0.22414387, -0.12940952, 0. ]),
    np.array([ 0. , -0.12940952, -0.22414387,  0.8365163 , -0.48296291, 0. ])
]

# Shift deconstruction filters to one side, and reconstruction
# to the other side
shifted_fb = [np.array(f, copy=True) for f in filter_bank]
for i, filt in enumerate(shifted_fb[:2]):  # Deconstruction filters
    shifted_fb[i] = np.roll(filt, 1)
for i, filt in enumerate(shifted_fb[2:]):  # Reconstruction filters
    shifted_fb[i + 2] = np.roll(filt, -1)

In [15]: db2.filter_bank
Out[15]: 
([-0.12940952255126037,  0.2241438680420134,  0.8365163037378079,  0.48296291314453416],
 [-0.48296291314453416,  0.8365163037378079,  -0.2241438680420134,  -0.12940952255126037],
 [0.48296291314453416,  0.8365163037378079,  0.2241438680420134,  -0.12940952255126037],
 [-0.12940952255126037,  -0.2241438680420134,  0.8365163037378079,  -0.48296291314453416])

In [16]: shifted_fb
Out[16]: 
[array([ 0. ,  0. , -0.12940952,  0.22414387,  0.8365163 , 0.48296291]),
 array([ 0. ,  0. , -0.48296291,  0.8365163 , -0.22414387, -0.12940952]),
 array([ 0.48296291,  0.8365163 ,  0.22414387, -0.12940952,  0. , 0.  ]),
 array([-0.12940952, -0.22414387,  0.8365163 , -0.48296291,  0. , 0.  ])]

I changed shifted_fb[::2] to shifted_fb[:2]) and shifted_fb[2::] to shifted_fb[2:] because:

from pywt import Wavelet

db2 = Wavelet("db2")

db2.filter_bank[0] == db2.dec_lo  # return True
db2.filter_bank[1] == db2.dec_hi  # return True
db2.filter_bank[2] == db2.rec_lo  # return True
db2.filter_bank[3] == db2.rec_hi  # return True

@LaurentRDC
Copy link
Owner

Ahh yes I see the problem now. Thank you for investigating!

If you feel comfortable, you might want to submit a pull-request yourself. Otherwise, I will be able to fix this only next week.

@niki200481
Copy link
Author

Hi Laurent,
I have to do my own research how exactly the filter_bank and the shifted_fb, structured this way, satisfied the condition (30).

I wish you successes. 👍

@LaurentRDC
Copy link
Owner

LaurentRDC commented Jul 21, 2021

Version 2.1.7 has just been released, which contains a fix for this.

Don't hesitate to open other issues if you find more problems. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants