在图像处理领域,去噪是一个重要的任务,它旨在减少图像中的噪声,恢复图像的原始特征。本文将介绍一种利用在线字典学习和多种变换方法对浣熊脸部图像碎片进行去噪的技术。首先,通过在线字典学习对图像的扭曲部分进行建模,然后利用该字典重建图像的另一部分。值得注意的是,如果从无噪声的图像开始,可能会获得更好的性能,但在这里假设这样的图像不可用。
评估图像去噪结果的常用方法是观察重建图像与原始图像之间的差异。如果重建完美,差异将呈现为高斯噪声。从图表中可以看出,使用正交匹配追踪(OMP)方法,保留两个非零系数的结果比仅保留一个系数的偏差要小(边缘看起来不那么突出)。此外,它在Frobenius范数上更接近真实值。最小角回归的结果则有更强的偏差:差异让人想起原始图像的局部强度值。阈值处理显然不适用于去噪,但在这里展示是为了说明它可以以非常高的速度产生有启发性的输出,因此可能适用于其他任务,如目标分类,其中性能不一定与可视化相关。
import numpy as np
try:
# Scipy >= 1.10
from scipy.datasets import face
except ImportError:
from scipy.misc import face
raccoon_face = face(gray=True)
# 将uint8表示转换为0到1之间的浮点表示
raccoon_face = raccoon_face / 255.0
# 降采样以提高速度
raccoon_face = (raccoon_face[::4, ::4] + raccoon_face[1::4, ::4] + raccoon_face[::4, 1::4] + raccoon_face[1::4, 1::4]) / 4.0
height, width = raccoon_face.shape
# 扭曲图像的右半部分
print("Distorting image...")
distorted = raccoon_face.copy()
distorted[:, width//2:] += 0.075 * np.random.randn(height, width//2)
Distorting image...
接下来,将展示扭曲后的图像,并从中提取参考块。这些参考块将用于后续的字典学习过程。
import matplotlib.pyplot as plt
def show_with_diff(image, reference, title):
""“辅助函数用于显示去噪”""
plt.figure(figsize=(5, 3.3))
plt.subplot(1, 2, 1)
plt.title("Image")
plt.imshow(image, vmin=0, vmax=1, cmap=plt.cm.gray, interpolation="nearest")
plt.xticks(())
plt.yticks(())
plt.subplot(1, 2, 2)
difference = image - reference
plt.title("Difference (norm: %.2f)" % np.sqrt(np.sum(difference**2)))
plt.imshow(difference, vmin=-0.5, vmax=0.5, cmap=plt.cm.PuOr, interpolation="nearest")
plt.xticks(())
plt.yticks(())
plt.suptitle(title, size=16)
plt.subplots_adjust(0.02, 0.02, 0.98, 0.79, 0.02, 0.2)
show_with_diff(distorted, raccoon_face, "Distorted image")
从图像的左半部分提取所有参考块,并对其进行标准化处理。这一步骤是为了确保字典学习过程的有效性。
from time import time
from sklearn.feature_extraction.image import extract_patches_2d
print("Extracting reference patches...")
t0 = time()
patch_size = (7, 7)
data = extract_patches_2d(distorted[:, :width//2], patch_size)
data = data.reshape(data.shape[0], -1)
data -= np.mean(data, axis=0)
data /= np.std(data, axis=0)
print(f"{data.shape[0]} patches extracted in %.2fs." % (time() - t0))
Extracting reference patches...
22692 patches extracted in 0.03s.
现在,将使用这些参考块来学习字典。字典学习是一个无监督的过程,它旨在找到一组基础元素,这些元素可以有效地表示图像数据。
from sklearn.decomposition import MiniBatchDictionaryLearning
print("Learning the dictionary...")
t0 = time()
dico = MiniBatchDictionaryLearning(n_components=50, batch_size=200, alpha=1.0, max_iter=10)
V = dico.fit(data).components_
dt = time() - t0
print(f"{dico.n_iter_} iterations / {dico.n_steps_} steps in {dt:.2f}.")
学习完字典后,将使用它来重建图像的扭曲部分。这个过程涉及到从扭曲部分提取噪声块,然后使用字典对这些块进行变换和重建。
from sklearn.feature_extraction.image import reconstruct_from_patches_2d
print("Extracting noisy patches... ")
t0 = time()
data = extract_patches_2d(distorted[:, width//2:], patch_size)
data = data.reshape(data.shape[0], -1)
intercept = np.mean(data, axis=0)
data -= intercept
print("done in %.2fs." % (time() - t0))
transform_algorithms = [
("Orthogonal Matching Pursuit\n1 atom", "omp", {"transform_n_nonzero_coefs": 1}),
("Orthogonal Matching Pursuit\n2 atoms", "omp", {"transform_n_nonzero_coefs": 2}),
("Least-angle regression\n4 atoms", "lars", {"transform_n_nonzero_coefs": 4}),
("Thresholding\nalpha=0.1", "threshold", {"transform_alpha": 0.1}),
]
reconstructions = {}
for title, transform_algorithm, kwargs in transform_algorithms:
print(title + "...")
reconstructions[title] = raccoon_face.copy()
t0 = time()
dico.set_params(transform_algorithm=transform_algorithm, **kwargs)
code = dico.transform(data)
patches = np.dot(code, V)
patches += intercept
patches = patches.reshape(len(data), *patch_size)
if transform_algorithm == "threshold":
patches -= patches.min()
patches /= patches.max()
reconstructions[title][:, width//2:] = reconstruct_from_patches_2d(patches, (height, width//2))
dt = time() - t0
print("done in %.2fs." % dt)
show_with_diff(reconstructions[title], raccoon_face, title + " (time: %.1fs)" % dt)
plt.show()
通过上述步骤,可以看到不同去噪方法的效果。正交匹配追踪(OMP)和最小角回归(LARS)是两种常见的稀疏编码方法,它们在去噪方面表现出了不同的性能。阈值处理虽然不适用于去噪,但其高速的特点使其在其他任务中具有应用价值。