移不变小波去噪#

离散小波变换不是 平移不变性 的。可以通过未抽取的小波变换(也称为平稳小波变换)来实现平移不变性,但这会增加冗余(即小波系数多于输入图像像素)。在离散小波变换的图像去噪背景下,近似平移不变性的另一种方法是使用称为“循环平移”的技术。这涉及对以下3步过程的结果进行平均,适用于多个空间平移,n:

  1. (循环地) 将信号移动一定量,n

  2. 应用去噪

  3. 应用逆移位

对于2D图像去噪,我们在这里证明,这种循环平移可以显著提高质量,其中大部分增益仅通过在每个轴上平均平移n=0和n=1即可实现。

Noisy PSNR=16.51, Denoised: no cycle shifts PSNR=26.33, Denoised: 2x2 shifts PSNR=27.22, Denoised: 4x4 shifts PSNR=27.62, Denoised: 6x6 shifts PSNR=27.68
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.01045549921308173..0.8356522405833259].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.012952752545302242..0.8368206901283463].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.005793614321844774..0.8381866612550969].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.004121155579357938..0.8379893559145168].

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()

脚本总运行时间: (0 分钟 0.546 秒)

由 Sphinx-Gallery 生成的图库