scikit-learn/examples/decomposition/plot_image_denoising.py

164 lines
5.6 KiB
Python
Raw Normal View History

2011-07-06 07:47:59 +08:00
"""
=========================================
Image denoising using dictionary learning
=========================================
2011-08-24 16:40:14 +08:00
2011-07-06 07:47:59 +08:00
An example comparing the effect of reconstructing noisy fragments
2011-08-23 19:05:24 +08:00
of Lena using online :ref:`DictionaryLearning` and various transform methods.
The dictionary is fitted on the distorted left half of the image, and
subsequently used to reconstruct the right half. Note that even better
performance could be achieved by fitting to an undistorted (i.e.
noiseless) image, but here we start from the assumption that it is not
available.
2011-08-24 16:07:18 +08:00
2011-08-24 16:40:14 +08:00
A common practice for evaluating the results of image denoising is by looking
at the difference between the reconstruction and the original image. If the
reconstruction is perfect this will look like gaussian noise.
It can be seen from the plots that the results of :ref:`omp` with two
non-zero coefficients is a bit less biased than when keeping only one
(the edges look less prominent). It is in addition closer from the ground
truth in Frobenius norm.
2011-08-24 16:40:14 +08:00
The result of :ref:`least_angle_regression` is much more strongly biased: the
difference is reminiscent of the local intensity value of the original image.
2011-08-25 06:57:02 +08:00
Thresholding is clearly not useful for denoising, but it is here to show that
it can produce a suggestive output with very high speed, and thus be useful
for other tasks such as object classification, where performance is not
necessarily related to visualisation.
2011-07-06 07:47:59 +08:00
"""
print __doc__
from time import time
import pylab as pl
import numpy as np
2011-12-08 03:16:04 +08:00
from scipy.misc import lena
2011-09-17 23:55:16 +08:00
from sklearn.decomposition import MiniBatchDictionaryLearning
2011-09-16 18:15:57 +08:00
from sklearn.feature_extraction.image import extract_patches_2d
from sklearn.feature_extraction.image import reconstruct_from_patches_2d
2011-07-06 07:47:59 +08:00
###############################################################################
# Load Lena image and extract patches
2011-09-16 18:15:57 +08:00
2011-12-08 03:16:04 +08:00
lena = lena() / 256.0
2011-08-23 19:05:24 +08:00
# downsample for higher speed
2011-08-22 05:07:17 +08:00
lena = lena[::2, ::2] + lena[1::2, ::2] + lena[::2, 1::2] + lena[1::2, 1::2]
lena /= 4.0
2011-08-23 01:41:15 +08:00
height, width = lena.shape
2011-08-23 19:05:24 +08:00
# Distort the right half of the image
2011-08-24 17:01:21 +08:00
print 'Distorting image...'
distorted = lena.copy()
2011-08-24 17:01:21 +08:00
distorted[:, height / 2:] += 0.075 * np.random.randn(width, height / 2)
2011-08-23 01:41:15 +08:00
# Extract all reference patches from the left half of the image
print 'Extracting reference patches...'
2011-09-16 18:15:57 +08:00
t0 = time()
2011-09-09 10:43:13 +08:00
patch_size = (7, 7)
2011-08-24 17:01:21 +08:00
data = extract_patches_2d(distorted[:, :height / 2], patch_size)
2011-07-06 07:47:59 +08:00
data = data.reshape(data.shape[0], -1)
2011-09-09 10:43:13 +08:00
data -= np.mean(data, axis=0)
data /= np.std(data, axis=0)
2011-09-16 18:15:57 +08:00
print 'done in %.2fs.' % (time() - t0)
2011-07-06 07:47:59 +08:00
###############################################################################
# Learn the dictionary from reference patches
2011-09-16 18:15:57 +08:00
print 'Learning the dictionary... '
t0 = time()
dico = MiniBatchDictionaryLearning(n_components=100, alpha=1, n_iter=500)
2011-07-06 07:47:59 +08:00
V = dico.fit(data).components_
2011-08-24 04:44:19 +08:00
dt = time() - t0
2011-09-16 18:15:57 +08:00
print 'done in %.2fs.' % dt
2011-08-24 04:44:19 +08:00
2011-08-25 01:41:28 +08:00
pl.figure(figsize=(4.2, 4))
for i, comp in enumerate(V[:100]):
pl.subplot(10, 10, i + 1)
2011-08-25 01:41:28 +08:00
pl.imshow(comp.reshape(patch_size), cmap=pl.cm.gray_r,
interpolation='nearest')
pl.xticks(())
pl.yticks(())
2011-08-24 17:01:21 +08:00
pl.suptitle('Dictionary learned from Lena patches\n' +
'Train time %.1fs on %d patches' % (dt, len(data)),
2011-08-24 04:44:19 +08:00
fontsize=16)
2011-08-25 06:57:02 +08:00
pl.subplots_adjust(0.08, 0.02, 0.92, 0.85, 0.08, 0.23)
2011-07-06 07:47:59 +08:00
2011-12-20 22:34:17 +08:00
2011-09-16 18:15:57 +08:00
###############################################################################
# Display the distorted image
2011-08-24 17:01:21 +08:00
def show_with_diff(image, reference, title):
2011-08-24 17:01:21 +08:00
"""Helper function to display denoising"""
2011-08-25 06:57:02 +08:00
pl.figure(figsize=(5, 3.3))
pl.subplot(1, 2, 1)
2011-08-24 17:01:21 +08:00
pl.title('Image')
pl.imshow(image, vmin=0, vmax=1, cmap=pl.cm.gray, interpolation='nearest')
pl.xticks(())
pl.yticks(())
pl.subplot(1, 2, 2)
2011-08-24 16:07:18 +08:00
difference = image - reference
2011-08-24 17:01:21 +08:00
pl.title('Difference (norm: %.2f)' % np.sqrt(np.sum(difference ** 2)))
2011-08-24 16:07:18 +08:00
pl.imshow(difference, vmin=-0.5, vmax=0.5, cmap=pl.cm.PuOr,
interpolation='nearest')
pl.xticks(())
pl.yticks(())
pl.suptitle(title, size=16)
2011-08-25 06:57:02 +08:00
pl.subplots_adjust(0.02, 0.02, 0.98, 0.79, 0.02, 0.2)
2011-08-24 17:01:21 +08:00
show_with_diff(distorted, lena, 'Distorted image')
2011-08-22 05:07:17 +08:00
2011-08-23 19:05:24 +08:00
###############################################################################
# Extract noisy patches and reconstruct them using the dictionary
2011-09-16 18:15:57 +08:00
2011-08-24 17:01:21 +08:00
print 'Extracting noisy patches... '
2011-09-16 18:15:57 +08:00
t0 = time()
2011-08-24 17:01:21 +08:00
data = extract_patches_2d(distorted[:, height / 2:], patch_size)
2011-09-09 10:43:13 +08:00
data = data.reshape(data.shape[0], -1)
intercept = np.mean(data, axis=0)
data -= intercept
2011-09-16 18:15:57 +08:00
print 'done in %.2fs.' % (time() - t0)
2011-08-23 19:05:24 +08:00
transform_algorithms = [
2011-08-25 06:57:02 +08:00
('Orthogonal Matching Pursuit\n1 atom', 'omp',
2011-08-25 01:41:28 +08:00
{'transform_n_nonzero_coefs': 1}),
2011-08-25 06:57:02 +08:00
('Orthogonal Matching Pursuit\n2 atoms', 'omp',
2011-08-25 01:41:28 +08:00
{'transform_n_nonzero_coefs': 2}),
('Least-angle regression\n5 atoms', 'lars',
2012-12-25 20:16:05 +08:00
{'transform_n_nonzero_coefs': 5}),
2011-08-25 06:57:02 +08:00
('Thresholding\n alpha=0.1', 'threshold', {'transform_alpha': .1})]
2011-08-23 19:05:24 +08:00
2011-08-23 01:41:15 +08:00
reconstructions = {}
2011-08-25 01:41:28 +08:00
for title, transform_algorithm, kwargs in transform_algorithms:
2011-09-16 18:15:57 +08:00
print title, '... '
2011-08-23 01:41:15 +08:00
reconstructions[title] = lena.copy()
2011-08-22 05:07:17 +08:00
t0 = time()
2011-09-09 10:43:13 +08:00
dico.set_params(transform_algorithm=transform_algorithm, **kwargs)
2011-08-25 00:21:28 +08:00
code = dico.transform(data)
2011-08-25 06:57:02 +08:00
patches = np.dot(code, V)
if transform_algorithm == 'threshold':
patches -= patches.min()
patches /= patches.max()
2011-09-09 10:43:13 +08:00
2011-08-25 06:57:02 +08:00
patches += intercept
2011-08-22 05:54:13 +08:00
patches = patches.reshape(len(data), *patch_size)
2011-08-25 06:57:02 +08:00
if transform_algorithm == 'threshold':
patches -= patches.min()
patches /= patches.max()
2011-08-24 17:01:21 +08:00
reconstructions[title][:, height / 2:] = reconstruct_from_patches_2d(
patches, (width, height / 2))
2011-08-24 04:44:19 +08:00
dt = time() - t0
2011-09-16 18:15:57 +08:00
print 'done in %.2fs.' % dt
show_with_diff(reconstructions[title], lena,
title + ' (time: %.1fs)' % dt)
2011-08-22 05:07:17 +08:00
2011-07-08 19:09:46 +08:00
pl.show()