Python計算機視覺程式設計學習筆記 六 影象聚類

2020-08-09 14:20:23

所謂聚類,就是將相似的事物聚集在一 起,而將不相似的事物劃分到不同的類別的過程,是數據分析之中十分重要的一種手段。比如古典生物學之中,人們通過物種的形貌特徵將其分門別類,可以說就是 一種樸素的人工聚類。如此,我們就可以將世界上紛繁複雜的資訊,簡化爲少數方便人們理解的類別,可以說是人類認知這個世界的最基本方式之一。

在數據分析的術語之中,聚類和分類是兩種技術。分類是指我們已經知道了事物的類別,需要從樣品中學習分類的規則,是一種有指導學習;而聚類則是由我們來給定簡單的規則,從而得到分類,是一種無指導學習。兩者可以說是相反的過程。

(一)K-means聚類(K均值聚類)

定義:k-means演算法中的k代表類簇個數,means代表類簇內數據物件的均值(這種均值是一種對類簇中心的描述),因此,k-means演算法又稱爲k-均值演算法。k-means演算法是一種基於劃分的聚類演算法,以距離作爲數據物件間相似性度量的標準,即數據物件間的距離越小,則它們的相似性越高,則它們越有可能在同一個類簇。

K-Means演算法原理:
對給定的樣本集,事先確定聚類簇數K,讓簇內的樣本儘可能緊密分佈在一起,使簇間的距離儘可能大。該演算法試圖使叢集數據分爲n組獨立數據樣本,使n組叢集間的方差相等,數學描述爲最小化慣性或叢集內的平方和。K-Means作爲無監督的聚類演算法,實現較簡單,聚類效果好,因此被廣泛使用。

演算法步驟:

輸入:樣本集D,簇的數目k,最大迭代次數N;

輸出:簇劃分(k個簇,使平方誤差最小);

  1. 以隨機或猜測的方式初始化類中心ui,i=1……k;(注:採用隨機的方法實現簡單,但是簇的品質往往比較差,所以有好幾種關於中心選取的解決方案,比如先使用層次聚類進行聚類,從層次聚類中提取K個簇,並用這些簇的質心作爲初始質心。也有通過使類內總方差最小的方式,選擇方差最小的類中心。)

  2. 將每個數據點歸併到離它距離最近的類中心所屬的類ci;
    (注:常用的距離度量方法包括:歐幾裡得距離和餘弦相似度。兩者都是評定個體間差異的大小的。歐幾裡得距離度量會受指標不同單位刻度的影響,所以一般需要先進行標準化。餘弦相似度傾向給出更優解。)

  3. 對所有屬於該類的數據點求平均,將平均值作爲新的類中心;

  4. 重複步驟(2)和步驟(3)直到收斂。

K-means試圖使類內總方差最小:

V=ikxjcixjμi2V= \sum_{i}^{k}\sum_{x_{j}\in c_{i}}^{}(x_{j}-\mu _{i})^{2}

其中, xjxj​是輸入數據,並且是向量。該演算法是啓發式提煉演算法,在很多情形下都適用,但是不能保證得到最優的結果。爲了避免初始化類中心時沒選取好類中心初值所造成的影響,該演算法通常會初始化不同的類中心進行多次運算,然後選擇方差VV最小的結果。

K-means演算法的缺陷是: 必須預先設定聚類數k,如果選擇不恰當則會導致聚類出來的結果很差。當樣本集規模大時,收斂速度會變慢;對孤立點數據敏感,少量噪聲就會對平均值造成較大影響;k的取值十分關鍵,對不同數據集,k選擇沒有參考性,需要大量實驗。

K-means演算法優點是: 容易實現,可以並行計算,並且對於很多別的問題不需要任何調整就能夠直接使用;聚類效果較優;演算法的可解釋度比較強;主要需要調參的參數僅僅是簇數k。

K-means演算法的關鍵: 在於初始中心的選擇和距離公式。

演算法複雜度:

時間複雜度:O(tKmn),其中,t爲迭代次數,K爲簇的數目,m爲記錄數,n爲維數。

空間複雜度:O((m+K)n),其中,K爲簇的數目,m爲記錄數,n爲維數。

1.1 Scipy聚類包

K-means演算法很容易實現,可以使用Scipy向量量化包scipy.clusterr.vq中有K-means的實現。

#匯入scipy中K-means的相關工具
from scipy.cluster.vq import *

#randn是NumPy中的一個函數
from numpy import *
from pylab import *

#生成簡單的二維數據:生成兩類二維正態分佈數據
class1 = 1.5 * randn(100,2)
class2 = randn(100,2) + array([5,5])
features = vstack((class1,class2))

#用 k=2 對這些數據進行聚類:
centroids,variance = kmeans(features,2)

"""
由於 SciPy 中實現的 K-means 會計算若幹次(預設爲 20 次),併爲我們選擇方差最
小的結果,所以這裏返回的方差並不是我們真正需要的。
"""

#用 SciPy 包中的向量量化函數對每個數據點進行歸類:通過得到的 code ,我們可以檢查是否有歸類錯誤
code,distance = vq(features,centroids)

#視覺化結果:畫出這些數據點及最終的聚類中心:函數 where() 給出每個類的索引
figure()
ndx = where(code==0)[0]
plot(features[ndx,0],features[ndx,1],'*')
ndx = where(code==1)[0]
plot(features[ndx,0],features[ndx,1],'r.')
plot(centroids[:,0],centroids[:,1],'go')
axis('off')
show()

處理效果:

在这里插入图片描述

分析:
原數據聚完類後的結果如圖所示,綠色圓點表示聚類中心,預測出的類分別標記爲藍色星號和紅色點。

1.2 影象聚類

檔案selectedfontimeages.zip包含66幅來自該字型數據集fontinages的影象(爲了便於說明這些聚類簇,選擇這些影象做簡單概述)。利用之前計算過的前40個主成分進行投影,用投影係數作爲每幅影象的向量描述符。用pickle模組載入模型檔案,在主成分上對影象進行投影,然後用下面 下麪的方法聚類:

# -*- coding: utf-8 -*-
from PCV.tools import imtools
import pickle
from scipy import *
from pylab import *
from PIL import Image
from scipy.cluster.vq import *
from PCV.tools import pca

# Uses sparse pca codepath.
imlist = imtools.get_imlist('D:\Python Computer Vision\_selected_thumbs\_selected_thumbs')

# 獲取影象列表和他們的尺寸
im = array(Image.open(imlist[0]))  # open one image to get the size
m, n = im.shape[:2]  # get the size of the images
imnbr = len(imlist)  # get the number of images
print
"The number of images is %d" % imnbr

# Create matrix to store all flattened images
immatrix = array([array(Image.open(imname)).flatten() for imname in imlist], 'f')

# PCA降維
V, S, immean = pca.pca(immatrix)

# 儲存均值和主成分
f = open('D:\Python Computer Vision\A_s', 'wb')
pickle.dump(immean, f)
pickle.dump(V, f)
f.close()

# 獲取 selected-fontimages 檔案下影象檔名,並儲存在列表中
imlist = imtools.get_imlist('D:\Python Computer Vision\_selected_thumbs\_selected_thumbs')
imnbr = len(imlist)

# 載入模型檔案
with open('D:\Python Computer Vision\A_s', 'rb') as f:
    immean = pickle.load(f)
    V = pickle.load(f)
# 建立矩陣,儲存所有拉成一組形式後的影象
immatrix = array([array(Image.open(im)).flatten() for im in imlist], 'f')

# 投影到前 40 個主成分上
immean = immean.flatten()
projected = array([dot(V[:40], immatrix[i] - immean) for i in range(imnbr)])

# 進行 k-means 聚類
projected = whiten(projected)
centroids, distortion = kmeans(projected, 4)
code, distance = vq(projected, centroids)

# 繪製聚類簇
for k in range(4):
    ind = where(code == k)[0]
    figure()
    gray()
    for i in range(minimum(len(ind), 40)):
        subplot(4, 10, i + 1)
        imshow(immatrix[ind[i]].reshape((25, 25)))
        axis('off')
show()


處理效果:

在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述

分析:
上面的code變數中包含的是每幅影象屬於哪個簇。這裏設定聚類數k=4,同時用Scipy的whiten()函數對數據「白化」處理,並進行歸一化,使每個特徵具有單位方差,得到4類。可以改變其中的參數,比如主成分數目和k,觀察聚類結果有何改變。將每個簇顯示在一個獨立影象視窗中,且在該圖形視窗中最多可以顯示40幅影象。用pylab的subplot()函數來設定網格數。

1.3 在主成分上視覺化影象

主成分分析(PCA)

用途: 降維中最常用的一種手段
目標: 提取最有價值的資訊(基於方差,找最大的方差方向,因爲越大的方差方向,就會使數據降維後越分的開,數據分的開,就能更好的進行分類任務。)

概念: 主成分分析(Principal Component Analysis,PCA), 是一種統計方法。通過正交變換將一組可能存在相關性的變數轉換爲一組線性不相關的變數,轉換後的這組變數叫主成分。它已經應用於人臉識別和影象壓縮領域中,並且是高維數據計算模型的常用技術。 簡單說是把高維數據將成低維數據,比如100000x100000的矩陣降成100000x100的。

爲了便於觀察上面是如何利用主成分進行聚類的,我們可以在一對主成分方向的座標上視覺化這些影象。一種方法是將影象投影到兩個主成分上,改變投影爲:

projected = array([dot(V[[0,2]],immatrix[i]-immean) for i in range(imnbr)])

相應的座標(在這裏 V[[0,2]] 分別是第一個和第三個主成分)。當然,也可以將其投影到所有成分上,之後挑選出需要的列。

用PIL中的ImageDraw模組進行視覺化。用下面 下麪的指令碼可以生成如圖所示的效果:


 # -*- coding: utf-8 -*-
from PCV.tools import imtools, pca
from PIL import Image, ImageDraw
from pylab import *
from PCV.clustering import  hcluster

imlist = imtools.get_imlist('D:\Python Computer Vision\_selected_thumbs\_selected_thumbs')
imnbr = len(imlist)

# Load images, run PCA.
immatrix = array([array(Image.open(im)).flatten() for im in imlist], 'f')
V, S, immean = pca.pca(immatrix)

# Project on 2 PCs.
projected = array([dot(V[[0, 1]], immatrix[i] - immean) for i in range(imnbr)])
#projected = array([dot(V[[1, 2]], immatrix[i] - immean) for i in range(imnbr)])

# height and width
h, w = 1200, 1200

# create a new image with a white background
img = Image.new('RGB', (w, h), (255, 255, 255))
draw = ImageDraw.Draw(img)

# draw axis
draw.line((0, h/2, w, h/2), fill=(255, 0, 0))
draw.line((w/2, 0, w/2, h), fill=(255, 0, 0))

# scale coordinates to fit
scale = abs(projected).max(0)
scaled = floor(array([(p/scale) * (w/2 - 20, h/2 - 20) + (w/2, h/2)
                      for p in projected])).astype(int)

# paste thumbnail of each image
for i in range(imnbr):
  nodeim = Image.open(imlist[i])
  nodeim.thumbnail((25, 25))
  ns = nodeim.size
  box = (scaled[i][0] - ns[0] // 2, scaled[i][1] - ns[1] // 2,
         scaled[i][0] + ns[0] // 2 + 1, scaled[i][1] + ns[1] // 2 + 1)
  img.paste(nodeim, box)

#tree = hcluster.hcluster(projected)
#hcluster.draw_dendrogram(tree,imlist,filename='fonts.png')

figure()
imshow(img)
axis('off')
img.save('pca_font.png')
show()

在这里插入图片描述
分析:
這裏用到了整數或 floor 向下取整除法運算子 //,通過移去小數點後面的部 分,可以返回各個縮圖在白色背景中對應的整數座標位置。可以很清楚地看到,二維投影後相似的字型影象距離較近。

1.4 畫素聚類

將影象區域或畫素合併成有意義的部分稱爲影象分割。單純在畫素水平上應用 K-means可以用於一些簡單影象的影象分割,但是對於複雜影象得出的結果往往是毫無意義的。要產生有意義的結果,往往需要更復雜的類模型而非平均畫素色彩或空間一致性。

下面 下麪在RGB三通道的畫素值上運用K-means進行聚類:

注意:

把書上的改爲:dx = im.shape[0]//steps dy = im.shape[1]//steps 。如果只想得到整數的結果,丟棄分數部分,可以使用運算子 //,// 得到的是整除的結果。使用list[n]存取list元素時,必須保證n是個整數!

from scipy.cluster.vq import *
from scipy import *
from pylab import *
from PIL import Image,ImageFont
# 新增中文字型支援
from matplotlib.font_manager import FontProperties

font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)


def clusterpixels(infile, k, steps):
    im = array(Image.open(infile))
    dx = im.shape[0] // steps
    dy = im.shape[1] // steps
    # compute color features for each region
    features = []
    for x in range(steps):
        for y in range(steps):
            R = mean(im[x * dx:(x + 1) * dx, y * dy:(y + 1) * dy, 0])
            G = mean(im[x * dx:(x + 1) * dx, y * dy:(y + 1) * dy, 1])
            B = mean(im[x * dx:(x + 1) * dx, y * dy:(y + 1) * dy, 2])
            features.append([R, G, B])
    features = array(features, 'f')  # make into array
    # 聚類, k是聚類數目
    centroids, variance = kmeans(features, k)
    code, distance = vq(features, centroids)
    # create image with cluster labels
    codeim = code.reshape(steps, steps)
   # codeim = imresize(codeim, im.shape[:2], 'nearest')
    return codeim


k = 3
infile_empire = 'D:\Data\JM.jpg'
im_empire = array(Image.open(infile_empire))
infile_boy_on_hill = 'D:\Data\pkq.jpg'
im_boy_on_hill = array(Image.open(infile_boy_on_hill))
steps = (50, 100)  # image is divided in steps*steps region
print (steps[0], steps[-1])

# 顯示原圖empire.jpg
figure()
subplot(231)
title(u'原圖', fontproperties=font)
axis('off')
imshow(im_empire)

# 用50*50的塊對empire.jpg的畫素進行聚類
codeim = clusterpixels(infile_empire, k, steps[0])
subplot(232)
title(u'k=3,steps=50', fontproperties=font)
# ax1.set_title('Image')
axis('off')
imshow(codeim)

# 用100*100的塊對empire.jpg的畫素進行聚類
codeim = clusterpixels(infile_empire, k, steps[-1])
ax1 = subplot(233)
title(u'k=3,steps=100', fontproperties=font)
# ax1.set_title('Image')
axis('off')
imshow(codeim)

# 顯示原圖empire.jpg
subplot(234)
title(u'原圖', fontproperties=font)
axis('off')
imshow(im_boy_on_hill)

# 用50*50的視窗對empire.jpg的畫素進行聚類
codeim = clusterpixels(infile_boy_on_hill, k, steps[0])
subplot(235)
title(u'k=3,steps=50', fontproperties=font)
# ax1.set_title('Image')
axis('off')
imshow(codeim)

# 用100*100的視窗對empire.jpg的畫素進行聚類
codeim = clusterpixels(infile_boy_on_hill, k, steps[-1])
subplot(236)
title(u'k=3,steps=100', fontproperties=font)
axis('off')
imshow(codeim)

show()


處理效果:
在这里插入图片描述
分析:
K-means的輸入是一個有steps×steps行的陣列,陣列的每一行有3列,各列分別爲區域塊R、G、B三個通道的畫素平均值。爲視覺化最後的結果,用skimage.transform中的resize()函數在原影象座標中顯示這幅影象。上圖顯示了用50×50和100×100視窗對兩幅相對比較簡單的範例影象進行畫素聚類後的結果。注意,K-means標籤的次序是任意的。視窗對影象進行了下採樣,但結果仍然是有噪聲的。如果影象某些區域有空間一致性,則較容易將它們分開,如圖中的皮卡丘。

(二)層次聚類

層次聚類,是一種很直觀的演算法。顧名思義就是要一層一層地進行聚類,可以從下而上地把小的cluster合併聚集,也可以從上而下地將大的cluster進行分割。似乎一般用得比較多的是從下而上地聚集,因此這裏我就只介紹這一種。
所謂從下而上地合併cluster,具體而言,就是每次找到距離最短的兩個cluster,然後進行合併成一個大的cluster,直到全部合併爲一個cluster。整個過程就是建立一個樹結構,類似於下圖。

在这里插入图片描述
那麼,如何判斷兩個cluster之間的距離呢?一開始每個數據點獨自作爲一個類,它們的距離就是這兩個點之間的距離。而對於包含不止一個數據點的 cluster,就可以選擇多種方法了。最常用的,就是average-linkage,即計算兩個cluster各自數據點的兩兩距離的平均值。類似的 還有single-linkage/complete-linkage,選擇兩個cluster中距離最短/最長的一對數據點的距離作爲類的距離。個人經 驗complete-linkage基本沒用,single-linkage通過關注局域連線,可以得到一些形狀奇特的cluster,但是因爲太過極 端,所以效果也不是太好。

層次聚類較大的優點,就是它一次性地得到了整個聚類的過程,只要得到了上面那樣的聚類樹,想要分多少個cluster都可以直接根據樹結構來得到結果,改變 cluster數目不需要再次計算數據點的歸屬。層次聚類的缺點是計算量比較大,因爲要每次都要計算多個cluster內所有數據點的兩兩距離。另外,由 於層次聚類使用的是貪婪演算法,得到的顯然只是局域最優,不一定就是全域性最優,這可以通過加入隨機效應解決,這就是另外的問題了。

層次法(Hierarchicalmethods) 先計算樣本之間的距離。每次將距離最近的點合併到同一個類。然後,再計算類與類之間的距離,將距離最近的類合併爲一個大類。不停的合併,直到合成了一個類。其中類與類的距離的計算方法有:最短距離法,最長距離法,中間距離法,類平均法等。比如最短距離法,將類與類的距離定義爲類與類之間樣本的最短距離。

層次聚類演算法根據層次分解的順序分爲:自下底向上和自上向下,即凝聚的層次聚類演算法和分裂的層次聚類演算法(agglomerative和divisive),也可以理解爲自下而上法(bottom-up)和自上而下法(top-down)。分裂層次聚類採用的就是"自頂而下"的思想,先將所有的樣本都看作是同一個簇,然後通過迭代將簇劃分爲更小的簇,直到每個簇中只有一個樣本爲止。凝聚層次聚類採用的是"自底向上"的思想,先將每一個樣本都看成是一個不同的簇,通過重複將最近的一對簇進行合併,直到最後所有的樣本都屬於同一個簇爲止。

在凝聚層次聚類中,判定簇間距離的兩個標準方法就是單連線(single linkage)全連線(complete linkage)。單連線,是計算每一對簇中最相似兩個樣本的距離,併合並距離最近的兩個樣本所屬簇。全連線,通過比較找到分佈於兩個簇中最不相似的樣本(距離最遠),從而來完成簇的合併。還可以通過平均連線(average linkage)。使用平均連線時,合併兩個簇所有成員間平均距離最小的兩個簇。

層次聚類有若幹優點,例如,利用樹結構可以視覺化數據間的關係,並顯示這些簇是如何關聯的。在樹中,一個好的特徵向量可以給出一個很好的分離結果。另外一個優點是,對於給定的不同的閾值,可以直接利用原來的樹,而不需要重新計算。不足之處在於,實際需要的聚類簇,需要選擇一個合適的閾值。

範例:

# -*- coding: utf-8 -*-
import os
from PCV.clustering import hcluster
from matplotlib.pyplot import *
from numpy import *
from PIL import Image

# 建立影象列表
path = 'D:\Python Computer Vision\Star-skY'
imlist = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.jpg')]
# 提取特徵向量,每個顏色通道量化成 8 個小區間
features = zeros([len(imlist), 512])
for i, f in enumerate(imlist):
    im = array(Image.open(f))
    # 多維直方圖
    h, edges = histogramdd(im.reshape(-1, 3), 8, normed=True, range=[(0, 255), (0, 255), (0, 255)])
    features[i] = h.flatten()
tree = hcluster.hcluster(features)

# 設定一些(任意的)閾值以視覺化聚類簇
clusters = tree.extract_clusters(0.23 * tree.distance)
# 繪製聚類簇中元素超過 3 個的那些影象
for c in clusters:
    elements = c.get_cluster_elements()
    nbr_elements = len(elements)
    if nbr_elements > 3:
        figure()
        for p in range(minimum(nbr_elements, 20)):
            subplot(4, 5, p + 1)
            im = array(Image.open(imlist[elements[p]]))
            imshow(im)
            axis('off')
show()

hcluster.draw_dendrogram(tree, imlist, filename='sunset.pdf')


用100 幅星空影象進行層次聚類的範例聚類簇:
在这里插入图片描述在这里插入图片描述
聚類後:

在这里插入图片描述 在这里插入图片描述說明:
可見相近的影象具有相似的顏色分佈。用100幅星空進行層次聚類,將RGB空間的512個小區間直方圖作爲每幅影象的特徵向量。樹中捱得近的影象具有相似的顏色分佈。樹狀圖的高和子部分由距離決定,這些都需要調整,以適應所選擇的影象解析度。隨着座標向下傳遞到下一級,會遞回繪製出這些節點,上述程式碼用20×20畫素繪製葉節點的縮圖,使用 get_height() 和 get_depth() 這兩個輔助函數可以獲得樹的高和寬。

(三)譜聚類

聚類演算法的一個有趣的型別叫做譜聚類。譜聚類相對K均值和層次聚類來說有不同的方法。

對於n個元素的相似度矩陣(或者叫affinity matrix, 有時也叫距離矩陣)是一個有着成對相似度分數的n*n矩陣。譜聚類的這個名稱是從相似度矩陣構造的矩陣的譜的使用得來。這個矩陣的特徵向量被用來降維,然後再聚類。

譜聚類方法的其中一個優勢是唯一的輸入就是這個矩陣,並且可以被你可以想到的任何相似度度量構造出來。像K均值和層次聚類這樣的方法計算特徵向量的平均值,這個限制了特徵(或者是描述符)對向量(爲了能夠計算平均值)。有了譜方法,不再需要任何型別的特徵向量,只有「距離」或者「相似度」。

這裏描述它是如何實現的。給定一個有着相似度分數sijsijnnn*n的相似度矩陣S,建立一個矩陣,叫做拉普拉斯矩陣
L=ID1/2SD1/2L=I−D^{−1/2}SD^{−1/2}

其中,II是單位矩陣,DD是對角矩陣,對角線上的元素是SS對應行元素之和,D=diag(di)D=diag(di),di=jsijd i =∑jsij 。拉普拉斯矩陣中的D1/2D^{−1/2} 爲:

在这里插入图片描述
爲了簡介表示,使用較小的值並且要求sij0sij​⩾0

通過計算L的特徵向量和使用對應於k個最大的特徵值的k個特徵向量建立一個特徵向量的集合(記住我們可能會沒有任何東西開始)。使用k個特徵向量作爲列建立一個矩陣,行將被作爲新的特徵向量(長度爲k)。這些新的特徵向量可以使用類似k均值被聚類產生最終的簇。本質上,演算法做的事情是把原始的數據轉換成可以被更加容易聚類的新的特徵向量(在一些情況下,使用在一開始不能用的聚類演算法)。

對理論足夠了解之後,再看看應用到實際案例中的程式碼。 使用在k均值中案例中使用的字型影象:

from PCV.tools import imtools, pca
from PIL import Image, ImageDraw
from pylab import *
from scipy.cluster.vq import *

imlist = imtools.get_imlist('D:\Python Computer Vision\_selected_thumbs\_selected_thumbs')
imnbr = len(imlist)

# Load images, run PCA.
immatrix = array([array(Image.open(im)).flatten() for im in imlist], 'f')
V, S, immean = pca.pca(immatrix)

# Project on 2 PCs.
projected = array([dot(V[[0, 1]], immatrix[i] - immean) for i in range(imnbr)])

n = len(projected)
# 計算距離矩陣
S = array([[sqrt(sum((projected[i] - projected[j]) ** 2))
            for i in range(n)] for j in range(n)], 'f')
# 建立拉普拉斯矩陣
rowsum = sum(S, axis=0)
D = diag(1 / sqrt(rowsum))
I = identity(n)
L = I - dot(D, dot(S, D))
# 計算矩陣 L 的特徵向量
U, sigma, V = linalg.svd(L)
k = 5
# 從矩陣 L 的前k個特徵向量(eigenvector)中建立特徵向量(feature vector) # 疊加特徵向量作爲陣列的列
features = array(V[:k]).T
# k-means 聚類
features = whiten(features)
centroids, distortion = kmeans(features, k)
code, distance = vq(features, centroids)
# 繪製聚類簇
for c in range(k):
    ind = where(code == c)[0]
    figure()
    gray()
    for i in range(minimum(len(ind), 39)):
        im = Image.open(imlist[ind[i]])
        subplot(4, 10, i + 1)
        imshow(array(im))
        axis('equal')
        axis('off')
show()

處理效果:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

說明:
在上面的實驗中,用兩兩間的歐式距離建立矩陣S,並對k個特徵向量用常規的K-means進行聚類。繪製出這些聚類簇。觀察到,上面分別顯示出了五類,根據不同的特徵向量,將相同的類聚集起來,形成這些聚類影象。