SVD与图像处理
我们都知道SVD可以用来压缩图像。如果你用python的PIL库,进行如下操作:
- 将图像转化成numpy array
- 进行SVD分解,并形成压缩后的矩阵
- 用fromarray()函数还原图像。
你会发现图像不能正常还原,得到的图像无法辨识。
原因在于我们没有将numpy array中的变量类型转换成uint8。只需要加一句
r = r.astype('uint8')
然后再调用fromarray()函数就行了。
背景知识补充 :图像像素色彩信息的保存采用的是uint8变量类型。uint8可以存储0-255范围内的整数。在SVD分解和还原过程中,数据格式会变成float,所以最后要把格式转化回uint8,才能得到正确的图像。
最基本的SVD压缩代码如下:
from PIL import Image
import numpy as np
a = Image.open('神奈川冲浪里.png')#打开图像
b = a.convert('L')#转化成可以用矩阵表示的黑白格式
matrix = np.matrix(b)#转化成二维矩阵
#svd分解
s,v,d = np.linalg.svd(matrix)
#取n个最大的奇异值,还原矩阵
n = 150
r = s[:,:n]*np.diag(v[:n])*d[:n,:]
r = r.astype('uint8')#将变量类型转化为uint8
r = Image.fromarray(r)
下面分别是a(原图像)、b(黑白图像)、r(压缩后的b)。在本例中,一个638*638的图像,只取前150个最大的奇异值,就能基本还原原来的图像b。



也可以处理彩色照片。彩色图像的每个像素的色彩信息是由R、G、B三个uint8组成,要将原始的三维数组分拆成R、G、B三个二维数组,再分别应用SVD。代码如下。
def image_compress(image,n):
r,g,b = image[:,:,0],image[:,:,1],image[:,:,2]
shape = image.shape
r,g,b = image_svd(r,n),image_svd(g,n),image_svd(b,n)
result = np.zeros(shape)
result[:,:,0]=r
result[:,:,1]=g
result[:,:,2]=b
return result
def image_svd(image,n):
image = np.matrix(image)
s,v,d = np.linalg.svd(image)
r =s[:,:n]*np.diag(v[:n])*d[:n,:]
return r
a = np.array(Image.open('神奈川冲浪里.png'))
p = image_compress(a,600)
p = Image.fromarray(p.astype('uint8'))