OpenCV-Python:K值聚類


關於K聚類,我曾經在一篇博客中提到過,這里簡單的做個回顧。

KMeans的步驟以及其他的聚類算法

  K-均值是因為它可以發現k個不同的簇,且每個簇的中心采用簇中所含值的均值計算

  其他聚類算法:二分K-均值

  講解一下步驟,其實就是說明一下偽代碼

隨機選擇k個點作為起始質心
        當任意一個點的簇分配結果發生改變時
            對數據集中的每個數據點
                對每個質心
                    計算質心與數據點之間的距離
                將數據分配到距其最近的簇
            對每一個簇,計算簇中所有點的均值並將均值作為質心

 

OpenCV中使用cv2.kmeans()對數據進行分類

理解函數的參數

輸入參數:cv2.kmeans(data,K, bestLabels,criteria,attempt,flags)

  1. data:應該是np.float32類型的數據,每個特征應該放在一列。

  2. K:聚類的最終數目

  3. criteria:終止迭代的條件。當條件滿足,算法的迭代終止。它應該是一個含有3個成員的元組,它們是(type,max_iter, epsilon):

    type終止的類型:有如下三種選擇:

      - cv2.TERM_CRITERIA_EPS 只有精確度epslion滿足時停止迭代

      - cv2.TERM_CRITERIA_MAX_ITER 當迭代次數超過閾值時停止迭代

      – cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER 上面的任何一個條件滿足時停止迭代

   max_iter:最大迭代次數

   epsilon:精確度閾值

  4. attempts:使用不同的起始標記來執行算法的次數。算法會返回緊密度最好的標記。緊密度也會作為輸出被返回

  5. flags:用來設置如何選擇起始中心。通常我們有兩個選擇:cv2.KMEANS_PP_CENTERS和 cv2.KMEANS_RANDOM_CENTERS。

輸出參數:

  1. compactness:緊密度返回每個點到相應中心的距離的平方和

  2. labels:標志數組,每個成員被標記為0,1等

  3. centers:有聚類的中心組成的數組

 

僅有一個特征的數據

假設我們有一組數據,每個數據只有一個特征。例如前面的T恤問題,我們只用身高來決定T恤的大小。我們來產生一些隨機數據,並使用Matplotlib

# 隨機在25~100之間產生25個值
x = np.random.randint(25,100,25)

y = np.random.randint(175,255,25)

z = np.hstack((x,y))
z = z.reshape((50,1))
z = np.float32(z)
plt.hist(z,256,[0,256]),plt.show()

我們使用KMeans函數。先設置好終止條件。10次迭代或者精確度epsilon=1.0

# Define criteria = ( type, max_iter = 10 , epsilon = 1.0 )
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

# Set flags (Just to avoid line break in the code)
flags = cv2.KMEANS_RANDOM_CENTERS

# Apply KMeans
compactness,labels,centers = cv2.kmeans(z,2,None,criteria,10,flags)

把數據分成兩組

A = z[labels==0]
B = z[labels==1]

現在將 A 組數用紅色表示,將 B 組數據用藍色表示,重心用黃色表示。

# Now plot 'A' in red, 'B' in blue, 'centers' in yellow
plt.hist(A,256,[0,256],color = 'r')
plt.hist(B,256,[0,256],color = 'b')
plt.hist(centers,32,[0,256],color = 'y')
plt.show()

含有多個特征的數據

T恤我們只考慮了身高,現在將體重也考慮進去,也就是兩個特征。在本例中我們的測試數據是50x2的向量,其中包含50個人的身高和體重。第一列對應身高,第二列對應體重。如下圖所示:

import numpy as np
import cv2
from matplotlib import pyplot as plt

X = np.random.randint(25,50,(25,2))
Y = np.random.randint(60,85,(25,2))
Z = np.vstack((X,Y))

# convert to np.float32
Z = np.float32(Z)

# define criteria and apply kmeans()
# 迭代次數為10次,精確度為1.0
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret,label,center=cv2.kmeans(Z,2,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

# Now separate the data, Note the flatten()
A = Z[label.ravel()==0]
B = Z[label.ravel()==1]

# Plot the data
plt.scatter(A[:,0],A[:,1])
plt.scatter(B[:,0],B[:,1],c = 'r')
plt.scatter(center[:,0],center[:,1],s = 80,c = 'y', marker = 's')
plt.xlabel('Height'),plt.ylabel('Weight')
plt.show()

顏色量化

顏色量化就是減少圖片中顏色數目的一個過程,其原因是為了減少內存消耗。現在有3個特征:R,G,B,所以我們需要把圖片數據變形成Mx3(M是圖片中像素點的數目)的向量。聚類完成后,我們用聚類中心值替換與其同簇的像素值,這樣結果圖片就只含指定數目的顏色了。

分別取K=2、4、8

import numpy as np
import cv2

img = cv2.imread('home.jpg')
Z = img.reshape((-1,3))

# convert to np.float32
Z = np.float32(Z)


# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 2
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

# Now convert back into uint8, and make original image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))

cv2.imshow('K=2',res2)
cv2.imwrite('K=2.png', res2)
cv2.waitKey(0)
cv2.destroyAllWindows()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM