1. 前言
數字圖片在計算機中是以矩陣形式存儲的。所以可以通過矩陣理論和矩陣算法對數字圖像進行分析和處理。本文通過對圖片進行SVD壓縮,對不同的參數下的壓縮效果進行對比。
SVD概念可以參考:《統計學習方法》–奇異值分解(Singular Value Decomposition,SVD)
2. 原理簡介
彩色圖片有3個圖層,RGB(紅、綠、藍)也就是矩陣的一個位置上存儲了3個基色的數值,由3個基色混合成不同的色彩。
通過對3個圖層矩陣,分別進行SVD近似,SVD奇異值是唯一的,可以取前 k 個最大的奇異值進行近似表達,最後再將3個圖層的矩陣數據合併,用較少的數據去表達圖片。
2.1 SVD定義
3. 實踐代碼
<code># -*- coding:utf-8 -*- # @Python Version: 3.7 # @Time: 2020/4/21 23:38 # @Author: Michael Ming # @Website: https://michael.blog.csdn.net/ # @File: 15.svd_pic_compress.py # @Reference: https://blog.csdn.net/weixin_44344462/article/details/89401727 import numpy as np import matplotlib.pyplot as plt def zip_img_by_svd(img, plotId, rate=0.8): zip_img = np.zeros(img.shape) u_shape = 0 sigma_shape = 0 vT_shape = 0 for chanel in range(3): # 3個圖層 u, sigma, v = np.linalg.svd(img[:, :, chanel]) # numpy svd函數 sigma_i = 0 temp = 0 while (temp / np.sum(sigma)) < rate: # 選取的奇異值和需要達到設定的權重 temp += sigma[sigma_i] sigma_i += 1 SigmaMat = np.zeros((sigma_i, sigma_i)) # 選取了sigma_i 最大的奇異值 for i in range(sigma_i): SigmaMat[i, i] = sigma[i] # 將奇異值填充到Sigma對角矩陣 zip_img[:, :, chanel] = u[:, 0:sigma_i].dot(SigmaMat).dot(v[0:sigma_i, :]) # 將分解得到的3個矩陣相乘,得到壓縮後的近似矩陣 u_shape = u[:, 0:sigma_i].shape sigma_shape = SigmaMat.shape vT_shape = v[0:sigma_i, :].shape for i in range(3): # 對三個通道的矩陣數值進行歸一化處理 MAX = np.max(zip_img[:, :, i]) MIN = np.min(zip_img[:, :, i]) zip_img[:, :, i] = (zip_img[:, :, i] - MIN) / (MAX - MIN) zip_img = np.round(zip_img * 255).astype("uint8") # 不乘255圖片是黑的(接近0,0,0),數據類型uint8 plt.imsave("zip_svd_img.jpg", zip_img) # 保存壓縮後的圖片 zip_rate = (img.size - 3 * ( u_shape[0] * u_shape[1] + sigma_shape[0] * sigma_shape[1] + vT_shape[0] * vT_shape[1])) / (zip_img.size) f = plt.subplot(3, 3, plotId) f.imshow(zip_img) f.set_title("SVD壓縮率 %.4f,奇異值數量:%d" % (zip_rate, sigma_i)) print("設置的壓縮率:", rate) print("使用的奇異值數量:", sigma_i) print("原始圖片大小:", img.shape) print("壓縮後用到的矩陣大小:3x({}+{}+{})".format(u_shape, sigma_shape, vT_shape)) print("壓縮率為:", zip_rate) if __name__ == '__main__': imgfile = "svd_img.jpg" plt.figure(figsize=(12, 12)) plt.rcParams['font.sans-serif'] = 'SimHei' # 消除中文亂碼 img = plt.imread(imgfile) f1 = plt.subplot(331) # 繪製子圖,3行3列,3*3個子圖,現在畫第1幅 f1.imshow(img) f1.set_title("原始圖片") for i in range(8): # 再畫8個子圖 rate = (i + 1) / 10.0 # 壓縮率 10% - 80% zip_img_by_svd(img, i + 2, rate) plt.suptitle('圖片SVD效果對比', fontsize=17, y=0.02) # y偏移距離 plt.show()/<code>
- 可以看出在使用128個奇異值的SVD壓縮情況下,就可以得到跟原圖差不多效果的圖片
- 原圖是703x800的尺寸,SVD使用的矩陣 ((703, 128)+(128, 128)+(128, 800))=208768
- 可以少使用的矩陣數據比例為(703*800*3-208768*3)/(703*800*3)= 62.88%
- 可以只用37.12%的數據量去近似表達原始圖片,是不是很酷!!!
- 在網絡傳輸圖片的過程中,終端用戶可能點擊,也可能不點擊,那我都給他們發送SVD後的圖片矩陣數據(減少了當次傳輸數據量),然後在終端進行矩陣運算得到壓縮後的圖片,當用戶點擊圖片後,再進行傳輸原圖片(1、用戶點擊是分散的,可以降低統一發送原圖的網絡擁擠現象;2、有的用戶也不會點擊,就避免了傳輸原圖,達到了壓縮的目的,節省流量)
總結難免有不足,大家可以評論區提出來一起討論。另外小編精心準備了2020最新python學習資料,大家可以關注公眾號:芝麻代理。回覆:資料分享。免費領取。