forked from SherlockUnknowEn/ImageCompress
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathKMCompress.py
executable file
·151 lines (129 loc) · 4.1 KB
/
KMCompress.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# -*- coding: utf-8 -*-
# @Time : 2017/8/28 下午6:18
# @Author : fj
# @Site :
# @File : KMCompress.py
# @Software: PyCharm
import numpy as np
from PIL import Image
import random
class KMCompress():
def __init__(self):
self.centroids = None #簇中心 (K, c)
self.data = None #压缩后的数据 (h*w, c)
self.cen_idx = None #压缩后的数据对应簇中心的下标(h*w, 1)
self.shape = None #原图的shape
def compress(self, path, K=16, iter=3):
'''
压缩图像
:param path: 图像路径
:param K: K簇,压缩后图像使用K个像素点表示全图
:param iter: 迭代计算次数
:return: None
'''
X, self.shape = self.__image_to_matrix(path)
centroids = self.__init_random_centroids(X, K)
for i in range(iter):
print(' ====> ' + str((i+1.0)*100 / (iter + 1)) + '%')
cen_idx = self.__find_closest_centroids(X, centroids)
centroids = self.__move_centroids(X, cen_idx, K)
print(' ====> 99%')
cen_idx = self.__find_closest_centroids(X, centroids)
self.cen_idx = cen_idx
self.centroids = centroids
self.__fill_data()
def __fill_data(self):
m = self.cen_idx.shape[0]
channel = self.shape[2]
self.data = np.zeros((m, channel))
for i in range(m):
self.data[i] = self.centroids[int(self.cen_idx[i])]
def __image_to_matrix(self, path):
'''
加载图片
:param path:
:return: 图像矩阵 (h * w, c)
'''
img = Image.open(path)
w, h = img.size
if img.mode == 'RGB':
shape = (h, w, 3)
elif img.mode == 'L':
shape = (h, w, 1)
return np.asmatrix(img.getdata(), dtype='float'), shape
def __init_random_centroids(self, X, K):
'''
初始化簇中心
:param X: 图像矩阵 (h*w, c)
:param K:
:return: 簇中心(K, c)
'''
m, n = X.shape
sh = list(range(m))
random.shuffle(sh)
centroids = []
for i in range(K):
centroids.append(X[sh[i]])
return (np.asarray(centroids))[:,0,:] #list 转换成Matrix
def __find_closest_centroids(self, img, centroids):
'''
计算图像每个像素点对应的簇中心下标
:param img:
:param centroids: (h*w, 1)
:return: 图像每个像素点对应的簇中心下标
'''
m, n = img.shape
K, _ = centroids.shape
cen_idx = np.zeros([m, 1], dtype='int')
for i in range(m):
M = np.full([K, n], img[i])
err = M - centroids
distance = np.multiply(err, err).sum(axis=1)
cen_idx[i] = distance.argmin() #最小列索引
return cen_idx
def __move_centroids(self, img, cen_idx, K):
'''
更新簇中心
:param img:
:param cen_idx: 图像每个像素点对应的簇中心下标
:param K: K簇
:return: 簇中心矩阵 (K, c)
'''
m, n = img.shape
times = np.zeros([K, 1], dtype='int')
centroids = np.zeros([K, n], dtype='float')
for i in range(m):
idx = int(cen_idx[i])
centroids[idx] = centroids[idx] + img[i]
times[idx] = times[idx] + 1
while times.min() == 0: #避免除零异常
times[times.argmin()] = 1
centroids = centroids / times
return centroids
def get_img(self):
'''
返回图像文件
:param M:
:param shape:
:return:
'''
img = np.reshape(np.asarray(self.data), self.shape)
return Image.fromarray(img.astype(np.uint8))
def save(self, path):
'''
#TODO 字典+二进制压缩存储图片
:param path:
:return:
'''
pass
def load(self, path):
'''
TODO 读取压缩后的图片
:param path:
:return:
'''
pass
a = KMCompress()
a.compress('./b.jpg', iter=10)
a.get_img().save('./compress_b.jpg')
print('done...')