sklearn
庫是最為常用且經(jīng)典的機器學(xué)習(xí)庫蜓肆,里面封裝了許多機器學(xué)習(xí)算法,此篇文章使用此庫中的 KMeans
算法舀奶,從而實現(xiàn)圖像的聚類分割暑竟。
本文不講理論,只談應(yīng)用育勺。
引入庫
除了 sklearn
庫之外但荤,還需要一些圖像處理的庫,我引入了如下幾個庫:
import numpy as np
import pylab as plt
import PIL.Image as image
from sklearn.cluster import KMeans
讀入圖片
我使用了 pylab
庫來讀入圖片:
img = plt.imread('E:/圖片/壁紙/001.jpg')
此時讀入的 img
是一個三維 numpy
數(shù)組涧至,其形狀為 (height, width, 3)
纱兑,其中3是指通道數(shù),即 RGB
三個通道化借。
但是,KMeans
傳入的參數(shù)必須是二維數(shù)組捡多,故蓖康,還需要將其打散為二維:
img1 = img.reshape((img.shape[0]*img.shape[1], 3))
構(gòu)建 KMeans
在此構(gòu)建時铐炫,只需要使用最簡單的方法即可:
k = 3
kmeans = KMeans(n_clusters=k)
參數(shù)有很多,我在構(gòu)建的時候除了 n_clusters
都使用的默認值:
-
n_clusters
:聚類數(shù)蒜焊,即聚為幾類
使用 KMeans
聚類
然后倒信,使用 fit()
進行訓(xùn)練:
kmeans.fit(img1)
聚類之后,有很多參數(shù)泳梆,比較重要的鳖悠,以及此處需要用到的主要有倆:
-
kmeans.labels_
:聚類的結(jié)果,是一個一維numpy
數(shù)組优妙,包含了每一個數(shù)據(jù)所屬的類別乘综。比如,如果聚3類套硼,便可能是:[0, 0, 0, 1, 2, ..., 2, 1]
-
kmeans.cluster_centers_
:迭代完成后的聚類中心卡辰,是一個2維的numpy
數(shù)組,形狀為(k, 3)
【k
是聚類數(shù)邪意,3通道】
重新填色
聚類完成之后九妈,需要將每個像素點重新填色,將同一類的像素點均填為此類聚類中心的顏色雾鬼。
在此之前萌朱,首先需要得到圖片的高度和寬度:
height = img.shape[0]
width = img.shape[1]
首先用 image.new()
重新創(chuàng)建一個圖片,其語法如下:
pic_new = image.new("RGB", (width, height))
- 第一個參數(shù):一個字符串策菜,表示圖片類型晶疼。
RGB
表示常見的RGB
彩圖;如果是L
做入,表示為灰度圖冒晰。 - 第二個參數(shù),一個長度為2的元組:高寬竟块。
然后需要用 putpixel()
方法來填充像素壶运,但是在此之前,還需要處理幾個小細節(jié):
更改數(shù)據(jù)類型
RGB圖中浪秘,每個通道都是 0-255
之間的整數(shù)蒋情,但是,kmeans.cluster_centers_
中元素類型卻是 float64
耸携,故在填充之前棵癣,還需要小小處理一番,將元素變?yōu)?int32
類型的夺衍。
center = np.zeros([k, 3])
for i in range(k):
for j in range(3):
center[i, j] = kmeans.cluster_centers_[i, j]
center = center.astype(np.int32)
直接轉(zhuǎn)變類型不太合適狈谊,因為 kmeans.cluster_centers_
畢竟是類似于一個屬性值的東西,而且這個名字太長,換一個簡短的也是好的河劝。故重新復(fù)制一份再使用 astype
更改數(shù)據(jù)類型即可壁榕。
恢復(fù)被打平的結(jié)果
上面便提到,kmeans.labels_
是一個一維數(shù)組赎瞎,但是圖片是二維的牌里,所以將其恢復(fù)過來即可:
label = kmeans.labels_.reshape((height, width))
然后便可以填充像素了:
for i in range(height):
for j in range(width):
pic_new.putpixel((j, i), tuple((center[label[i][j]])))
這里需要注意 putpixel()
方法,其的兩個參數(shù):
- 第一個參數(shù)务甥,是新圖片的坐標(biāo)牡辽,如果輸入的是
(i, j)
實際上填充的是(j, i)
處的像素,故需要倒著寫[1]敞临。 - 第二個參數(shù)态辛,在
RGB
圖像的時候,需要一個長度為3的元組哟绊,故需要tuple()
將其由numpy
轉(zhuǎn)換為元組因妙。
最后保存圖片即可:
pic_new.save("D:/K=3.jpg", "JPEG")
結(jié)果展示
我使用了王者榮耀大喬的圖片來做測試: