1. import numpy as np
    2. from PIL import Image
    3. # 载入图片
    4. img = np.array(Image.open("./1.png",'r'))
    5. print("img(原图):",img.shape)
    6. # 第一步:通道分离
    7. c_list = [img[...,i] for i in range(img.shape[-1])]
    8. def Compress(x,precent,print_shape=True,print=print):
    9. """
    10. 作用:对面二维矩阵进行压缩
    11. x: 二维矩阵
    12. precent:保留的奇异值的比例, 例如 0.9即保留前90%的奇异值
    13. print_shape和print: 可忽略,只是方便打印shape的辅助手段。
    14. """
    15. if print_shape:
    16. print = print
    17. else:
    18. print = lambda *args,**kwargs:...
    19. x = np.array(x)
    20. print("x",x.shape)
    21. U,Sigma,V_T = np.linalg.svd(x) # 奇异值分解
    22. print("U,Sigma,V_T:",U.shape,Sigma.shape,V_T.shape)
    23. # 全零矩阵,大小与目标矩阵相同。
    24. zeroimg = np.zeros(shape=(U.shape[0],V_T.shape[0]))
    25. print("zeroimg:",zeroimg.shape)
    26. assert zeroimg.shape == x.shape
    27. k = int(len(Sigma)*precent)
    28. print("k(选取的奇异值数):",k)
    29. sigma_k = np.eye(k) * Sigma[:k]
    30. U_k = U[...,:k]
    31. V_T_k = V_T[:k,...]
    32. print("sigma_k,U_k,V_T_k:",sigma_k.shape,U_k.shape,V_T_k.shape)
    33. x_re = zeroimg + U_k@sigma_k@V_T_k
    34. x_re = np.clip(x_re,0,255).astype("uint8") # 矩阵数值范围截断为0~255并设值uint8类型
    35. print("x_re:",x_re.shape)
    36. return x_re
    37. img_list = [img]
    38. for i,precent in enumerate([0.1,0.01]):
    39. print()
    40. # 第二步:对各个通道矩阵进行压缩
    41. c_re_list = []
    42. for j,x in enumerate(c_list):
    43. x_re = Compress(x,precent,print_shape=True if j==0 else False)
    44. c_re_list.append(x_re)
    45. # 第三步 重建图像
    46. img_re = np.stack(c_re_list,-1)
    47. print(f"img_re{i}(重建图片{i}):",img_re.shape)
    48. img_list.append(img_re)
    49. # 可视化
    50. import matplotlib.pyplot as plt
    51. plt.figure(figsize=(20,20))
    52. for i,img in enumerate(img_list,start=1):
    53. plt.subplot(1,len(img_list),i)
    54. plt.imshow(img)

    输出:
    image.png
    image.png