OpenCV學習(22) opencv中使用kmeans算法


kmeans算法的原理參考:http://www.cnblogs.com/mikewolf2002/p/3368118.html

下面學習一下opencv中kmeans函數的使用。

     首先我們通過OpenCV中的隨機數產生器RNG,生成一些均勻分布的隨機點,這些點的位置對應一副圖像中的像素位置,然后使用kmeans算法對這些隨機點進行分類,並計算出分類簇的中心點。

     隨機產生的簇的數量是2到5之間的值,采樣點的數量范圍是1-1000,一維矩陣centers存放kmeans算法結束后,各個簇的中心位置。

     

//簇的數量
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());

printf("clusterCount=%d, sampleCount=%d\n", clusterCount, sampleCount);
//產生多高斯部分的隨機采樣點
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);
    printf("rows start=%d rows end=%d\n", k*sampleCount/clusterCount, k == clusterCount - 1 ? sampleCount :
        (k+1)*sampleCount/clusterCount);

注意rng.fill函數,會以center點為中心,產生高斯分布的隨機點(位置點),並把位置點保存在矩陣pointChunk中。
    //第三個參數中心,第四個參數偏移
    rng.fill(pointChunk, CV_RAND_NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
    }

//打亂points中值,第二個參數表示隨機交換元素的數量的縮放因子,總的交換次數dst.rows*dst.cols*iterFactor,第三個參數是個隨機發生器,決定選那兩個元素交換

randShuffle(points, 1, &rng);

      kmeans函數中points為輸入矩陣,其中存儲的是采樣點,labels也是一個一維矩陣,它的size和points一樣,里面存儲的是每個采樣點執行kmeans算法后屬於屬於那一個簇,值為0到clusterCount-1,centers中存放的是kmeans算法結束后每個簇的中心位置。

      flags(第7個參數)為KMEANS_PP_CENTERS 表示使用 kmeans++ center initialization by Arthur and Vassilvitskii [Arthur2007]算法決定簇的初始中心,否則就是采用隨機值的方法決定初始中心

     如果flags是CV_KMEANS_USE_INITIAL_LABELS,則需要初始化labels,就是初始指定點的分類。

     最后我們在圖像中畫出每個位置點對應的像素,中心位置用藍色的圓圈表示。

//labels中放的是執行kmeans算法后sample中簇的索引
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 );
    }

cout<<"Center: \n"<<centers<<endl;

//用藍色畫出每個聚類的中心
//有bug,不讓我直接用centers.at<Point2f>(i);,會異常

for( i = 0; i < clusterCount; i++ )
    {
    Point ipt = Point(centers.at<float>(i*2), centers.at<float>(i*2+1));
    circle( img, ipt, 5, Scalar(255,0,0),CV_FILLED, CV_AA );

    }
imshow("clusters", img);

下面圖像是5個簇的kmeans聚類結果。

image

源代碼參考工程:FirstOpenCV15


免責聲明!

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



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