.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/009_decompose_module.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. or to run this example in your browser via JupyterLite or Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_009_decompose_module.py: Decompose Module ================ This example demonstrates how to use the 'decompose' module. - Pyramid decomposition (reduce & expand) in 1D and 2D. - Haar wavelet decomposition (analysis & synthesis) in 2D. You can download this example at the tab at right (Python script or Jupyter notebook. .. GENERATED FROM PYTHON SOURCE LINES 14-18 Imports ------- We import the required libraries and modules. .. GENERATED FROM PYTHON SOURCE LINES 18-42 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt # For downloading and handling the image import requests from io import BytesIO from PIL import Image # Pyramid decomposition utilities from splineops.decompose.pyramid import ( get_pyramid_filter, reduce_1d, expand_1d, reduce_2d, expand_2d ) # Wavelet classes for 2D from splineops.decompose.wavelets.haar import HaarWavelets from splineops.decompose.wavelets.splinewavelets import ( Spline1Wavelets, Spline3Wavelets, Spline5Wavelets ) .. GENERATED FROM PYTHON SOURCE LINES 43-47 1D Pyramid Decomposition ------------------------ Here is a 1D examples that involves data of length 10. We do a pyramid reduce-then-expand. .. GENERATED FROM PYTHON SOURCE LINES 47-83 .. code-block:: Python x = np.array([0.0, 1.0, 2.0, 3.0, 2.0, 1.0, 0.0, -2.0, -4.0, -6.0], dtype=np.float64) filter_name = "Centered Spline" order = 3 g, h, is_centered = get_pyramid_filter(filter_name, order) reduced = reduce_1d(x, g, is_centered) expanded = expand_1d(reduced, h, is_centered) error = expanded - x print("[1D Pyramid Test]") print(f"Filter: '{filter_name}' (order={order}), is_centered={is_centered}") print("Input x:", x) print("Reduced :", reduced) print("Expanded :", expanded) print("Error :", error) fig, axs = plt.subplots(nrows=3, ncols=1, figsize=(8, 6)) axs[0].plot(x, 'o-', label='Input') axs[0].set_title("1D Input Signal") axs[0].legend() axs[1].plot(reduced, 'o--', color='r', label='Reduced') axs[1].set_title("Reduced (Half-Size)") axs[1].legend() axs[2].plot(expanded, 'o--', color='g', label='Expanded') axs[2].plot(x, 'o-', color='k', alpha=0.3, label='Original') axs[2].set_title(f"Expanded vs Original (Error max={np.abs(error).max():.3g})") axs[2].legend() plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_001.png :alt: 1D Input Signal, Reduced (Half-Size), Expanded vs Original (Error max=0.291) :srcset: /auto_examples/images/sphx_glr_009_decompose_module_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none [1D Pyramid Test] Filter: 'Centered Spline' (order=3), is_centered=True Input x: [ 0. 1. 2. 3. 2. 1. 0. -2. -4. -6.] Reduced : [ 0.34065843 2.68175207 1.54133046 -0.83042701 -5.23331582] Expanded : [-0.04459776 0.95501393 2.29130194 2.71324125 2.02602713 1.08397035 -0.01051075 -1.9097665 -4.28487695 -5.81974832] Error : [-0.04459776 -0.04498607 0.29130194 -0.28675875 0.02602713 0.08397035 -0.01051075 0.0902335 -0.28487695 0.18025168] .. GENERATED FROM PYTHON SOURCE LINES 84-89 Load and Normalize a 2D Image ----------------------------- Here, we load an example image from an online repository. We convert it to grayscale in [0,1]. .. GENERATED FROM PYTHON SOURCE LINES 89-118 .. code-block:: Python url = 'https://r0k.us/graphics/kodak/kodak/kodim07.png' response = requests.get(url) img = Image.open(BytesIO(response.content)) # Convert to numpy float64 image_color = np.array(img, dtype=np.float64) # Normalize to [0,1] image_color /= 255.0 # Convert to grayscale using standard weights image_gray = ( image_color[:, :, 0] * 0.2989 + image_color[:, :, 1] * 0.5870 + image_color[:, :, 2] * 0.1140 ) ny, nx = image_gray.shape print(f"Downloaded image shape = {ny} x {nx}") # Plot the original grayscale image plt.figure(figsize=(6, 6)) plt.imshow(image_gray, cmap='gray', interpolation='nearest', vmin=0, vmax=1) plt.title("Original Grayscale Image", fontsize=14) plt.axis('off') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_002.png :alt: Original Grayscale Image :srcset: /auto_examples/images/sphx_glr_009_decompose_module_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Downloaded image shape = 512 x 768 .. GENERATED FROM PYTHON SOURCE LINES 119-123 2D Pyramid Decomposition ------------------------ Reduce and expand the input image using spline pyramid decomposition. .. GENERATED FROM PYTHON SOURCE LINES 123-156 .. code-block:: Python filter_name = "Spline" order = 3 g, h, is_centered = get_pyramid_filter(filter_name, order) reduced_2d = reduce_2d(image_gray, g, is_centered) expanded_2d = expand_2d(reduced_2d, h, is_centered) error_2d = expanded_2d - image_gray max_err = np.abs(error_2d).max() print("[2D Pyramid Test]") print(f"Filter: '{filter_name}' (order={order}), is_centered={is_centered}") print("Reduced shape:", reduced_2d.shape) print("Expanded shape:", expanded_2d.shape) print(f"Max error: {max_err}") # Retrieve the pyramid filter parameters (using "Spline" filter with order 3) filter_name = "Spline" order = 3 g, h, is_centered = get_pyramid_filter(filter_name, order) # Compute pyramid levels: # Level 0: Original image, and each subsequent level is obtained by reducing the previous one. num_reductions = 3 levels = [] current = image_gray # image_gray is already loaded from previous cell. levels.append(current) # Level 0: Original image for _ in range(num_reductions): current = reduce_2d(current, g, is_centered) levels.append(current) original_shape = image_gray.shape # (ny, nx) .. rst-class:: sphx-glr-script-out .. code-block:: none [2D Pyramid Test] Filter: 'Spline' (order=3), is_centered=False Reduced shape: (256, 384) Expanded shape: (512, 768) Max error: 0.5062710854288006 .. GENERATED FROM PYTHON SOURCE LINES 157-159 1-Level Decomposition ~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 159-171 .. code-block:: Python canvas1 = np.ones(original_shape, dtype=image_gray.dtype) # white canvas h1, w1 = levels[1].shape canvas1[:h1, :w1] = levels[1] # Place the reduced image in the top-left corner plt.figure(figsize=(6, 6)) plt.imshow(canvas1, cmap='gray', vmin=0, vmax=1, interpolation='nearest') plt.title("Pyramid 1-Level Decomposition", fontsize=14) plt.axis('off') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_003.png :alt: Pyramid 1-Level Decomposition :srcset: /auto_examples/images/sphx_glr_009_decompose_module_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 172-174 2-Level Decomposition ~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 174-186 .. code-block:: Python canvas2 = np.ones(original_shape, dtype=image_gray.dtype) # white canvas h2, w2 = levels[2].shape canvas2[:h2, :w2] = levels[2] # Place the reduced image in the top-left corner plt.figure(figsize=(6, 6)) plt.imshow(canvas2, cmap='gray', vmin=0, vmax=1, interpolation='nearest') plt.title("Pyramid 2-Level Decomposition", fontsize=14) plt.axis('off') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_004.png :alt: Pyramid 2-Level Decomposition :srcset: /auto_examples/images/sphx_glr_009_decompose_module_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 187-189 3-Level Decomposition ~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 189-201 .. code-block:: Python canvas3 = np.ones(original_shape, dtype=image_gray.dtype) # white canvas h3, w3 = levels[3].shape canvas3[:h3, :w3] = levels[3] # Place the reduced image in the top-left corner plt.figure(figsize=(6, 6)) plt.imshow(canvas3, cmap='gray', vmin=0, vmax=1, interpolation='nearest') plt.title("Pyramid 3-Level Decomposition", fontsize=14) plt.axis('off') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_005.png :alt: Pyramid 3-Level Decomposition :srcset: /auto_examples/images/sphx_glr_009_decompose_module_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 202-207 2D Wavelet Decomposition ------------------------ We demonstrate wavelet decomposition (analysis) and reconstruction (synthesis) using 2D Haar wavelets on a grayscale image. .. GENERATED FROM PYTHON SOURCE LINES 207-253 .. code-block:: Python haar2d = HaarWavelets(scales=3) coeffs = haar2d.analysis(image_gray) recon_haar = haar2d.synthesis(coeffs) err_haar = recon_haar - image_gray max_err_haar = np.abs(err_haar).max() print("[Wavelets 2D Haar Test]") print(f"Max error after 3-scale decomposition: {max_err_haar}") # Helper function for visualization def pyramid_with_quadrant_embedding_levels(wavelet, inp, num_levels): """ Perform multi-scale wavelet analysis in-place so that at each level the new coarse approximation is stored in the quadrant corresponding to the previous level's coarse region. Parameters ---------- wavelet : AbstractWavelets instance A wavelet instance (e.g., HaarWavelets) with the desired number of scales. inp : np.ndarray Input 2D array (e.g., grayscale image). num_levels : int The number of decomposition levels to perform. Returns ------- coeffs : np.ndarray Final coefficient array (same size as inp) with the pyramid layout. """ out = np.copy(inp) ny, nx = out.shape[:2] for level in range(num_levels): # Process the current top-left subarray sub = out[:ny, :nx] sub_out = wavelet.analysis1(sub) out[:ny, :nx] = sub_out # Update region size for next level (halve each dimension) nx = max(1, nx // 2) ny = max(1, ny // 2) return out .. rst-class:: sphx-glr-script-out .. code-block:: none [Wavelets 2D Haar Test] Max error after 3-scale decomposition: 1.3322676295501878e-15 .. GENERATED FROM PYTHON SOURCE LINES 254-256 1-Level Decomposition ~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 256-267 .. code-block:: Python wavelet1 = HaarWavelets(scales=1) coeffs1 = pyramid_with_quadrant_embedding_levels(wavelet1, image_gray, 1) plt.figure(figsize=(8, 8)) plt.imshow(coeffs1, cmap='gray', interpolation='nearest') plt.title("Haar 1-Level Decomposition", fontsize=14) plt.axis('off') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_006.png :alt: Haar 1-Level Decomposition :srcset: /auto_examples/images/sphx_glr_009_decompose_module_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 268-270 2-Level Decomposition ~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 270-281 .. code-block:: Python wavelet2 = HaarWavelets(scales=2) coeffs2 = pyramid_with_quadrant_embedding_levels(wavelet2, image_gray, 2) plt.figure(figsize=(8, 8)) plt.imshow(coeffs2, cmap='gray', interpolation='nearest') plt.title("Haar 2-Level Decomposition", fontsize=14) plt.axis('off') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_007.png :alt: Haar 2-Level Decomposition :srcset: /auto_examples/images/sphx_glr_009_decompose_module_007.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 282-284 3-Level Decomposition ~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 284-294 .. code-block:: Python wavelet3 = HaarWavelets(scales=3) coeffs3 = pyramid_with_quadrant_embedding_levels(wavelet3, image_gray, 3) plt.figure(figsize=(8, 8)) plt.imshow(coeffs3, cmap='gray', interpolation='nearest') plt.title("Haar 3-Level Decomposition", fontsize=14) plt.axis('off') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_009_decompose_module_008.png :alt: Haar 3-Level Decomposition :srcset: /auto_examples/images/sphx_glr_009_decompose_module_008.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 15.304 seconds) .. _sphx_glr_download_auto_examples_009_decompose_module.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/splineops/splineops.github.io/main?urlpath=lab/tree/notebooks_binder/auto_examples/009_decompose_module.ipynb :alt: Launch binder :width: 150 px .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../lite/lab/index.html?path=auto_examples/009_decompose_module.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 009_decompose_module.ipynb <009_decompose_module.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 009_decompose_module.py <009_decompose_module.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 009_decompose_module.zip <009_decompose_module.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_