📜  在Python使用奇异值分解 (SVD) 进行图像重建

📅  最后修改于: 2022-05-13 01:54:44.676000             🧑  作者: Mango

在Python使用奇异值分解 (SVD) 进行图像重建

奇异值分解又名 SVD 是众多矩阵分解技术之一,它将矩阵分解为 3 个子矩阵,即 U、S、V,其中 U 是左特征向量,S 是奇异值的对角矩阵,V 称为右特征向量。我们可以使用 NumPy 模块的linalg.svd()方法重建图像的 SVD。

使用的图像:



Python3
# import module
import requests
import cv2
import numpy as np
import matplotlib.pyplot as plt
 
# assign and open image
url = 'https://media.geeksforgeeks.org/wp-content/cdn-uploads/20210401173418/Webp-compressed.jpg'
response = requests.get(url, stream=True)
 
with open('image.png', 'wb') as f:
    f.write(response.content)
 
img = cv2.imread('image.png')
 
# Converting the image into gray scale for faster
# computation.
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
# Calculating the SVD
u, s, v = np.linalg.svd(gray_image, full_matrices=False)
 
# inspect shapes of the matrices
print(f'u.shape:{u.shape},s.shape:{s.shape},v.shape:{v.shape}')


Python3
# import module
import seaborn as sns
 
var_explained = np.round(s**2/np.sum(s**2), decimals=6)
 
# Variance explained top Singular vectors
print(f'variance Explained by Top 20 singular values:\n{var_explained[0:20]}')
 
sns.barplot(x=list(range(1, 21)),
            y=var_explained[0:20], color="dodgerblue")
 
plt.title('Variance Explained Graph')
plt.xlabel('Singular Vector', fontsize=16)
plt.ylabel('Variance Explained', fontsize=16)
plt.tight_layout()
plt.show()


Python3
# plot images with different number of components
comps = [3648, 1, 5, 10, 15, 20]
plt.figure(figsize=(12, 6))
 
for i in range(len(comps)):
    low_rank = u[:, :comps[i]] @ np.diag(s[:comps[i]]) @ v[:comps[i], :]
     
    if(i == 0):
        plt.subplot(2, 3, i+1),
        plt.imshow(low_rank, cmap='gray'),
        plt.title(f'Actual Image with n_components = {comps[i]}')
     
    else:
        plt.subplot(2, 3, i+1),
        plt.imshow(low_rank, cmap='gray'),
        plt.title(f'n_components = {comps[i]}')


输出:

u.shape:(3648, 3648),s.shape:(3648,),v.shape:(3648, 5472)

解释:

上面的输出形状表明该图像中有 3648 个线性无关的特征向量。

现在让我们以图形方式查看在奇异向量上使用的图像的方差:

蟒蛇3



# import module
import seaborn as sns
 
var_explained = np.round(s**2/np.sum(s**2), decimals=6)
 
# Variance explained top Singular vectors
print(f'variance Explained by Top 20 singular values:\n{var_explained[0:20]}')
 
sns.barplot(x=list(range(1, 21)),
            y=var_explained[0:20], color="dodgerblue")
 
plt.title('Variance Explained Graph')
plt.xlabel('Singular Vector', fontsize=16)
plt.ylabel('Variance Explained', fontsize=16)
plt.tight_layout()
plt.show()

输出:

方差解释图。

说明:上面的方差解释图清楚地表明,大约 99.77% 的信息是由第一个特征向量及其相应的特征值本身解释的。因此,非常建议仅使用前几个特征向量本身来重建图像。

在基于上述讨论的以下程序中,我们使用 SVD 重建图像:

蟒蛇3

# plot images with different number of components
comps = [3648, 1, 5, 10, 15, 20]
plt.figure(figsize=(12, 6))
 
for i in range(len(comps)):
    low_rank = u[:, :comps[i]] @ np.diag(s[:comps[i]]) @ v[:comps[i], :]
     
    if(i == 0):
        plt.subplot(2, 3, i+1),
        plt.imshow(low_rank, cmap='gray'),
        plt.title(f'Actual Image with n_components = {comps[i]}')
     
    else:
        plt.subplot(2, 3, i+1),
        plt.imshow(low_rank, cmap='gray'),
        plt.title(f'n_components = {comps[i]}')

输出:

使用 SVD 重建的图像。

解释:

  1. 尽管第一个特征向量包含 99.77% 的信息,但仅从其重建图像并不能给出清晰的图片。
  2. 使用前 15 个向量进行图像重建可以提供足够好的近似值。同样在 3648 个向量中,这大大减少了计算量,并且还压缩了图像。