SVD 是一种矩阵分解和降维的算法,通过分解矩阵找到奇异值,奇异值越大代表特征越重要。公式如下
A = U Σ V T A = U \Sigma V^T A=UΣVT
- U : 左矩阵 ( m × \times × m )
- Σ \Sigma Σ: 对角奇异值矩阵
- V:右矩阵( n × \times × n )
Sklearn 实现 SVD
import numpy as np
A = np.array([[0,1],[1,1],[1,0]])
u, s, vt = np.linalg.svd(A, full_matrices=True)
print(u.shape, s.shape, vt.shape)
SVD 可以用于图片的压缩,只保留最重要信息,从 k=1 到 k=50:
import numpy as np
import os
from PIL import Image
from tqdm import tqdm
# 定义恢复函数,由分解后的矩阵恢复到原矩阵
def restore(u, s, v, K):
'''
u:左奇异矩阵
v:右奇异矩阵
s:奇异值矩阵
K:奇异值个数
'''
m, n = len(u), len(v[0])
a = np.zeros((m, n))
for k in range(K):
uk = u[:, k].reshape(m, 1)
vk = v[k].reshape(1, n)
# 前k个奇异值的加总
a += s[k] * np.dot(uk, vk)
a = a.clip(0, 255)
return np.rint(a).astype('uint8')
A = np.array(Image.open("./mountain.png", 'r'))
# 对RGB图像进行奇异值分解
u_r, s_r, v_r = np.linalg.svd(A[:, :, 0])
u_g, s_g, v_g = np.linalg.svd(A[:, :, 1])
u_b, s_b, v_b = np.linalg.svd(A[:, :, 2])
# 使用前50个奇异值
K = 50
output_path = './svd_pic'
#
for k in tqdm(range(1, K+1)):
R = restore(u_r, s_r, v_r, k)
G = restore(u_g, s_g, v_g, k)
B = restore(u_b, s_b, v_b, k)
I = np.stack((R, G, B), axis=2)
Image.fromarray(I).save('%s/svd_%d.jpg' % (output_path, k))
显示图片
from PIL import Image
from IPython.display import display, HTML
import os
import re
import time
# Path to the folder containing images
image_folder = "./svd_pic"
# List all image files
image_files = [f for f in os.listdir(image_folder) if f.endswith(('.png', '.jpg', '.jpeg'))]
# Sort image files by the numeric part of the filename
def extract_number(filename):
match = re.search(r'_(\d+)\.', filename)
return int(match.group(1)) if match else float('inf')
image_files = sorted(image_files, key=extract_number)
# Generate HTML for horizontal display with cache busting
html = "<div style='display: flex; flex-direction: row; flex-wrap: wrap;'>"
timestamp = int(time.time()) # Use current timestamp for cache busting
for idx, image_file in enumerate(image_files):
img_path = os.path.join(image_folder, image_file)
# Add a unique query parameter to disable caching
img_url = f"{img_path}?v={timestamp}"
img = Image.open(img_path)
img_resized = img.resize((150, 150)) # Resize to 300x300
img_resized.save("temp_resized.jpg") # Save resized image temporarily
# Add image with index number overlay
html += f"""
<div style="margin: 10px; position: relative; display: inline-block; text-align: center;">
<img src="{img_url}" style="width: 150px; height: 150px; display: block;">
<div style="position: absolute; top: 10px; left: 10px;
background-color: rgba(0, 0, 0, 0.6); color: white;
padding: 5px 10px; font-size: 16px; border-radius: 5px;">
{idx + 1}
</div>
</div>
"""
html += "</div>"
# Display the images horizontally with no cache
display(HTML(html))
随着K 值增大,图片会越来越清晰。
总结
SVD 算法通过求解奇异值对矩阵进行分解,较大奇异值能表达更重要的信息。