任务描述
本关任务:编写一个程序对图像进行分割。
原图如下:
分割图像如下:
相关知识
为了完成本关任务,你需要掌握:
-
聚类与图像分割;
-
图像的基础操作;
-
如何使用 GaussianMixture。
聚类与图像分割
图像分割非常好理解,如上面的图所示,就是将图像划分成若干个不同的部分(分割结果可以看出将原图划分成了 3 个部分:道路、树林、天空)。
那么图像分割怎样和聚类扯上关系呢?很简单,我们知道一副彩色图像是由多个像素点组成的。若把每个像素点看成是一个样本的话,我们就可以通过聚类的方式给每个像素点打上簇标记(比如 0,1,2)。然后再根据簇标记将像素点设置成想要的颜色(比如簇标记为 0 的设置成黄色,簇标记为 1 的设置成绿色,簇标记为 2 的设置成蓝色),然后可视化出来就能得到图像分割的效果。
那么怎样将一副图像转换成我们通常想要的类似表格的数据呢?也很简单,一副彩色图像是由多个像素点组成的,而一个像素点一般是由 R,G,B 三个通道组成的。那么我们可以把每一个像素点看成是数据集中的一个样本,每个样本包含 3 个特征( RGB 三个通道的值)。所以如果一副彩色图的高是 200,宽是 300。则该图可以看成是一个 60000 行,3 列的数据集。有了我们喜闻乐见的表格数据后,就可以将数据传递给聚类算法进行聚类了。
如果你对数字图像处理中的阈值化感兴趣,可以 点这里 学习怎样用另一种思来实现图像分割。
图像的基础操作
我们可以使用 PIL 来对图像进行操作。如果你想读取一幅图或者保存一副图,代码如下:
from PIL import Image
# 读取road.jpg到im变量中
im = Image.open('road.jpg')
# 将im保存为new_road.jpg
im.save('new_road.jpg')
值得注意的是,当使用 open 函数读取到图像后,我们不能直接将图像传给 sklearn 的聚类算法接口。因为此时的 im 不是 ndarray 或者 list ,而且 im 的形状不是喜闻乐见的表格的形状。所以需要进行转换,代码如下:
import numpy as np
# 将im转换成ndarray
img = np.array(im)
# 将img变形为[-1, 3]的shape,并保存至img_reshape
img_reshape = img.reshape(-1, 3)
当聚类算法给出结果后,我们需要根据聚类结果给图像上色,代码如下:
# pred为聚类算法的预测结果,将簇为0的点设置成红色,簇为1的点设置成蓝色
img[pred == 0, :] = [255, 0, 0]
img[pred == 1, :] = [0, 0, 255]
由于 img 为 ndarray,我们需要将其转成 Image 类型才能使用 save 函数实现保存图片的功能。转换代码如下:
im = Image.fromarray(img.astype('uint8'))
如何使用 GaussianMixture
GaussianMixture 是 sklearn 提供的高斯混合聚类的一个类,该类的构造函数中可以根据实际需要设置很多参数。但常用的参数是 n_components 和 max_iter。其中:
- n_components :想要聚成几个簇,类型为 int;
- max_iter :迭代次数,类型为 int。
使用 GaussianMixture 进行聚类很简单,fit-predict 大法就完事了。代码如下:
# 实例化一个将数据聚成2个簇的高斯混合聚类器
gmm = GaussianMixture(2)
# 将数据传给fit函数,fit函数会计算出各个高斯分布的参数和响应系数
gmm.fit(img_reshape)
# 对数据进行聚类,簇标记为0或1(因为gmm对象想要聚成2个簇)
pred = gmm.predict(img_reshape)
# 图省事可以这样,相当于调用了fit之后调用predict
pred = gmm.fit_predict(img_reshape)
编程要求
在右侧编辑器的 begin-end 之间补充代码,你所需要完成的功能是:
-
读取
./step3/image/test.jpg
; -
将读取到的图像分割成 3 个部分。其中簇标记为 0 的部分用黄色表示;簇标记为 1 的部分用蓝色表示;簇标记为 2 的部分用绿色表示;
-
将分割后的图像保存至
./step3/dump/result.jpg
测试说明
只需将分割后的图像保存到正确的位置即可,平台内部会计算你的结果与正确答案的差异程度,差异程度小于 10 视为过关。
预期输出:你的分割结果与正确答案的差异度小于 10!
开始你的任务吧,祝你成功!
from PIL import Image
import numpy as np
from sklearn.mixture import GaussianMixture
#******** Begin *********#
im = Image.open('./step3/image/test.jpg')
img = np.array(im)
img_reshape = img.reshape(-1,3)
gmm = GaussianMixture(n_components=3,covariance_type='full')
gmm.fit(img_reshape)
pred = gmm.predict(img_reshape)
img_reshape[pred==0,:] = [255,255,0]
img_reshape[pred==1,:] = [0,0,255]
img_reshape[pred==2,:] = [0,255,0]
im = Image.fromarray(img.astype('uint8'))
im.save('./step3/dump/result.jpg')
#********* End *********#