注意
跳到最後以下載完整範例程式碼。或透過 Binder 在您的瀏覽器中執行此範例
非局部均值去噪以保留紋理#
在此範例中,我們使用非局部均值濾鏡對太空人影像的細節進行去噪。非局部均值演算法將像素的值替換為所選其他像素值的平均值:以其他像素為中心的小塊與以感興趣的像素為中心的塊進行比較,並且僅對具有與當前塊接近的塊的像素執行平均。因此,此演算法可以很好地還原紋理,否則紋理會被其他去噪演算法模糊。
當 fast_mode
引數為 False
時,在計算塊距離時,會將空間高斯加權應用於這些塊。當 fast_mode
為 True
時,會應用更快的演算法,該演算法對這些塊採用均勻的空間加權。
對於這兩種情況,如果提供雜訊標準差 sigma
,則在計算塊距離時會減去預期的雜訊變異數。這可以適度提高影像品質。
estimate_sigma
函數可以為設定非局部均值演算法的 h
(以及可選的 sigma
) 參數提供一個良好的起點。h
是一個常數,用於控制塊權重隨著塊之間距離的衰減。較大的 h
允許在不同的塊之間進行更多平滑處理。
在此示範中,h
經過人工調整,以提供每個變體的最佳效能。

estimated noise standard deviation = 0.07824735983398969
PSNR (noisy) = 22.21
PSNR (slow) = 29.30
PSNR (slow, using sigma) = 29.72
PSNR (fast) = 28.88
PSNR (fast, using sigma) = 29.26
import numpy as np
import matplotlib.pyplot as plt
from skimage import data, img_as_float
from skimage.restoration import denoise_nl_means, estimate_sigma
from skimage.metrics import peak_signal_noise_ratio
from skimage.util import random_noise
astro = img_as_float(data.astronaut())
astro = astro[30:180, 150:300]
sigma = 0.08
noisy = random_noise(astro, var=sigma**2)
# estimate the noise standard deviation from the noisy image
sigma_est = np.mean(estimate_sigma(noisy, channel_axis=-1))
print(f'estimated noise standard deviation = {sigma_est}')
patch_kw = dict(
patch_size=5, # 5x5 patches
patch_distance=6, # 13x13 search area
channel_axis=-1,
)
# slow algorithm
denoise = denoise_nl_means(noisy, h=1.15 * sigma_est, fast_mode=False, **patch_kw)
# slow algorithm, sigma provided
denoise2 = denoise_nl_means(
noisy, h=0.8 * sigma_est, sigma=sigma_est, fast_mode=False, **patch_kw
)
# fast algorithm
denoise_fast = denoise_nl_means(noisy, h=0.8 * sigma_est, fast_mode=True, **patch_kw)
# fast algorithm, sigma provided
denoise2_fast = denoise_nl_means(
noisy, h=0.6 * sigma_est, sigma=sigma_est, fast_mode=True, **patch_kw
)
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(8, 6), sharex=True, sharey=True)
ax[0, 0].imshow(noisy)
ax[0, 0].axis('off')
ax[0, 0].set_title('noisy')
ax[0, 1].imshow(denoise)
ax[0, 1].axis('off')
ax[0, 1].set_title('non-local means\n(slow)')
ax[0, 2].imshow(denoise2)
ax[0, 2].axis('off')
ax[0, 2].set_title('non-local means\n(slow, using $\\sigma_{est}$)')
ax[1, 0].imshow(astro)
ax[1, 0].axis('off')
ax[1, 0].set_title('original\n(noise free)')
ax[1, 1].imshow(denoise_fast)
ax[1, 1].axis('off')
ax[1, 1].set_title('non-local means\n(fast)')
ax[1, 2].imshow(denoise2_fast)
ax[1, 2].axis('off')
ax[1, 2].set_title('non-local means\n(fast, using $\\sigma_{est}$)')
fig.tight_layout()
# print PSNR metric for each case
psnr_noisy = peak_signal_noise_ratio(astro, noisy)
psnr = peak_signal_noise_ratio(astro, denoise)
psnr2 = peak_signal_noise_ratio(astro, denoise2)
psnr_fast = peak_signal_noise_ratio(astro, denoise_fast)
psnr2_fast = peak_signal_noise_ratio(astro, denoise2_fast)
print(f'PSNR (noisy) = {psnr_noisy:0.2f}')
print(f'PSNR (slow) = {psnr:0.2f}')
print(f'PSNR (slow, using sigma) = {psnr2:0.2f}')
print(f'PSNR (fast) = {psnr_fast:0.2f}')
print(f'PSNR (fast, using sigma) = {psnr2_fast:0.2f}')
plt.show()
腳本的總執行時間: (0 分鐘 2.921 秒)