玩命加载中...
### 3. NMF压缩图像
非负矩阵分解(NMF)是一个常用的对矩阵进行填充、平滑的算法。一个著名的案例就是Netflix利用NMF来填充“用户-电影”矩阵。这里,我们将对三个颜色逐一进行矩阵分解。
$$d\_{\text{Red}}= P\_{\text{Red}} Q\_{\text{Red}}$$
这里$d\_{\text{Red}}$是$600\times 800$的矩阵,$P\_{\text{Red}}$是$600\times K$的非负矩阵,$Q\_{\text{Red}}$是$K\times 800$的非负矩阵,其中$K$的矩阵分解中成分的个数。通常成分个数越多,拟合效果越好。
假如这个$600\times 800$的图像中每个像素点的颜色都不一样,那么我们需要
$$800\times 600 \times 3 = 1440000$$
个数来表示这个图像。对于NMF压缩之后的图像,我们只需要
$$600 \times K \times 3 + K \times 800 \times 3$$
个数来表示。在$K$较小时,比如100以内,NMF的压缩效率明显优于K Means。
下面,我们就来看看NMF压缩后的图像的视觉效果。
下面的函数`NMFImage(d, num_components)`就可以用来生成根据NMF压缩得到的图像。
```python
from sklearn.decomposition import NMF
def NMFImage(d, num_components):
w, h, c = d.shape
new_img = d.copy()
for i in range(c):
nmf = NMF(n_components=num_components)
P = nmf.fit_transform(d[:, :, i])
Q = nmf.components_
new_img[:, : ,i] = np.clip(P @ Q, 0, 1)
return {'new_image': new_img}
```
运行以上函数,我们可以看看在不同的成分个数取值之下,图像压缩的效果。
```python
plt.figure(figsize=(12, 9))
plt.imshow(d); plt.axis('off')
plt.show()
for i in [1, 2, 3]:
print('Number of components:', i)
out = NMFImage(d, i)
new_image = out['new_image']
plt.figure(figsize=(12, 9))
plt.imshow(new_image); plt.axis('off')
plt.show()
```
`Number of components: 1`
`Number of components: 2`
`Number of components: 3`
`Number of components: 5`
`Number of components: 10`
`Number of components: 20`
`Number of components: 80`
`Number of components: 150`
### 4. 完整代码
**点击[这里](http://sofasofa.io/tutorials/image_compression/taibei101.jpg)下载实验图片**。
```python
import numpy as np
import matplotlib.pyplot as plt
from skimage import io
from sklearn.cluster import KMeans
from sklearn.decomposition import NMF
# 利用K Means进行压缩
def KMeansImage(d, n_colors):
w, h, c = d.shape
dd = np.reshape(d, (w * h, c))
km = KMeans(n_clusters=n_colors)
km.fit(dd)
labels = km.predict(dd)
centers = km.cluster_centers_
new_img = d.copy()
for i in range(w):
for j in range(h):
ij = i * h + j
new_img[i][j] = centers[labels[ij]]
return {'new_image': new_img, 'center_colors': centers}
# 利用NMF进行压缩
def NMFImage(d, n_components):
w, h, c = d.shape
new_img = d.copy()
for i in range(c):
nmf = NMF(n_components=n_components)
P = nmf.fit_transform(d[:, :, i])
Q = nmf.components_
new_img[:, : ,i] = np.clip(P @ Q, 0, 1)
return {'new_image': new_img}
# 查看K Means在不同聚类个数下的视觉效果
plt.figure(figsize=(12, 9))
plt.imshow(d); plt.axis('off')
plt.show()
for i in [2, 3, 5, 10, 20, 30]:
print('Number of clusters:', i)
out = KMeansImage(d, i)
centers, new_image = out['center_colors'], out['new_image']
plt.figure(figsize=(12, 1))
plt.imshow([centers]); plt.axis('off')
plt.show()
plt.figure(figsize=(12, 9))
plt.imshow(new_image); plt.axis('off')
plt.show()
# 查看NMF在不同成分个数下的视觉效果
plt.figure(figsize=(12, 9))
plt.imshow(d); plt.axis('off')
plt.show()
for i in [1, 2, 3, 5, 10, 20, 30, 50, 80, 150]:
print('Number of components:', i)
out = NMFImage(d, i)
new_image = out['new_image']
plt.figure(figsize=(12, 9))
plt.imshow(new_image); plt.axis('off')
plt.show()
```