.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/filters/plot_cycle_spinning.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 Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_filters_plot_cycle_spinning.py: ================================= Shift-invariant wavelet denoising ================================= The discrete wavelet transform is not `shift-invariant`_. Shift invariance can be achieved through an undecimated wavelet transform (also called stationary wavelet transform), at cost of increased redundancy (i.e. more wavelet coefficients than input image pixels). An alternative way to approximate shift-invariance in the context of image denoising with the discrete wavelet transform is to use the technique known as "cycle spinning". This involves averaging the results of the following 3-step procedure for multiple spatial shifts, n: 1. (circularly) shift the signal by an amount, n 2. apply denoising 3. apply the inverse shift For 2D image denoising, we demonstrate here that such cycle-spinning can provide a substantial increase in quality, with much of the gain being achieved simply by averaging shifts of only n=0 and n=1 on each axis. .. _`shift-invariant`: https://en.wikipedia.org/wiki/Shift-invariant_system .. GENERATED FROM PYTHON SOURCE LINES 25-100 .. image-sg:: /auto_examples/filters/images/sphx_glr_plot_cycle_spinning_001.png :alt: Noisy PSNR=16.47, Denoised: no cycle shifts PSNR=26.42, Denoised: 2x2 shifts PSNR=27.29, Denoised: 4x4 shifts PSNR=27.67, Denoised: 6x6 shifts PSNR=27.72 :srcset: /auto_examples/filters/images/sphx_glr_plot_cycle_spinning_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). | .. code-block:: Python import matplotlib.pyplot as plt from skimage.restoration import denoise_wavelet, cycle_spin from skimage import data, img_as_float from skimage.util import random_noise from skimage.metrics import peak_signal_noise_ratio original = img_as_float(data.chelsea()[100:250, 50:300]) sigma = 0.155 noisy = random_noise(original, var=sigma**2) fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(10, 4), sharex=False, sharey=False) ax = ax.ravel() psnr_noisy = peak_signal_noise_ratio(original, noisy) ax[0].imshow(noisy) ax[0].axis('off') ax[0].set_title(f'Noisy\nPSNR={psnr_noisy:0.4g}') # Repeat denosing with different amounts of cycle spinning. e.g. # max_shift = 0 -> no cycle spinning # max_shift = 1 -> shifts of (0, 1) along each axis # max_shift = 3 -> shifts of (0, 1, 2, 3) along each axis # etc... denoise_kwargs = dict( channel_axis=-1, convert2ycbcr=True, wavelet='db1', rescale_sigma=True ) all_psnr = [] max_shifts = [0, 1, 3, 5] for n, s in enumerate(max_shifts): im_bayescs = cycle_spin( noisy, func=denoise_wavelet, max_shifts=s, func_kw=denoise_kwargs, channel_axis=-1, ) ax[n + 1].imshow(im_bayescs) ax[n + 1].axis('off') psnr = peak_signal_noise_ratio(original, im_bayescs) if s == 0: ax[n + 1].set_title(f'Denoised: no cycle shifts\nPSNR={psnr:0.4g}') else: ax[n + 1].set_title(f'Denoised: {s+1}x{s+1} shifts\nPSNR={psnr:0.4g}') all_psnr.append(psnr) # plot PSNR as a function of the degree of cycle shifting ax[5].plot(max_shifts, all_psnr, 'k.-') ax[5].set_ylabel('PSNR (dB)') ax[5].set_xlabel('max cycle shift along each axis') ax[5].grid(True) plt.subplots_adjust(wspace=0.35, hspace=0.35) # Annotate with a cyan arrow on the 6x6 case vs. no cycle shift case to # illustrate a region with reduced block-like artifact with cycle shifting arrowprops = dict( arrowstyle="simple,tail_width=0.1,head_width=0.5", connectionstyle="arc3", color='c' ) for i in [1, 4]: ax[i].annotate( "", xy=(101, 39), xycoords='data', xytext=(70, 70), textcoords='data', arrowprops=arrowprops, ) plt.show() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.111 seconds) .. _sphx_glr_download_auto_examples_filters_plot_cycle_spinning.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/scikit-image/scikit-image/v0.23.2?filepath=notebooks/auto_examples/filters/plot_cycle_spinning.ipynb :alt: Launch binder :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_cycle_spinning.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_cycle_spinning.py ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_