22.1. PCA#

22.1.1. Esempio: compressione di immagini#

Un’immagine in scala di grigio può essere rappresentata con una matrice \(\mathbf{A}\), i cui elementi rappresentano il valore di grigio di ogni pixel.

Hide code cell source
%reset -f
import numpy as np
import scipy as sp

from skimage import data, color
import matplotlib.pyplot as plt

#> Load image
#image = data.camera()
image = data.astronaut()
image = color.rgb2gray(image)

# Display the image
plt.imshow(image, cmap='gray')
plt.axis('off')
(-0.5, 511.5, 511.5, -0.5)
../../_images/d15539d1970035394b1f718ad297932c613ca3b0921d5661e4564c59114a0002.png

22.1.1.1. Preprocessing e SVD#

Viene rimosso il valore medio dall’immagine, prima di valutare la SVD della matrice \(\mathbf{A}\)

Hide code cell source
#> Preprocessing
image_avg = np.mean(image)
A = image - image_avg

#> Compute SVD
U, s, Vh = sp.linalg.svd(A, full_matrices=False)

22.1.1.2. Risultati della SVD#

I valori singolari rappresentano il contenuto energetico dei singoli modi. La somma cumulativa dei valori singolari rappresenta il contenuto energetico della

Hide code cell source
#> Show singular values and energy error
plt.figure()
plt.subplot(3,1,1)
plt.semilogy(s, 'o')
plt.title("Singular values")
plt.tight_layout()

energy = np.cumsum(s)
energy_error = np.sum(s) - np.cumsum(s)
plt.subplot(3,1,2)
plt.plot(energy/np.sum(s), 'o')
plt.title("Energy [%]")
plt.ylim(1e-2,1)
# plt.semilogy(energy_error/np.sum(s), 'o')
# plt.title("Energy error [%]")
# plt.ylim(1e-5,1)
plt.tight_layout()

storage = ( np.shape(image)[0] + np.shape(image)[1] ) * np.arange(len(s)) + np.arange(len(s))
storage_original = np.shape(image)[0] * np.shape(image)[1]
plt.subplot(3,1,3)
plt.plot(storage/storage_original, label='compressed image')
plt.plot([0, len(s)-1], [1, 1], '--', label='original_data')
plt.title("Storage [% of the original image]")
plt.tight_layout()
plt.xlabel('$n_s$')

# plt.ylim(1e-5,1)
plt.show()
../../_images/c6965c58085cc4d71bfdf313c435b306c7f61cb53c920e592c9eb51a68c74a30.png

22.1.1.3. Ricostruzione dell’immagine compressa#

Hide code cell source
#> Image reconstruction
n_svd = 100
sigmaVh_svd = np.diag(s[0:n_svd]) @  Vh[0:n_svd,:]
A_svd = U[:,0:n_svd] @ sigmaVh_svd + image_avg

print(f"\nImage reconstruction with {n_svd} singular values:")
print(f"> Energy error [% original]: {energy_error[n_svd-1]/np.sum(s)}")
print(f"> Storage      [% original]: {storage[n_svd-1]/storage_original}")
print()

plt.figure()
plt.subplot(1,2,1)
plt.imshow(A_svd, cmap='gray')
plt.axis('off')
plt.title(f"Compressed image with {n_svd} s.v.")

plt.subplot(1,2,2)
plt.imshow(image-A_svd, cmap='gray')
plt.axis('off')
plt.title("Difference")

plt.show()
Image reconstruction with 100 singular values:
> Energy error [% original]: 0.1647581016503445
> Storage      [% original]: 0.3870964050292969
../../_images/f13f70c80b4dea160b1518e19e0e9bcfcbbb4dd7aaf247870e153c2052f08e9f.png