一堆博客(下方推荐栏中)说奇异值分解(SVD)能用于图片压缩,判断方法无一例外都是肉眼观测,例如
通过肉眼观察,奇异值个数越少,图片越模糊,因此SVD能够压缩图片。
emm……
判断能不能压缩图片,不看压缩后的图片文件大小,而是看图片的模糊程度??
问题:SVD能否压缩图片(文件大小)?
方法:
参考SVD Image Compression, Explained | dmicz devblog这篇博客,该博客的代码在GitHub - dmicz/devblognotebooks: Repository of notebooks featured on dmicz.github.io。
先将图片转化为灰度图并保存,作为原始图片,之后分别取前1个至350个奇异值重构图片,并将重构后的图片储存起来,读取储存后的图片文件大小,并画图。示例代码如下
# 保存原图
cv2.imwrite("origin_cat.png", image)
# SVD
U, S, Vt = np.linalg.svd(image, full_matrices=False)
pic_size = []
for n in range(1,351):
# 重构图片
reconstructed = np.matrix(U[:, :n]) * np.diag(S[:n]) * np.matrix(Vt[:n, :])
#保存重构后的图片
cv2.imwrite("reconstructed_cat.png", reconstructed)
# 获取图片文件大小
pic_size.append(os.stat("reconstructed_cat.png").st_size)
plt.plot(pic_size)
plt.xlabel("奇异值个数")
plt.ylabel("文件大小/B")
plt.axhline(os.stat("origin_cat.png").st_size,color='red', linestyle='dashed')
结果如下图所示,X轴为奇异值个数,Y轴为重构后的图片文件大小,红色虚线为原图文件大小,约57000B,即56KB。
可以看出,当奇异值个数小于40时,重构后的图片文件大小比原图更小,然而当奇异值个数在40至250之间时,重构后图片文件居然比原文件更大。之后随着奇异值个数的继续增加,重构后的图片才与原文件大小相同。
结论:
虽然直觉判断SVD能够压缩图片,并且奇异值个数越少,重构后图片越小;奇异值个数越多,重构后图片越大。
但试验结果表明,SVD不一定能压缩图片;
不一定奇异值个数越少,重构后图片越小,甚至重构后的图片可能比原图还大。
( 之前看到过这样一种解释,和这篇博客差不多,对于一张400×400的图片,取K个奇异值,则U、S、V矩阵中分别有400×K、K、K×400个元素,总共801×K个。原图有400×400=160000个元素,只要
801×K ≤ 160000,即K ≤ 199,
就能实现压缩,当K > 199时,SVD的总元素个数多于原图,就无法实现压缩的目的。
但就算这样,801×K 是单调递增的线性函数,文件大小也应该越来越大,而不是先变大后变小。。
非常希望有人能说明该现象产生的原因,能给出证据就更好了;)