机器学习之实战篇——图像压缩(K-means聚类算法)
- 0. 文章传送
- 1.实验任务
- 2.实验思想
- 3.实验过程
0. 文章传送
机器学习之监督学习(一)线性回归、多项式回归、算法优化[巨详细笔记]
机器学习之监督学习(二)二元逻辑回归
机器学习之监督学习(三)神经网络基础
机器学习之监督学习(四)决策树和随机森林
机器学习之实战篇——预测二手房房价(线性回归)
机器学习之实战篇——肿瘤良性/恶性分类器(二元逻辑回归)
机器学习之实战篇——MNIST手写数字0~9识别(全连接神经网络模型)
机器学习之非监督学习(一)K-means 聚类算法
1.实验任务
图像和实验文件打包如下:
通过百度网盘分享的文件:bird.zip
链接:https://pan.baidu.com/s/1RK1AF5iY8Pfi_tFxf-bLyw?pwd=tmdt
提取码:tmdt
2.实验思想
使用聚类算法进行图像压缩的思想:
①对于每一个像素点,表示其颜色需要存储三个颜色通道的值,每个值取值为范围0~255的整数,需要8bit(1byte)的存储空间,故对于原始图像共占128×128×1×3
=48kb的存储空间。通过图片属性可以查看其大小约为36kb,这是因为PNG 格式采用了无损压缩技术。虽然原始图像未压缩时大约占用 48 KB,但由于压缩,实际存储在计算机上的文件大小会小于这个值。
②进行图像压缩,需要减少像素点颜色的种类,本案例中假设压缩后颜色种类为16,假设用整数0~15表示每个整数可以用4bit(即0.5byte)表示,对于压缩后的图片,每个像素点只需存储相应的颜色编号,因此占据的存储空间为128×128×0.5+(16×1×3)≈ 8KB,大小仅仅是原始图像的 1 6 \frac{1}{6} 61!
③因此可以采用K-means聚类算法,数据集由包含三个颜色分量特征的128×128个像素点构成,设置目标聚类类别K=16,并使用编写的kmeans.py中的run_kMeans函数实现聚类算法。
3.实验过程
手动编写的kmeans模块,实现k-means聚类算法
#kmeans.py
import numpy as np
import matplotlib.pyplot as plt
# 计算每个数据点所归属的簇
def find_closest_centroids(X, centroids):
K = centroids.shape[0]
m = X.shape[0]
idx = np.zeros(m, dtype=int)
for i in range(m):
idx[i] = np.argmin(np.sum((X[i] - centroids) ** 2, axis=1))
return idx
# 根据当前分类情况计算新的簇心
def compute_centroids(X, idx, K):
m, n = X.shape
centroids = np.zeros((K, n))
for k in range(K):
cond = (idx == k)
if cond.any():
X_k = X[cond]
centroids[k] = np.mean(X_k, axis=0)
else: # 如果没有点被分配到这个簇,则随机选择一个点作为新的簇心
centroids[k] = X[np.random.choice(X.shape[0])]
return centroids
# 随机初始化簇心
def kMeans_init_centroids(X, K):
randidx = np.random.permutation(X.shape[0])
centroids = X[randidx[:K]]
return centroids
# 成本函数
def KMeans_compute_cost(X, centroids, idx):
m = X.shape[0]
cost = 0
for i in range(m):
K_idx = idx[i]
X_centroid = centroids[K_idx]
cost += np.sum((X_centroid - X[i]) ** 2)
return cost / m
# 运行 K-means 聚类算法
def run_kMeans(X, K, max_iters=10, test_times=10):
m, n = X.shape
min_cost = float('inf')
best_idx = np.zeros(m)
best_centroids = np.zeros((K, n))
for j in range(test_times):
print(f'K-Means test {j}/{test_times - 1}:')
initial_centroids = kMeans_init_centroids(X, K)
centroids = initial_centroids
for i in range(max_iters):
print(f' K-Means iteration {i}/{max_iters - 1}')
idx = find_closest_centroids(X, centroids)
centroids = compute_centroids(X, idx, K)
cost = KMeans_compute_cost(X, centroids, idx)
if cost < min_cost:
min_cost = cost
best_idx = idx
best_centroids = centroids
print(f'cost: {cost}, min_cost: {min_cost}')
return best_centroids, best_idx
导入所需模块
#导入所需模块
import numpy as np
import matplotlib.pyplot as plt
import kmeans as km
处理原始图像作为数据集
#将小鸟图读取为像素矩阵
bird=plt.imread('bird.png')
print(bird)
print(f'bird.shape:{bird.shape}')
原始小鸟彩色图片分辨率为128*128,RGB三个颜色通道值都已进行归一化处理(÷255)
注:因为png格式的图片以浮点数形式存储,而jpeg图像以整数(0~255)存储
#进行聚类之前,先将128*128*3的像素矩阵转化为(128*128=16384)*3的二维特征矩阵
bird_X=bird.reshape((128*128,3))
bird_X
运行聚类算法
K=16
color_centroids, color_idx=km.run_kMeans(bird_X,K)
使用聚类结果进行图像压缩
bird_compressed_X=color_centroids[color_idx]
bird_compressed=bird_compressed_X.reshape((128,128,3))
plt.imshow(bird_compressed)
对比压缩前后图片
# Display original image
fig, ax = plt.subplots(1,2, figsize=(8,8))
plt.axis('off')
ax[0].imshow(bird)
ax[0].set_title('Original')
ax[0].set_axis_off()
# Display compressed image
ax[1].imshow(bird_compressed)
ax[1].set_title('Compressed with %d colours'%K)
ax[1].set_axis_off()
#%% md
可以看到压缩后的图像大体上还是保留了原图像的主要特征,但大大节省了存储空间!