OpenCV學習筆記(1):Kmeans聚類
前言
一提到聚類演算法,必然首先會想到的是kmeans聚類,因為它的名氣實在太大了。最近,剛好要使用OpenCV中Kmeans函式。這節內容主要是講講OpenCV中kmeans函式的使用方法。
開發環境:OpenCV2.4.8+VS2013
實驗基礎
在使用kmeans之前,必須先了解kmeans演算法的2個缺點:第一是必須人為指定所聚的類的個數k;第二是如果使用歐式距離來衡量相似度的話,可能會得到錯誤的結果,因為沒有考慮到屬性的重要性和相關性。為了減少這種錯誤,在使用kmeans距離時,一定要使樣本的每一維資料歸一化,不然的話由於樣本的屬性範圍不同會導致錯誤的結果。
實驗一是對隨機產生的sampleCount個二維樣本(共分為clusterCount個類別),每個類別的樣本資料都服從高斯分佈,該高斯分佈的均值是隨機的,方差是固定的。然後對這sampleCount個樣本資料使用kmeans演算法聚類,最後將不同的類用不同的顏色顯示出來。
下面是程式中使用到的幾個OpenCV函式:
void RNG::fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false )
這個函式是對矩陣mat填充隨機數,隨機數的產生方式有引數2來決定,如果為引數2的型別為RNG::UNIFORM,則表示產生均一分佈的隨機數,如果為RNG::NORMAL則表示產生高斯分佈的隨機數。對應的引數3和引數4為上面兩種隨機數產生模型的引數。比如說如果隨機數產生模型為均勻分佈,則引數a表示均勻分佈的下限,引數b表示上限。如果隨機數產生模型為高斯模型,則引數a表示均值,引數b表示方程。引數5只有當隨機數產生方式為均勻分佈時才有效,表示的是是否產生的資料要佈滿整個範圍(沒用過,所以也沒仔細去研究)。另外,需要注意的是用來儲存隨機數的矩陣mat可以是多維的,也可以是多通道的,目前最多隻能支援4個通道。
void randShuffle(InputOutputArray dst, double iterFactor=1., RNG* rng=0 )
該函式表示隨機打亂1D陣列dst裡面的資料,隨機打亂的方式由隨機數發生器rng決定。iterFactor為隨機打亂資料對數的因子,總共打亂的資料對數為:dst.rows*dst.cols*iterFactor,因此如果為0,表示沒有打亂資料。
Class TermCriteria
類TermCriteria 一般表示迭代終止的條件,如果為CV_TERMCRIT_ITER,則用最大迭代次數作為終止條件,如果為CV_TERMCRIT_EPS 則用精度作為迭代條件,如果為CV_TERMCRIT_ITER+CV_TERMCRIT_EPS則用最大迭代次數或者精度作為迭代條件,看哪個條件先滿足。
double kmeans(InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() )
該函式為kmeans聚類演算法實現函式。引數data表示需要被聚類的原始資料集合,一行表示一個數據樣本,每一個樣本的每一列都是一個屬性;引數k表示需要被聚類的個數;引數bestLabels表示每一個樣本的類的標籤,是一個整數,從0開始的索引整數;引數criteria表示的是演算法迭代終止條件;引數attempts表示執行kmeans的次數,取結果最好的那次聚類為最終的聚類,要配合下一個引數flages來使用;引數flags表示的是聚類初始化的條件。其取值有3種情況,如果為KMEANS_RANDOM_CENTERS,則表示為隨機選取初始化中心點,如果為KMEANS_PP_CENTERS則表示使用某一種演算法來確定初始聚類的點;如果為KMEANS_USE_INITIAL_LABELS,則表示使用使用者自定義的初始點,但是如果此時的attempts大於1,則後面的聚類初始點依舊使用隨機的方式;引數centers表示的是聚類後的中心點存放矩陣。該函式返回的是聚類結果的緊湊性,其計算公式為:
實驗二是對輸入的一張圖片進行聚類。
實驗結果
實驗一:隨機產生的符合高斯分佈的資料被聚類的結果
實驗二:對圖片的聚類
源影象:
聚類後圖像:程式碼詳見: 參考: