前面我们介绍过了K-Means,知道在机器学习中经常使用它做聚类。那么在计算机视觉中,也有使用这个算法的应用,那就是图像分割。
所谓的图像分割,就是算法根据图像的颜色、形状、纹理来进行划分区域,也就是对图像的像素进行聚类。如果一个区域内的像素差异小,那么它们的相似度就高;反之,也一样的道理。因此,就利用这一特性来做图像的分割。
这里我们先使用2聚类来模拟生成灰度化后的图。方法很简单,就是当聚类的结果为0则为255,当聚类结果为1时则为127.
import numpy as np
import PIL.Image as image
from sklearn.cluster import KMeans
from sklearn import preprocessing
def load_data(filePath):
f = open(filePath,'rb')
data = []
img = image.open(f)
width, height = img.size
for x in range(width):
for y in range(height):
c1, c2, c3 = img.getpixel((x, y))
data.append([c1, c2, c3])
f.close()
# 采用Min-Max规范化
mm = preprocessing.MinMaxScaler()
data = mm.fit_transform(data)
return np.mat(data), width, height
img, width, height = load_data('./test.jpg')
# 进行2聚类
kmeans =KMeans(n_clusters=2)
kmeans.fit(img)
label = kmeans.predict(img)
# 将图像聚类结果,转化成图像尺寸的矩阵
label = label.reshape([width, height])
# 创建个新图像pic_mark,用来保存图像聚类的结果,并设置不同的灰度值
pic_mark = image.new("L", (width, height))
for x in range(width):
for y in range(height):
# 根据类别设置图像灰度, 类别0 灰度值为255, 类别1 灰度值为127
pic_mark.putpixel((x, y), int(256/(label[x][y]+1))-1)
pic_mark.save("result.jpg", "JPEG")
那么,如果我们想进增加多几个聚类标识,那么只需要多增加聚类的数目就行了。那么之后根据label对图像的颜色做变换,就可以分割出多姿多彩的图片。
import numpy as np
import PIL.Image as image
from sklearn.cluster import KMeans
from sklearn import preprocessing
import matplotlib.image as mpimg
def load_data(filePath):
f = open(filePath,'rb')
data = []
img = image.open(f)
width, height = img.size
for x in range(width):
for y in range(height):
c1, c2, c3 = img.getpixel((x, y))
data.append([(c1+1)/256.0, (c2+1)/256.0, (c3+1)/256.0])
f.close()
return np.mat(data), width, height
img, width, height = load_data('./test.jpg')
#进行16个聚类
kmeans =KMeans(n_clusters=16)
label = kmeans.fit_predict(img)
label = label.reshape([width, height])
# 创建个新图像img,用来保存图像聚类压缩后的结果
img=image.new('RGB', (width, height))
for x in range(width):
for y in range(height):
c1 = kmeans.cluster_centers_[label[x, y], 0]
c2 = kmeans.cluster_centers_[label[x, y], 1]
c3 = kmeans.cluster_centers_[label[x, y], 2]
img.putpixel((x, y), (int(c1*256)-1, int(c2*256)-1, int(c3*256)-1))
img.save('result.jpg')
可以看到,我们这里使用了自己的方法
更改RGB三个通道的数值:+1 / 256,这样数值就会处于0-1之间,对其进行规范化。这样进行规范化后,在后续也可以进行反变换来实现色彩的还原。