Opencv圖像識別從零到精通(28)----Kmeans

    K-means算法算是個著名的聚類算法了,不僅容易實現,並且效果也不錯,訓練過程不需人工干預,實乃模式識別等領域的居家必備良品啊,今天就拿這個算法練練手。屬於無監督學習中間接聚類方法中的動態聚類

流程:

1.隨機選取樣本中的K個點作爲聚類中心
2.
計算所有樣本到各個聚類中心的距離,將每個樣本規劃在最近的聚類中
3.
計算每個聚類中所有樣本的中心,並將新的中心代替原來的中心
4.
檢查新老聚類中心的距離,如果距離超過規定的閾值,則重複2-4,直到小於閾值

       聚類屬於無監督學習,以往的迴歸、樸素貝葉斯、SVM等都是有類別標籤y的,也就是說樣例中已經給出了樣例的分類。而聚類的樣本中卻沒有給定y,只有特徵x,比如假設宇宙中的星星可以表示成三維空間中的點集clip_image002[10]。聚類的目的是找到每個樣本x潛在的類別y,並將同類別y的樣本x放在一起。比如上面的星星,聚類後結果是一個個星團,星團裏面的點相互距離比較近,星團間的星星距離就比較遠了。

     在聚類問題中,給我們的訓練樣本是clip_image004,每個clip_image006,沒有了y。

     K-means算法是將樣本聚類成k個簇(cluster),具體算法描述如下:

1、 隨機選取k個聚類質心點(cluster centroids)爲clip_image008[6]

2、 重複下面過程直到收斂 {

               對於每一個樣例i,計算其應該屬於的類

               clip_image009

               對於每一個類j,重新計算該類的質心

               clip_image010[6]

    K是我們事先給定的聚類數,clip_image012[6]代表樣例i與k個類中距離最近的那個類,clip_image012[7]的值是1到k中的一個。質心clip_image014[6]代表我們對屬於同一個類的樣本中心點的猜測,拿星團模型來解釋就是要將所有的星星聚成k個星團,首先隨機選取k個宇宙中的點(或者k個星星)作爲k個星團的質心,然後第一步對於每一個星星計算其到k個質心中每一個的距離,然後選取距離最近的那個星團作爲clip_image012[8],這樣經過第一步每一個星星都有了所屬的星團;第二步對於每一個星團,重新計算它的質心clip_image014[7](對裏面所有的星星座標求平均)。重複迭代第一步和第二步直到質心不變或者變化很小。

     下圖展示了對n個樣本點進行K-means聚類的效果,這裏k取2。

     clip_image015

參考;http://blog.csdn.net/holybin/article/details/22969747

Kmeans有以下幾個優點:

1、是解決聚類問題的一種經典算法,算法簡單、快速。

2、對處理大數據集,該算法是相對可伸縮的和高效率的,因爲它的複雜度是線性的,大約是O(nkt),其中n是所有樣本的數目,k是簇的數目,t是迭代的次數。通常k<<n。

3、該算法是收斂的(不會無限迭代下去)。

4、算法嘗試找出使平方誤差函數值最小的k個劃分。當簇是密集的、球狀或團狀的,而簇與簇之間區別明顯時,它的聚類效果很好。

Kmeans也存在如下缺點:

1、只有在簇的平均值被定義的情況下才能使用,不適用於某些應用,如涉及有分類屬性的數據不適用。它的前提假設是樣本數據的協方差矩陣已經歸一化。

2、雖然理論證明它是一定可以收斂的,但是不能保證是全局收斂,可能是局部收斂,這樣的話找到的聚類中心不一定是最佳方案。

3、要求用戶必須事先給出要生成的簇的數目K。對於同一個數據樣本集合,選擇不同的K值,得到的結果是不一樣的,甚至是不合理的。

4、對中心初值敏感,對於不同的初始值,可能會導致不同的聚類結果。

5、對於"噪聲"和孤立點數據敏感,少量的該類數據能夠對平均值產生極大影響。

6、不適合於發現非凸面形狀的簇,或者大小差別很大的簇。

CV_EXPORTS_W double kmeans( InputArray data, int K, InputOutputArray bestLabels,
                            TermCriteria criteria, int attempts,
                            int flags, OutputArray centers = noArray() );
注意,在opencv中,kmeans()函數是在core.h頭文件中的,所以首先要包含這個頭文件。下面分析其參數:
1 InputArray data:輸入的待聚類向量,其中每一行是一個樣本,有多少列,就有多少個樣本。
2 int K: 要聚類的個數。
3 InputOutputArray bestLabels:行數與data是一樣的,每行有一個數字,代表分類的編號。比如聚類的數目是8類,那麼每行的數字在0-3。
4 TerCriteria criteria:這個變量用於控制結束條件。其中TerCriteria是一個模板類,在opencv中的定義如下:
TermCriteria::TermCriteria(int _type, int _maxCount, double _epsilon)
    : type(_type), maxCount(_maxCount), epsilon(_epsilon) {}
其中,type的類型有三種:
TermCriteria::COUNT: 代表以運行的步數爲結束條件。
TermCriteria::EPS: 代表迭代到閾值時結束。
TermCriteria::COUNT + TermCriteria::EPS:當步數或閾值中有一個達到條件時終止。
_maxCount是運行的步數,_epsilon是閾值。
5 int attempts:這個變量控制kmean算法進行的次數,選擇最優的結果做爲最後結果。
6 int flags:這個變量可以取以下三個類型。
KMEANS_RANDOM_CENTERS:隨機選擇初始中心。
KMEANS_PP_CENTERS:以一種算法,確定初始中心。
KMEANS_USE_INITIAL_LABELS:用戶自定義中心。
7 centers:這個變量代表具體的聚類中心。
下面來看一個例子

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include <iostream>
using namespace cv;
using namespace std;


int main( int /*argc*/, char** /*argv*/ )
{
    const int MAX_CLUSTERS = 5;
    Scalar colorTab[] =     
    {
        Scalar(0, 0, 255),
        Scalar(0,255,0),
        Scalar(255,100,100),
        Scalar(255,0,255),
        Scalar(0,255,255)
    };

    Mat img(500, 500, CV_8UC3);
    RNG rng(12345); 

    for(;;)
    {
        int k, clusterCount = rng.uniform(2, MAX_CLUSTERS+1);
        int i, sampleCount = rng.uniform(1, 1001);
        Mat points(sampleCount, 1, CV_32FC2), labels;   

        clusterCount = MIN(clusterCount, sampleCount);
        Mat centers(clusterCount, 1, points.type());    

        /* generate random sample from multigaussian distribution */
        for( k = 0; k < clusterCount; k++ ) 
        {
            Point center;
            center.x = rng.uniform(0, img.cols);
            center.y = rng.uniform(0, img.rows);
            Mat pointChunk = points.rowRange(k*sampleCount/clusterCount,
                                             k == clusterCount - 1 ? sampleCount :
                                             (k+1)*sampleCount/clusterCount);   
  
            rng.fill(pointChunk, CV_RAND_NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
		
        }

        randShuffle(points, 1, &rng);  
        kmeans(points, clusterCount, labels,
               TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
               3, KMEANS_PP_CENTERS, centers);  

        img = Scalar::all(0);

        for( i = 0; i < sampleCount; i++ )
        {
            int clusterIdx = labels.at<int>(i);
            Point ipt = points.at<Point2f>(i);
            circle( img, ipt, 2, colorTab[clusterIdx], CV_FILLED, CV_AA );
        }

        imshow("clusters", img);

        char key = (char)waitKey();    
        if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
            break;
    }

    return 0;
}



matlab

K-means聚類算法採用的是將N*P的矩陣X劃分爲K個類,使得類內對象之間的距離最大,而類之間的距離最小。

使用方法:

Idx=Kmeans(X,K)

[Idx,C]=Kmeans(X,K)

[Idx,C,sumD]=Kmeans(X,K)

[Idx,C,sumD,D]=Kmeans(X,K)

[…]=Kmeans(…,’Param1’,Val1,’Param2’,Val2,…)

各輸入輸出參數介紹:

X N*P的數據矩陣

K 表示將X劃分爲幾類,爲整數

Idx N*1的向量,存儲的是每個點的聚類標號

C K*P的矩陣,存儲的是K個聚類質心位置

sumD 1*K的和向量,存儲的是類間所有點與該類質心點距離之和

D N*K的矩陣,存儲的是每個點與所有質心的距離

[…]=Kmeans(…,'Param1',Val1,'Param2',Val2,…)

這其中的參數Param1、Param2等,主要可以設置爲如下:

1. ‘Distance’(距離測度)

‘sqEuclidean’ 歐式距離(默認時,採用此距離方式)

‘cityblock’ 絕度誤差和,又稱:L1

‘cosine’ 針對向量

‘correlation’  針對有時序關係的值

‘Hamming’ 只針對二進制數據

2. ‘Start’(初始質心位置選擇方法)

‘sample’ 從X中隨機選取K個質心點

‘uniform’ 根據X的分佈範圍均勻的隨機生成K個質心

‘cluster’ 初始聚類階段隨機選擇10%的X的子樣本(此方法初始使用’sample’方法)

matrix 提供一K*P的矩陣,作爲初始質心位置集合

3. ‘Replicates’(聚類重複次數)  整數

<span style="font-size:18px;">X = [randn(100,2)+ones(100,2);...
     randn(100,2)-ones(100,2)];
opts = statset('Display','final');
[idx,ctrs] = kmeans(X,2,...
                    'Distance','city',...
                    'Replicates',5,...
                    'Options',opts);

plot(X(idx==1,1),X(idx==1,2),'r.','MarkerSize',12)
hold on
plot(X(idx==2,1),X(idx==2,2),'b.','MarkerSize',12)
plot(ctrs(:,1),ctrs(:,2),'kx',...
     'MarkerSize',12,'LineWidth',2)
plot(ctrs(:,1),ctrs(:,2),'ko',...
     'MarkerSize',12,'LineWidth',2)
legend('Cluster 1','Cluster 2','Centroids',...
       'Location','NW')
</span>


圖像識別算法交流 QQ羣:145076161,歡迎圖像識別與圖像算法,共同學習與交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章