0
# Single-Level Discrete Wavelet Transform
1
2
Single-level forward and inverse discrete wavelet transforms for 1D, 2D, and nD data providing complete coefficient decomposition into approximation and detail components.
3
4
## Capabilities
5
6
### 1D Discrete Wavelet Transform
7
8
Single-level analysis and synthesis for one-dimensional signals.
9
10
```python { .api }
11
def dwt(data, wavelet, mode: str = 'symmetric', axis: int = -1):
12
"""
13
Single-level 1D discrete wavelet transform.
14
15
Parameters:
16
- data: Input 1D array or array with axis specified
17
- wavelet: Wavelet specification (string name, Wavelet object, or filter bank)
18
- mode: Signal extension mode for boundary handling
19
- axis: Axis along which to perform DWT (default: -1, last axis)
20
21
Returns:
22
(cA, cD) - approximation and detail coefficients as tuple
23
"""
24
25
def idwt(cA, cD, wavelet, mode: str = 'symmetric', axis: int = -1):
26
"""
27
Single-level 1D inverse discrete wavelet transform.
28
29
Parameters:
30
- cA: Approximation coefficients (can be None)
31
- cD: Detail coefficients (can be None)
32
- wavelet: Wavelet specification matching forward transform
33
- mode: Signal extension mode matching forward transform
34
- axis: Axis along which to perform IDWT
35
36
Returns:
37
Reconstructed 1D signal
38
"""
39
```
40
41
#### Usage Examples
42
43
```python
44
import pywt
45
import numpy as np
46
import matplotlib.pyplot as plt
47
48
# Create test signal with noise
49
t = np.linspace(0, 1, 1000)
50
signal = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * 20 * t)
51
noisy_signal = signal + 0.3 * np.random.randn(len(signal))
52
53
# Single-level DWT
54
cA, cD = pywt.dwt(noisy_signal, 'db4')
55
print(f"Original signal length: {len(noisy_signal)}")
56
print(f"Approximation coefficients: {len(cA)}")
57
print(f"Detail coefficients: {len(cD)}")
58
59
# Perfect reconstruction
60
reconstructed = pywt.idwt(cA, cD, 'db4')
61
print(f"Reconstruction error: {np.max(np.abs(noisy_signal - reconstructed))}")
62
63
# Denoising by thresholding detail coefficients
64
threshold = 0.1 * np.max(np.abs(cD))
65
cD_thresh = np.where(np.abs(cD) > threshold, cD, 0)
66
denoised = pywt.idwt(cA, cD_thresh, 'db4')
67
68
# Plotting
69
plt.figure(figsize=(12, 8))
70
plt.subplot(2, 2, 1)
71
plt.plot(t, signal, 'b-', label='Original')
72
plt.plot(t, noisy_signal, 'r-', alpha=0.7, label='Noisy')
73
plt.title('Original vs Noisy Signal')
74
plt.legend()
75
76
plt.subplot(2, 2, 2)
77
plt.plot(cA, 'g-', label='Approximation')
78
plt.title('Approximation Coefficients')
79
plt.legend()
80
81
plt.subplot(2, 2, 3)
82
plt.plot(cD, 'r-', label='Detail')
83
plt.plot(cD_thresh, 'k-', label='Thresholded')
84
plt.title('Detail Coefficients')
85
plt.legend()
86
87
plt.subplot(2, 2, 4)
88
plt.plot(t, signal, 'b-', label='Original')
89
plt.plot(t, denoised, 'g-', label='Denoised')
90
plt.title('Original vs Denoised')
91
plt.legend()
92
plt.tight_layout()
93
plt.show()
94
95
# Multi-dimensional data along specific axis
96
data_2d = np.random.randn(50, 1000)
97
cA_2d, cD_2d = pywt.dwt(data_2d, 'haar', axis=1) # Transform along columns
98
print(f"2D data shape: {data_2d.shape}")
99
print(f"2D coefficients shape: {cA_2d.shape}, {cD_2d.shape}")
100
```
101
102
### 2D Discrete Wavelet Transform
103
104
Single-level analysis and synthesis for two-dimensional data such as images.
105
106
```python { .api }
107
def dwt2(data, wavelet, mode: str = 'symmetric', axes=(-2, -1)):
108
"""
109
Single-level 2D discrete wavelet transform.
110
111
Parameters:
112
- data: Input 2D array or multi-dimensional array
113
- wavelet: Wavelet specification
114
- mode: Signal extension mode for boundary handling
115
- axes: Pair of axes along which to perform 2D DWT (default: last two axes)
116
117
Returns:
118
(cA, (cH, cV, cD)) - approximation and horizontal/vertical/diagonal detail coefficients
119
"""
120
121
def idwt2(coeffs, wavelet, mode: str = 'symmetric', axes=(-2, -1)):
122
"""
123
Single-level 2D inverse discrete wavelet transform.
124
125
Parameters:
126
- coeffs: Coefficient tuple (cA, (cH, cV, cD)) from dwt2
127
- wavelet: Wavelet specification matching forward transform
128
- mode: Signal extension mode matching forward transform
129
- axes: Pair of axes along which to perform 2D IDWT
130
131
Returns:
132
Reconstructed 2D array
133
"""
134
```
135
136
#### Usage Examples
137
138
```python
139
import pywt
140
import numpy as np
141
import matplotlib.pyplot as plt
142
143
# Create test image
144
image = np.zeros((128, 128))
145
image[30:98, 30:98] = 1 # Square in center
146
image[40:88, 40:88] = 0.5 # Smaller square inside
147
# Add some texture
148
image += 0.1 * np.random.randn(128, 128)
149
150
# 2D DWT
151
coeffs = pywt.dwt2(image, 'db2')
152
cA, (cH, cV, cD) = coeffs
153
154
print(f"Original image shape: {image.shape}")
155
print(f"Approximation shape: {cA.shape}")
156
print(f"Detail shapes: {cH.shape}, {cV.shape}, {cD.shape}")
157
158
# Perfect reconstruction
159
reconstructed = pywt.idwt2(coeffs, 'db2')
160
print(f"Reconstruction error: {np.max(np.abs(image - reconstructed))}")
161
162
# Visualize decomposition
163
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
164
165
axes[0, 0].imshow(image, cmap='gray')
166
axes[0, 0].set_title('Original Image')
167
168
axes[0, 1].imshow(cA, cmap='gray')
169
axes[0, 1].set_title('Approximation (cA)')
170
171
axes[0, 2].imshow(reconstructed, cmap='gray')
172
axes[0, 2].set_title('Reconstructed')
173
174
axes[1, 0].imshow(cH, cmap='gray')
175
axes[1, 0].set_title('Horizontal Details (cH)')
176
177
axes[1, 1].imshow(cV, cmap='gray')
178
axes[1, 1].set_title('Vertical Details (cV)')
179
180
axes[1, 2].imshow(cD, cmap='gray')
181
axes[1, 2].set_title('Diagonal Details (cD)')
182
183
for ax in axes.flat:
184
ax.axis('off')
185
186
plt.tight_layout()
187
plt.show()
188
189
# Image compression by coefficient thresholding
190
threshold = 0.1
191
cA_thresh = cA # Keep all approximation coefficients
192
cH_thresh = np.where(np.abs(cH) > threshold, cH, 0)
193
cV_thresh = np.where(np.abs(cV) > threshold, cV, 0)
194
cD_thresh = np.where(np.abs(cD) > threshold, cD, 0)
195
196
compressed_coeffs = (cA_thresh, (cH_thresh, cV_thresh, cD_thresh))
197
compressed_image = pywt.idwt2(compressed_coeffs, 'db2')
198
199
# Calculate compression ratio
200
original_nonzero = np.count_nonzero(image)
201
compressed_nonzero = (np.count_nonzero(cA_thresh) +
202
np.count_nonzero(cH_thresh) +
203
np.count_nonzero(cV_thresh) +
204
np.count_nonzero(cD_thresh))
205
compression_ratio = original_nonzero / compressed_nonzero
206
207
print(f"Compression ratio: {compression_ratio:.2f}")
208
```
209
210
### nD Discrete Wavelet Transform
211
212
Single-level analysis and synthesis for n-dimensional data with arbitrary number of dimensions.
213
214
```python { .api }
215
def dwtn(data, wavelet, mode: str = 'symmetric', axes=None):
216
"""
217
Single-level nD discrete wavelet transform.
218
219
Parameters:
220
- data: Input nD array
221
- wavelet: Wavelet specification
222
- mode: Signal extension mode for boundary handling
223
- axes: Axes along which to perform DWT (default: all axes)
224
225
Returns:
226
Dictionary of coefficients with string keys indicating coefficient type.
227
For 2D: {'aa': cA, 'ad': cH, 'da': cV, 'dd': cD}
228
For 3D: {'aaa': cAAA, 'aad': cAAD, 'ada': cADA, ...} (8 coefficients)
229
"""
230
231
def idwtn(coeffs, wavelet, mode: str = 'symmetric', axes=None):
232
"""
233
Single-level nD inverse discrete wavelet transform.
234
235
Parameters:
236
- coeffs: Dictionary of coefficients from dwtn
237
- wavelet: Wavelet specification matching forward transform
238
- mode: Signal extension mode matching forward transform
239
- axes: Axes along which to perform IDWT (should match forward transform)
240
241
Returns:
242
Reconstructed nD array
243
"""
244
```
245
246
#### Usage Examples
247
248
```python
249
import pywt
250
import numpy as np
251
252
# 3D volume data example
253
volume = np.random.randn(32, 32, 32)
254
print(f"Original volume shape: {volume.shape}")
255
256
# 3D DWT
257
coeffs_3d = pywt.dwtn(volume, 'db2')
258
print(f"Number of coefficient arrays: {len(coeffs_3d)}")
259
print(f"Coefficient keys: {list(coeffs_3d.keys())}")
260
261
# Each coefficient array is 1/8 the size in 3D
262
for key, coeff in coeffs_3d.items():
263
print(f"Coefficient '{key}' shape: {coeff.shape}")
264
265
# Perfect reconstruction
266
reconstructed_3d = pywt.idwtn(coeffs_3d, 'db2')
267
print(f"3D reconstruction error: {np.max(np.abs(volume - reconstructed_3d))}")
268
269
# 2D example using dwtn (equivalent to dwt2)
270
image_2d = np.random.randn(64, 64)
271
coeffs_2d = pywt.dwtn(image_2d, 'haar')
272
print(f"2D coefficient keys: {list(coeffs_2d.keys())}")
273
print(f"Approximation 'aa' shape: {coeffs_2d['aa'].shape}")
274
275
# Compare with dwt2
276
coeffs_dwt2 = pywt.dwt2(image_2d, 'haar')
277
cA, (cH, cV, cD) = coeffs_dwt2
278
279
# Verify equivalence
280
print(f"dwtn 'aa' equals dwt2 cA: {np.allclose(coeffs_2d['aa'], cA)}")
281
print(f"dwtn 'ad' equals dwt2 cH: {np.allclose(coeffs_2d['ad'], cH)}")
282
print(f"dwtn 'da' equals dwt2 cV: {np.allclose(coeffs_2d['da'], cV)}")
283
print(f"dwtn 'dd' equals dwt2 cD: {np.allclose(coeffs_2d['dd'], cD)}")
284
285
# Partial transforms along specific axes
286
data_4d = np.random.randn(16, 16, 16, 100) # 3D spatial + 1D time
287
coeffs_partial = pywt.dwtn(data_4d, 'db1', axes=(0, 1, 2)) # Transform only spatial dimensions
288
print(f"Partial transform result shape for 'aaa': {coeffs_partial['aaa'].shape}")
289
```
290
291
### Utility Functions
292
293
Helper functions for working with DWT parameters and coefficients.
294
295
```python { .api }
296
def dwt_max_level(data_len: int, filter_len: int) -> int:
297
"""
298
Compute maximum useful decomposition level for 1D DWT.
299
300
Parameters:
301
- data_len: Length of input data
302
- filter_len: Length of wavelet filter
303
304
Returns:
305
Maximum decomposition level
306
"""
307
308
def dwt_coeff_len(data_len: int, filter_len: int, mode: str) -> int:
309
"""
310
Compute length of DWT coefficient arrays.
311
312
Parameters:
313
- data_len: Length of input data
314
- filter_len: Length of wavelet filter
315
- mode: Signal extension mode
316
317
Returns:
318
Length of coefficient arrays
319
"""
320
321
def dwtn_max_level(shape: tuple, wavelet, axes=None) -> int:
322
"""
323
Compute maximum decomposition level for nD data.
324
325
Parameters:
326
- shape: Shape of input data
327
- wavelet: Wavelet specification
328
- axes: Axes for transform (default: all axes)
329
330
Returns:
331
Maximum decomposition level
332
"""
333
334
def pad(x, pad_widths, mode: str):
335
"""
336
Extend signal using PyWavelets extension modes.
337
338
Parameters:
339
- x: Input array
340
- pad_widths: Padding widths for each axis
341
- mode: PyWavelets extension mode
342
343
Returns:
344
Padded array
345
"""
346
347
def downcoef(part: str, data, wavelet, mode: str = 'symmetric', level: int = 1):
348
"""
349
Partial discrete wavelet transform decomposition.
350
351
Parameters:
352
- part: Coefficients type ('a' for approximation, 'd' for details)
353
- data: Input signal array
354
- wavelet: Wavelet specification
355
- mode: Signal extension mode
356
- level: Decomposition level (default: 1)
357
358
Returns:
359
1D array of requested coefficients
360
"""
361
362
def upcoef(part: str, coeffs, wavelet, level: int = 1, take: int = 0):
363
"""
364
Direct reconstruction from wavelet coefficients.
365
366
Parameters:
367
- part: Coefficients type ('a' for approximation, 'd' for details)
368
- coeffs: Coefficient array to reconstruct from
369
- wavelet: Wavelet specification
370
- level: Multilevel reconstruction level (default: 1)
371
- take: Take central part of specified length (0 for full length)
372
373
Returns:
374
1D array with reconstructed signal
375
"""
376
```
377
378
#### Usage Examples
379
380
```python
381
import pywt
382
import numpy as np
383
384
# Calculate maximum decomposition levels
385
data_1d = np.random.randn(1000)
386
wavelet = 'db4'
387
filter_len = pywt.Wavelet(wavelet).dec_len
388
389
max_level_1d = pywt.dwt_max_level(len(data_1d), filter_len)
390
print(f"Max level for 1D data (length {len(data_1d)}): {max_level_1d}")
391
392
# Calculate coefficient lengths for different modes
393
coeff_len_sym = pywt.dwt_coeff_len(len(data_1d), filter_len, 'symmetric')
394
coeff_len_per = pywt.dwt_coeff_len(len(data_1d), filter_len, 'periodization')
395
print(f"Coefficient length (symmetric): {coeff_len_sym}")
396
print(f"Coefficient length (periodization): {coeff_len_per}")
397
398
# nD maximum levels
399
image_2d = np.random.randn(256, 256)
400
max_level_2d = pywt.dwtn_max_level(image_2d.shape, wavelet)
401
print(f"Max level for 2D image {image_2d.shape}: {max_level_2d}")
402
403
volume_3d = np.random.randn(64, 64, 64)
404
max_level_3d = pywt.dwtn_max_level(volume_3d.shape, wavelet)
405
print(f"Max level for 3D volume {volume_3d.shape}: {max_level_3d}")
406
407
# Signal padding examples
408
signal = np.array([1, 2, 3, 4, 5])
409
pad_widths = [(2, 2)] # Pad 2 elements on each side
410
411
padded_zero = pywt.pad(signal, pad_widths, 'zero')
412
padded_symmetric = pywt.pad(signal, pad_widths, 'symmetric')
413
padded_periodic = pywt.pad(signal, pad_widths, 'periodic')
414
415
print(f"Original: {signal}")
416
print(f"Zero padding: {padded_zero}")
417
print(f"Symmetric padding: {padded_symmetric}")
418
print(f"Periodic padding: {padded_periodic}")
419
420
# Partial decomposition with downcoef
421
test_signal = np.sin(2 * np.pi * np.linspace(0, 1, 256))
422
423
# Get only approximation coefficients at level 2
424
approx_only = pywt.downcoef('a', test_signal, 'db4', level=2)
425
print(f"Approximation coefficients shape: {approx_only.shape}")
426
427
# Get only detail coefficients at level 1
428
detail_only = pywt.downcoef('d', test_signal, 'db4', level=1)
429
print(f"Detail coefficients shape: {detail_only.shape}")
430
431
# Compare with full DWT
432
coeffs_full = pywt.wavedec(test_signal, 'db4', level=2)
433
cA2, cD2, cD1 = coeffs_full
434
print(f"Full decomposition - cA2: {cA2.shape}, matches downcoef: {np.allclose(cA2, approx_only)}")
435
436
# Direct reconstruction with upcoef
437
# Reconstruct signal from approximation coefficients only
438
reconstructed_approx = pywt.upcoef('a', approx_only, 'db4', level=2)
439
print(f"Reconstructed from approx shape: {reconstructed_approx.shape}")
440
441
# Reconstruct signal from detail coefficients only
442
reconstructed_detail = pywt.upcoef('d', detail_only, 'db4', level=1)
443
print(f"Reconstructed from detail shape: {reconstructed_detail.shape}")
444
445
# Visualization of partial reconstruction
446
plt.figure(figsize=(12, 8))
447
plt.subplot(2, 2, 1)
448
plt.plot(test_signal, 'b-', label='Original')
449
plt.title('Original Signal')
450
plt.legend()
451
452
plt.subplot(2, 2, 2)
453
plt.plot(reconstructed_approx[:len(test_signal)], 'g-', label='From Approximation')
454
plt.title('Reconstructed from Approximation Only')
455
plt.legend()
456
457
plt.subplot(2, 2, 3)
458
plt.plot(reconstructed_detail[:len(test_signal)], 'r-', label='From Details')
459
plt.title('Reconstructed from Details Only')
460
plt.legend()
461
462
plt.subplot(2, 2, 4)
463
combined = reconstructed_approx[:len(test_signal)] + reconstructed_detail[:len(test_signal)]
464
plt.plot(test_signal, 'b-', alpha=0.7, label='Original')
465
plt.plot(combined, 'k--', label='Approx + Detail')
466
plt.title('Combined Reconstruction')
467
plt.legend()
468
plt.tight_layout()
469
plt.show()
470
```
471
472
## Types
473
474
```python { .api }
475
# Single-level coefficient formats
476
Coeffs1D = Tuple[np.ndarray, np.ndarray] # (cA, cD)
477
Coeffs2D = Tuple[np.ndarray, Tuple[np.ndarray, np.ndarray, np.ndarray]] # (cA, (cH, cV, cD))
478
CoeffsND = Dict[str, np.ndarray] # String keys like 'aa', 'ad', 'da', 'dd' for 2D
479
480
# Input data types
481
ArrayLike = Union[np.ndarray, list, tuple]
482
483
# Extension modes
484
Mode = Literal[
485
'zero', 'constant', 'symmetric', 'periodic',
486
'smooth', 'periodization', 'reflect',
487
'antisymmetric', 'antireflect'
488
]
489
```