使用 scikit-image 应用小波变换执行图像去噪

514 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,点击查看活动详情

前言

离散的小波变换不具备平移不变性,为了实现平移不变性可以使用非抽样小波变换 (undecimated wavelet transform,也称平稳小波,stationary wavelet),但需要增加冗余的成本,即比输入图像像素更多的小波系数。为了使用离散小波变换实现图像去噪并近似平移不变性,我们也可以使用另一种称为循环旋转 (cycle-spinning) 的技术,这需要对多个空间移位结果求取均值:

  • 将信号(循环)移动量 n
  • 应用去噪 
  • 应用反向平移

使用 scikit-image restoration 模块应用小波变换执行图像去噪

在本节中,我们将看到,对于 2D 图像去噪,循环旋转技术可以令图像质量得到大幅提高,通过对每个轴上仅 n=0n=1 的偏移求取均值,就可以获取大部分图像增益:

(1) 首先,导入所有必需的 Python 模块和函数:

from skimage.restoration import (denoise_wavelet, estimate_sigma)
from skimage import data, img_as_float
from skimage.util import random_noise
from skimage.metrics import peak_signal_noise_ratio
import numpy as np
from skimage import img_as_float
import matplotlib.pylab as plt
from skimage.io import imread

(2) 读取输入图像,并在图像中添加随机噪声:

original = img_as_float(imread('3.png'))[...,:3]
sigma = 0.12
noisy = random_noise(original, var=sigma**2)

(3) 估计跨颜色通道的平均噪声标准差:

sigma_est = estimate_sigma(noisy, multichannel=True, average_sigmas=True)
print(f"Estimated Gaussian noise standard deviation = {sigma_est}")
# Estimated Gaussian noise standard deviation = 0.10885399509583953

如以上代码执行结果所示,由于对值进行了裁剪,得到的平均噪声标准差估计值比指定的 sigma 小一点。

(4) 使用 skimage.restoration 模块的 denoise_wavelet() 函数在图像上执行小波去噪。分别使用两种不同的阈值方法,即 BayesshrinkVisuShrink

im_bayes = denoise_wavelet(noisy, multichannel=True, convert2ycbcr=True,
                           method='BayesShrink', mode='soft',
                           rescale_sigma=True)
im_visushrink = denoise_wavelet(noisy, multichannel=True, convert2ycbcr=True,
                                method='VisuShrink', mode='soft',
                                sigma=sigma_est, rescale_sigma=True)

Visushrink 旨在消除具有高概率的噪声,但这会导致图像在视觉上过于光滑。使用不同阈值重复以上过程,观察得到的不同结果:

im_visushrink2 = denoise_wavelet(noisy, multichannel=True, convert2ycbcr=True,
                                 method='VisuShrink', mode='soft',
                                 sigma=sigma_est/2, rescale_sigma=True)
im_visushrink4 = denoise_wavelet(noisy, multichannel=True, convert2ycbcr=True,
                                 method='VisuShrink', mode='soft',
                                 sigma=sigma_est/4, rescale_sigma=True)

(5) 计算 PSNR 作为图像质量的指标:

psnr_noisy = peak_signal_noise_ratio(original, noisy)
psnr_bayes = peak_signal_noise_ratio(original, im_bayes)
psnr_visushrink = peak_signal_noise_ratio(original, im_visushrink)
psnr_visushrink2 = peak_signal_noise_ratio(original, im_visushrink2)
psnr_visushrink4 = peak_signal_noise_ratio(original, im_visushrink4)

(6) 绘制输入图像、输出图像以及相应的PSNR值:

plt.figure(figsize=(20,20))
plt.subplots_adjust(0,0,1,1,0.05,0.05)
plt.subplot(231), plt.imshow(original), plt.axis('off'), plt.title('Original', size=10)
plt.subplot(232), plt.imshow(noisy), plt.axis('off'), plt.title('Noisy\nPSNR={:0.4g}'.format(psnr_noisy), size=10)
plt.subplot(233), plt.imshow(im_bayes/im_bayes.max()), plt.axis('off'), plt.title('Wavelet denoising\n(BayesShrink)\nPSNR={:0.4f}'.format(psnr_bayes), size=10)
plt.subplot(234), plt.imshow(im_visushrink/im_visushrink.max()), plt.axis('off')
plt.title('Wavelet denoising\n' + r'(VisuShrink, $\sigma=\sigma_{est}$)' + '\nPSNR={:0.4g}'.format(psnr_visushrink), size=10)
plt.subplot(235), plt.imshow(im_visushrink2/im_visushrink2.max()), plt.axis('off')
plt.title('Wavelet denoising\n' + r'(VisuShrink, $\sigma=\sigma_{est}/2$)' + '\nPSNR={:0.4g}'.format(psnr_visushrink2), size=10)
plt.subplot(236), plt.imshow(im_visushrink4/im_visushrink4.max()), plt.axis('off')
plt.title('Wavelet denoising\n' + r'(VisuShrink, $\sigma=\sigma_{est}/4$)' + '\nPSNR={:0.4g}'.format(psnr_visushrink4), size=10)
plt.show()

运行以上代码,可以得到以下结果图像:

Figure_12.png