-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompress_image.py
More file actions
120 lines (95 loc) · 3.59 KB
/
Copy pathcompress_image.py
File metadata and controls
120 lines (95 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import numpy as np
from skimage.metrics import structural_similarity as ssim
def compress_image(algo, img, k):
"""
Comprimi immagine a colori con la tecnica scelta
:param algo: nome della tecnica ('pca' o 'svd' nel nostro caso)
:param img: immagine da comprimere
:param k: numero di valori singolari da mantenere
:return: immagine compressa, rapporto di compressione
"""
# Salvataggio dimensioni immagine originale (per il calcolo del rapporto di compressione)
h, w, _ = img.shape
# Separazione canali RGB
R, G, B = img[:, :, 0], img[:, :, 1], img[:, :, 2]
# Compressione mediante tecnica scelta canale per canale
match algo:
case 'pca':
R, G, B = pca_channel(R, k), pca_channel(G, k), pca_channel(B, k)
case 'svd':
R, G, B = svd_channel(R, k), svd_channel(G, k), svd_channel(B, k)
# Ricostruzione immagine
compressed_img = np.stack((R, G, B), axis=2)
# Normalizzazione tra 0 e 1
compressed_img = np.clip(compressed_img, 0, 255)
# Dimensione originale
original_size = h * w * 3
# Dimensione compressa
match algo:
case 'pca':
compressed_size = 3 * (h * k + w * k + w)
case 'svd':
compressed_size = 3 * (h * k + k + w * k)
print(f"ALGORITHM={algo} | ORIGINAL SIZE={original_size} | COMPRESSED SIZE={compressed_size}")
# Rapporto di compressione
compression_ratio = original_size / compressed_size
return compressed_img, compression_ratio
def evaluate_compression(original, compressed):
"""
Restituisce le metriche di valutazione della compressione.
:param original: immagine originale
:param compressed: immagine compressa
:return: mse, psnr, ssim
"""
# MSE (Mean Squared Error)
mse = np.mean((original - compressed) ** 2)
# PSNR (Peak Signal-to-Noise Ratio)
if mse == 0:
psnr = float("inf")
else:
psnr = 10 * np.log10((255.0 ** 2) / mse)
# SSIM (Structural Similarity Index Measure)
original_uint8 = original.astype(np.uint8)
compressed_uint8 = compressed.astype(np.uint8)
ssim_val = ssim(original_uint8, compressed_uint8, channel_axis=2)
return mse, psnr, ssim_val
def pca_channel(channel, k):
"""
Applica la PCA a un singolo canale dell'immagine.
:param channel: matrice 2D (un singolo canale)
:param k: numero di componenti principali da mantenere
:return: canale ricostruito
"""
# Centralizzazione dei dati
mean = np.mean(channel, axis=0)
channel_centered = channel - mean
# Calcolo della matrice di covarianza
cov_matrix = np.cov(channel_centered, rowvar=False)
# Autovalori e autovettori
eigvals, eigvecs = np.linalg.eigh(cov_matrix)
# Ordinamento per autovalore decrescente
idx = np.argsort(eigvals)[::-1]
eigvecs = eigvecs[:, idx]
# Selezione dei primi k autovettori
eigvecs_k = eigvecs[:, :k]
# Proiezione nei componenti principali
Z = np.dot(channel_centered, eigvecs_k)
# Ricostruzione
channel_reconstructed = np.dot(Z, eigvecs_k.T) + mean
return channel_reconstructed
def svd_channel(channel, k):
"""
Applica SVD a un singolo canale dell'immagine.
:param channel: matrice 2D
:param k: numero di valori singolari da mantenere
:return: canale ricostruito
"""
# Decomposizione SVD
U, S, Vt = np.linalg.svd(channel, full_matrices=False)
# Troncamento ai primi k
U_k = U[:, :k]
S_k = np.diag(S[:k])
Vt_k = Vt[:k, :]
# Ricostruzione
channel_reconstructed = np.dot(U_k, np.dot(S_k, Vt_k))
return channel_reconstructed