.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/plot_11_udct_denoise.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. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_plot_11_udct_denoise.py: Curvelet-based Denoising ======================== This example shows how the UDCT curvelets transform can be used to denoise images. More precisely, an the curvelet transform of a natual image tends to have strong, localized coefficients; on the other hand, the UDCT transform of a (white Gaussian) noise realization does not map into anything really consistent in the curvelets domain. As such if we take the UDCT transform of a noisy image and apply a suitable thresholding (e.g., by retaining a given percentage of the coefficients sorted in decreasing order), the inverse UDCT transform produces a denoised version of the input image. .. GENERATED FROM PYTHON SOURCE LINES 13-16 .. code-block:: Python from __future__ import annotations .. GENERATED FROM PYTHON SOURCE LINES 17-24 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np import numpy.typing as npt import scipy as sp from curvelets.numpy import UDCT .. GENERATED FROM PYTHON SOURCE LINES 25-30 Denoising by thresholding ######################### Define function that extracts indices of the strongest coefficients to retain for thresholding in the UDCT transform .. GENERATED FROM PYTHON SOURCE LINES 30-54 .. code-block:: Python def udct_threshold_indices( cwt_vect: npt.NDArray[np.complex64], perc: float ) -> npt.NDArray[np.intp]: """ Extract linear indices of coefficients to keep based on threshold percentage. Parameters ---------- cwt_vect : numpy.ndarray UDCT coefficients (vectorized version) perc : float Percentage of coefficients being retained Returns ------- idxs : numpy.ndarray Linear indices of the strongest coefficients to retain """ n = round(cwt_vect.size * perc) return np.argsort(np.abs(cwt_vect.ravel()))[::-1][:n] .. GENERATED FROM PYTHON SOURCE LINES 55-60 Noisy image ########### Create noisy image by adding a realization of white Gaussian noise to a natural image .. GENERATED FROM PYTHON SOURCE LINES 60-69 .. code-block:: Python # Load image dorig = sp.datasets.face() dorig = dorig / dorig.max() # Add noise to image rng = np.random.default_rng(seed=0) d = np.clip(dorig + rng.normal(0, 3e-1, dorig.shape), 0, 1) .. rst-class:: sphx-glr-script-out .. code-block:: none Downloading file 'face.dat' from 'https://raw.githubusercontent.com/scipy/dataset-face/main/face.dat' to '/home/docs/.cache/scipy-data'. .. GENERATED FROM PYTHON SOURCE LINES 70-76 Denoising ######### Apply denoising by thresholding in the UDCT domain. The threshold is determined from a grayscale version of the image, and the same filter is applied to all RGB channels to preserve color relationships. .. GENERATED FROM PYTHON SOURCE LINES 76-98 .. code-block:: Python # Defined UDCT transform Cop = UDCT(shape=d.shape[:2], num_scales=4, transform_kind="real") # Convert noisy image to grayscale using standard luminance weights d_gray = 0.299 * d[..., 0] + 0.587 * d[..., 1] + 0.114 * d[..., 2] # Compute threshold indices from grayscale image perc = 0.04 cwt_gray = Cop.vect(Cop.forward(d_gray)) thresh_idxs = udct_threshold_indices(cwt_gray, perc) # Apply the same threshold filter to each RGB channel d_cwts = [] for i in range(3): cwt = Cop.vect(Cop.forward(d[..., i])) cwt_thresh = np.zeros_like(cwt) cwt_thresh[thresh_idxs] = cwt[thresh_idxs] d_cwt_raw = Cop.backward(Cop.struct(cwt_thresh)) d_cwts.append(np.clip(d_cwt_raw, 0, 1)) d_cwt = np.stack(d_cwts, axis=-1) .. GENERATED FROM PYTHON SOURCE LINES 99-106 .. code-block:: Python print( f"Correlation between noisy and clean: {sp.stats.pearsonr(d.ravel(), dorig.ravel()).statistic:.1%}" ) print( f"Correlation between denoised and clean: {sp.stats.pearsonr(d_cwt.ravel(), dorig.ravel()).statistic:.1%}" ) .. rst-class:: sphx-glr-script-out .. code-block:: none Correlation between noisy and clean: 59.7% Correlation between denoised and clean: 95.5% .. GENERATED FROM PYTHON SOURCE LINES 107-123 .. code-block:: Python fig, axs = plt.subplots(2, 3, figsize=(14, 8), sharey=True, sharex=True) axs[0, 0].imshow(dorig) axs[0, 0].set_title("Clean") axs[0, 1].imshow(d) axs[0, 1].set_title("Noisy") axs[0, 2].imshow(d_cwt) axs[0, 2].set_title("Denoised") axs[1, 0].axis("off") axs[1, 1].imshow(np.abs(d - d_cwt)) axs[1, 1].set_title("Difference") axs[1, 2].imshow(np.abs(dorig - d_cwt)) axs[1, 2].set_title("Signal leakage") for ax in axs.ravel(): ax.axis("off") ax.axis("tight") fig.tight_layout() .. image-sg:: /auto_examples/images/sphx_glr_plot_11_udct_denoise_001.png :alt: Clean, Noisy, Denoised, Difference, Signal leakage :srcset: /auto_examples/images/sphx_glr_plot_11_udct_denoise_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 5.258 seconds) .. _sphx_glr_download_auto_examples_plot_11_udct_denoise.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_11_udct_denoise.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_11_udct_denoise.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_11_udct_denoise.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_