OpenCV-Python教程:55.OpenCV里的K-Means聚類

理解參數(shù)

輸入參數(shù)

1.samples:應該是np.float32數(shù)據(jù)類型,且每個特征應該放在一個單獨的列。

2.nclusters(K): 需要的聚類的數(shù)量

3.criteria: 這是迭代終止準則。當滿足這個準則時,算法迭代停止。實際上,它應該是一個3個參數(shù)的元組。他們是:(type, max_iter, epsilon):

? ? ·3.a - 終止準則的類型: 有3個標志如下:

? ? ? ? cv2.TERM_CRITERIA_EPS - 如果滿足了指定準確度,epsilon就停止算法迭代。
? ? ? ? cv2.TERM_CRITERIA_MAX_ITER - 在指定次數(shù)的迭代后就停止算法。

? ? ? ? cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER - 當任何上面的條件滿足就停止迭代

? ? ·3.b - max_iter - 指定最大的迭代次數(shù),整數(shù)

? ? ·3.c - epsilon - 需要的準確度

4.attempts: 標志,指定算法使用不同初始標簽執(zhí)行的次數(shù)。算法返回能得到最好密度的標簽。密度作為輸出被返回。

5.flags:這個標志是用來指定如何得到初始中心的。一般兩個標志會用到:cv2.KMEANS_PP_CENTERS和cv2.KMEANS_RANDOM_CENTERS.

輸出參數(shù)

1.compactness: 這是從每個點到他們對應的中心的距離的平方和。

2.labels: 這是標簽數(shù)組(和'code'一樣),每個元素被標記為'0', '1'...

3.centers: 這是聚類中心的數(shù)組

現(xiàn)在我們用三個例子看看怎么應用K-Means算法

1.只有一個特征的數(shù)據(jù)

你有一個只有一個特征或者一個維度的數(shù)據(jù)集,比如,我們你只能用人的身高來決定T恤的尺寸。

所以我們創(chuàng)建數(shù)據(jù)并用Matplotlib繪制:

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

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()

所以我們的'z'是一個大小為50的數(shù)組,值的范圍從0到255。我們把'z'變形成列向量。當超過一個特征被顯示時很有用。那么我們把數(shù)據(jù)變成np.float32類型。

現(xiàn)在我們使用KMeans函數(shù)。在此之前我們需要制定criteria。我們的criteria是當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)

這給我們密度,標簽和中心,在這個例子里,我們得到中心60和207. 標簽會有和測試數(shù)據(jù)相同的大小,每個數(shù)據(jù)會根據(jù)他們的質心被標記為'0', '1', '2'。現(xiàn)在我們根據(jù)標簽把數(shù)據(jù)分為不同的聚類。

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

現(xiàn)在我們用紅色畫出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()

下面是我們的輸出:

2. 多個特征的數(shù)據(jù)

在前面的例子里,我們對于T恤問題只取身高。這里,我們取身高和體重兩個特征。

記住,在前面的例子里,我們把我們的數(shù)據(jù)弄成單列向量。每個特征作為一列。每行對應一個輸入測試樣本。

例如,在這個例子里,我們設置一個大小為50x2的測試數(shù)據(jù),是50個人的身高和體重。第一列對應著所有50個人的身高,第二列對應他們的體重。第一行包含兩個元素,第一個元素是第一個人的身高,第二個元素是他的體重,類似的剩下的行對應剩下的人的身高和體重。看下圖:

現(xiàn)在我們直接看代碼:

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()
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.顏色量化

顏色量化是減少一個圖像里的顏色數(shù)量的過程。做這個的一個原因是減少內存使用。有時候,一些設備會受限只能生成有限的顏色數(shù)量。在那些情況下也會執(zhí)行顏色量化。這里我們使用k-means聚類來做顏色量化。

沒有新的內容要解釋。這里有3個特征,R,G,B。所以我們需要把圖像改造成Mx3大小的數(shù)組(M是圖像像素的數(shù)量)。聚類之后,我們應用中心值到所有的像素上,這樣結果圖像會有指定數(shù)量的顏色。再次我們需要把它變形回去變成原始圖片的形狀。下面是代碼:

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 = 8
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('res2',res2)
cv2.waitKey(0)
cv2.destroyAllWindows()

看下面K=8時的結果:

END

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容