26. Image Compression Using K-Means#
26.1. Introduction#
This challenge will target a picture of Jinli, a famous scenic spot in Chengdu. By using the Mini Batch K-Means method, similar pixels will be aggregated and replaced with the same pixel to achieve the effect of image compression.
26.2. Key Points#
Image compression
Mini Batch K-Means clustering
First, we download and import the sample picture named
challenge-7-chengdu.png
.
wget -nc "https://cdn.aibydoing.com/aibydoing/files/challenge-7-chengdu.png"
--2023-11-13 17:16:21-- https://cdn.aibydoing.com/aibydoing/files/challenge-7-chengdu.png
正在解析主机 cdn.aibydoing.com (cdn.aibydoing.com)... 198.18.7.59
正在连接 cdn.aibydoing.com (cdn.aibydoing.com)|198.18.7.59|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:1057505 (1.0M) [image/png]
正在保存至: “challenge-7-chengdu.png”
challenge-7-chengdu 100%[===================>] 1.01M 1.54MB/s 用时 0.7s
2023-11-13 17:16:23 (1.54 MB/s) - 已保存 “challenge-7-chengdu.png” [1057505/1057505])
Visualize the sample picture using Matplotlib.
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inline
chengdu = mpimg.imread('challenge-7-chengdu.png') # 将图片加载为 ndarray 数组
plt.imshow(chengdu) # 将数组还原成图像
chengdu.shape
(516, 819, 3)
After reading the picture using the
mpimg.imread
function, what is actually returned is an array of the
numpy.array
type, which represents a matrix of pixel points and contains
three elements: length, width, and height. For example, this
picture of Jinli in Chengdu contains a total of 516 rows and
819 columns, that is, 516 * 819 = 422,604 pixel points. The
height of each pixel point corresponds to the three primary
colors RGB (red, green, blue) in computer color, which are
composed of a total of 3 elements.
26.3. Data Preprocessing#
For the convenience of subsequent data processing, it is necessary to reduce the dimension of the data.
{exercise-start}
:label: chapter03_02_1
Challenge: Convert the data with shape \((516, 819, 3)\) to the data with shape \((422604, 3)\).
Hint: Use
np.reshape
to transform the data format.
{exercise-end}
"""数据格式变换
"""
## 代码开始 ### (≈ 1 行代码)
data = None
## 代码结束 ###
{solution-start} chapter03_02_1
:class: dropdown
"""Data format transformation
"""
### Start of code ###(≈ 1 line of code)
data = chengdu.reshape(516 * 819, 3)
### End of code ###
{solution-end}
Run tests
data.shape, data[10]
Expected output
((422604, 3), array([0.12941177, 0.13333334, 0.14901961], dtype=float32))
26.4. Calculation of the Number of Pixel Point Types#
Although there are 422604 pixel points, there are still many identical pixel points among them. Here we define that points with the same RGB values belong to one type, and points with any different values belong to different types.
Exercise 26.1
Challenge: Calculate the number of types among 422604 pixel points.
Hint: You can convert the data into a list type, then
convert each element into a tuple type, and finally use
the
set()
and
len()
functions for calculation. You can also complete it
according to your own ideas.
"""计算像素点种类个数
"""
def get_variety(data):
"""
参数:
预处理后像素点集合
返回:
num_variety -- 像素点种类个数
"""
### 代码开始 ### (≈ 3 行代码)
num_variety=None
### 代码结束 ###
return num_variety
Solution to Exercise 26.1
"""Calculate the number of pixel point types
"""
def get_variety(data):
"""
Parameters:
Set of preprocessed pixel points
Returns:
num_variety -- Number of pixel point types
"""
### Start of code ### (≈ 3 lines of code)
temp = data.tolist()
num_variety = len(set([tuple(t) for t in temp]))
### End of code ###
return num_variety
Run the test
get_variety(data), data[20]
Expected output
(100109, array([0.24705882, 0.23529412, 0.2627451 ], dtype=float32))
26.5. Mini Batch K-Means Clustering#
The number of pixel types is one of the main factors determining the image size. Here, the Mini Batch K-Means method is used to cluster the pixels of the image, replacing similar pixels with the same pixel value, thereby reducing the number of pixel types to achieve the effect of compressing the image.
{exercise-start}
:label: chapter03_02_3
Challenge: Use the Mini Batch K-Means clustering method to cluster the pixels and replace the pixels belonging to each category with the pixel at the center of each cluster.
Requirement: Set the number of clusters to 10.
Hint: Use the
fit()
and
predict()
functions in
MiniBatchKMeans
for clustering and the
cluster_centers_()
function for replacement. For this challenge, mostly use the
default parameters.
Read the official documentation
{exercise-end}
from sklearn.cluster import MiniBatchKMeans
## 代码开始 ### (≈ 4 行代码)
predict=None
## 代码结束 ###
new_colors = model.cluster_centers_[predict]
{solution-start} chapter03_02_3
:class: dropdown
from sklearn.cluster import MiniBatchKMeans
### Start of code ### (≈ 4 lines of code)
model = MiniBatchKMeans(10)
model.fit(data)
predict = model.predict(data)
### End of code ###
new_colors = model.cluster_centers_[predict]
{solution-end}
Run the test
# 调用前面实现计算像素点种类的函数,计算像素点更新后种类的个数
get_variety(new_colors)
Expected output
10
26.6. Comparison of the Image before and after Compression#
{exercise-start}
:label: chapter03_02_4
Challenge: Transform the pixel points that have been clustered and replaced with the category center point values back to the format before data processing, and draw pictures for comparison and display.
Hint: Use the
reshape()
function for format transformation and the
imshow()
function for drawing.
{exercise-end}
fig, ax = plt.subplots(1, 2, figsize=(16, 6))
## 代码开始 ### (≈ 3 行代码)
## 代码结束 ###
{solution-start} chapter03_02_4
:class: dropdown
fig, ax = plt.subplots(1, 2, figsize=(16, 6))
### Start of code ### (≈ 3 lines of code)
new_chengdu = new_colors.reshape(chengdu.shape)
ax[0].imshow(chengdu)
ax[1].imshow(new_chengdu)
### End of code ###
{solution-end}
Expected Output
By comparing the pictures, it is very easy to find that the picture quality has been compressed. In fact, because clustering is used, the colors of the compressed picture become 10 kinds.
Next, use the
mpimg.imsave()
function to store the compressed file and compare the volume
changes of the images before and after compression.
# 运行对比
mpimg.imsave("new_chengdu.png", new_chengdu)
!du -h new_chengdu.png
!du -h challenge-7-chengdu.png
It can be seen that after compressing the image using the Mini Batch K-Means clustering method, the volume is significantly reduced.