前言
SVD其实和PCA类似,就是丢入一个特征矩阵 X ,输出另外一个特征矩阵 X′ , X′ 的维度要比原来的X 要低。并且里面的变量都是原来的变量的线性组合,所以含义也变得不好解释。
简单来说就是数据压缩,特征降维的一种技术,很简单。本次使用它来进行图像压缩。
现在很多手机拍的图片都很大,占用内存,一个个去调整会很慢,那么可以用python进行批量处理。
本次就演示一下怎么用SVD进行图像压缩。
代码实现
SVD的实现都不需要skleran库,numpy库就够了。
导入包,然后自定义压缩图片的函数
import numpy as np
import matplotlib.pyplot as plt
from skimage import iodef svd_image_compression(image_path, k):"""使用 SVD 对图像进行压缩。参数:- image_path: 图像文件路径。- k: 选择的奇异值数量,用于压缩。返回:- 重构后的图像。"""# 读取图像img = io.imread(image_path)# 如果是彩色图像,将其转换为浮点类型 (0-1)img = img.astype(float) / 255.0# 初始化一个存储重建图像的数组img_reconstructed = np.zeros_like(img)# 对每个颜色通道进行 SVD 压缩for i in range(3): # 对于 RGB 的每一个通道# 进行奇异值分解U, S, Vt = np.linalg.svd(img[:, :, i], full_matrices=False)# 只保留前 k 个奇异值S_k = np.diag(S[:k])U_k = U[:, :k]Vt_k = Vt[:k, :]# 重建图像img_reconstructed[:, :, i] = np.dot(U_k, np.dot(S_k, Vt_k))# 确保像素值在 0 到 1 之间img_reconstructed = np.clip(img_reconstructed, 0, 1)return img_reconstructed
这个函数就2个参数,一个是图片的文件路径,一个是K值,也就是压缩图片的大小。这个值越大,图片越大。
我就用我之前吃鸡游戏的截图来实验一下好了:
# 加载和压缩图像
image_path = '还在.png'
k = 100 # 保留的奇异值数量
compressed_img = svd_image_compression(image_path, k)# 显示原始和压缩的图像
original_img = io.imread(image_path).astype(float) / 255.0plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(original_img)
plt.axis('off')plt.subplot(1, 2, 2)
plt.title(f'Compressed Image (k={k})')
plt.imshow(compressed_img)
plt.axis('off')plt.show()
我k取的100,可以发现确实图片变得模糊了一点点。
然后我们把图片向量保存为压缩后的图片:
from PIL import Image# 将图像数据转换为 0-255 范围,并转换为整数类型
compressed_img_int = (compressed_img * 255).astype(np.uint8)
# 使用 PIL 库保存为 JPEG 格式
compressed_image_pil = Image.fromarray(compressed_img_int)
compressed_image_pil.save('compressed_image.jpg', quality=85)
这样你本地同文件下就会多了一张图片,名称为compressed_image.jpg,可以看到其内存比原来少将近5倍。
就模糊了一点,但是内存占用变小了不少。
。
很方便。可以把上面代码打包为函数,然后用os遍历文件夹里面所有的图片,就可以实现自动化压缩全部图片了。