OPENCV KMeans算法

? ? KMeans算法作為數(shù)據(jù)聚類的重要算法之一,通過(guò)被廣泛的應(yīng)用。本文將調(diào)用OPENCV的工具包來(lái)對(duì)一些隨機(jī)數(shù)進(jìn)行聚類,并將結(jié)果通過(guò)OPENCV進(jìn)行可視化。 本實(shí)驗(yàn)主要是生成一些二維樣本數(shù)據(jù),每個(gè)樣本數(shù)據(jù)都服從高斯分布,我們將通過(guò)KMeans算法來(lái)對(duì)結(jié)果進(jìn)行分類。

? ??KMeans算法的基本流程

? ? 1.確定參數(shù)K,也就是需要將數(shù)據(jù)分成幾個(gè)類別

? ? 2隨機(jī).初始化K個(gè)中心坐標(biāo)點(diǎn)

? ? 3.根據(jù)每個(gè)數(shù)據(jù)樣本與中心點(diǎn)的距離來(lái)判斷,選擇距離最近的中心類別,分配聚類的編號(hào)

? ?4.對(duì)于相同類別的樣本數(shù)據(jù)重新計(jì)算每個(gè)樣本到中心點(diǎn)的距離,取均值來(lái)調(diào)整中心坐標(biāo)點(diǎn)的位置

????5.判斷算法是否到達(dá)了最大迭代次數(shù)或者精度,如果到達(dá)說(shuō)明數(shù)據(jù)聚類完成,沒有到達(dá)條件時(shí)將會(huì)繼續(xù)計(jì)算不停地調(diào)整中心坐標(biāo)點(diǎn)


??KMeans算法的基本流程

了解完基本思想后我們將通過(guò)代碼來(lái)演示KMeans算法對(duì)數(shù)據(jù)聚類的效果,同時(shí)對(duì)相關(guān)API函數(shù)進(jìn)行介紹

第一步我們先使用了OPENCV的Mat數(shù)據(jù)結(jié)構(gòu)來(lái)創(chuàng)建了一個(gè)畫板,我們由下圖的代碼可以看到,創(chuàng)建了一個(gè)長(zhǎng)500,寬500的畫板,同時(shí)對(duì)圖像的文件格式做了設(shè)定。在這里簡(jiǎn)單的提一下CvMat矩陣對(duì)應(yīng)的參數(shù)類型。一般的圖像文件格式使用的是 Unsigned 8bits吧,CvMat矩陣對(duì)應(yīng)的參數(shù)類型就是CV_8UC1,CV_8UC2,CV_8UC3。(最后的1、2、3表示通道數(shù),譬如RGB3通道就用CV_8UC3)。在這里我們使用了CV_8UC3創(chuàng)建了一張3通道的圖像,下面的步驟中我們需要對(duì)不同的數(shù)據(jù)類別指定不同的顏色,因此采用了3通道的圖像文件格式,當(dāng)然使用灰度圖也是沒有問(wèn)題的。


創(chuàng)建一個(gè)畫板用來(lái)顯示最后的結(jié)果

第二步生成隨機(jī)樣本,程序中采用RNG隨機(jī)模塊來(lái)進(jìn)行數(shù)據(jù)的隨機(jī)初始化,在此來(lái)介紹幾個(gè)程序中用到的初始化模塊。

(1)void?RNG::fill(InputOutputArray?mat, int?distType, InputArray?a, InputArray?b, bool?saturateRange=false?)

  這個(gè)函數(shù)是對(duì)矩陣mat填充隨機(jī)數(shù),隨機(jī)數(shù)的產(chǎn)生方式有參數(shù)2來(lái)決定,如果為參數(shù)2的類型為RNG::UNIFORM,則表示產(chǎn)生均一分布的隨機(jī)數(shù),如果為RNG::NORMAL則表示產(chǎn)生高斯分布的隨機(jī)數(shù)。對(duì)應(yīng)的參數(shù)3和參數(shù)4為上面兩種隨機(jī)數(shù)產(chǎn)生模型的參數(shù)。比如說(shuō)如果隨機(jī)數(shù)產(chǎn)生模型為均勻分布,則參數(shù)a表示均勻分布的下限,參數(shù)b表示上限。如果隨機(jī)數(shù)產(chǎn)生模型為高斯模型,則參數(shù)a表示均值,參數(shù)b表示方程。參數(shù)5只有當(dāng)隨機(jī)數(shù)產(chǎn)生方式為均勻分布時(shí)才有效,表示的是是否產(chǎn)生的數(shù)據(jù)要布滿整個(gè)范圍(沒用過(guò),所以也沒仔細(xì)去研究)。另外,需要注意的是用來(lái)保存隨機(jī)數(shù)的矩陣mat可以是多維的,也可以是多通道的,目前最多只能支持4個(gè)通道。

(2)void?randShuffle(InputOutputArray?dst, double?iterFactor=1.,?RNG*?rng=0?)

  該函數(shù)表示隨機(jī)打亂1D數(shù)組dst里面的數(shù)據(jù),隨機(jī)打亂的方式由隨機(jī)數(shù)發(fā)生器rng決定。iterFactor為隨機(jī)打亂數(shù)據(jù)對(duì)數(shù)的因子,總共打亂的數(shù)據(jù)對(duì)數(shù)為:dst.rows*dst.cols*iterFactor,因此如果為0,表示沒有打亂數(shù)據(jù)。


初始化隨機(jī)樣本核心代碼

int numCluster = 5;

int sampleCount = rng.uniform(5, 500);

Mat points(sampleCount, 1, CV_32FC2);

Mat labels;

Mat centers;

for (int k = 0;k < numCluster;k++)

{

Point center;

center.x = rng.uniform(0, img.cols);

center.y = rng.uniform(0,img.rows);

Mat pointDome = points.rowRange(k*sampleCount / numCluster, (k + 1)*sampleCount / numCluster);

rng.fill(points,rng.uniform,0,500);

}

randShuffle(points,1,&rng);


第三步我們將對(duì)構(gòu)建出來(lái)的隨機(jī)樣本進(jìn)行聚類,采用KMeans算法,對(duì)此我們對(duì)KMeans算法用到的API函數(shù)進(jìn)行介紹。

Class TermCriteria

  類TermCriteria 一般表示迭代終止的條件,如果為CV_TERMCRIT_ITER,則用最大迭代次數(shù)作為終止條件,如果為CV_TERMCRIT_EPS?則用精度作為迭代條件,如果為CV_TERMCRIT_ITER+CV_TERMCRIT_EPS則用最大迭代次數(shù)或者精度作為迭代條件,看哪個(gè)條件先滿足。

double?kmeans(InputArray?data, int?K, InputOutputArray?bestLabels, TermCriteria?criteria, int?attempts, int?flags, OutputArray?centers=noArray()?)

  該函數(shù)為kmeans聚類算法實(shí)現(xiàn)函數(shù)。參數(shù)data表示需要被聚類的原始數(shù)據(jù)集合,一行表示一個(gè)數(shù)據(jù)樣本,每一個(gè)樣本的每一列都是一個(gè)屬性;參數(shù)k表示需要被聚類的個(gè)數(shù);參數(shù)bestLabels表示每一個(gè)樣本的類的標(biāo)簽,是一個(gè)整數(shù),從0開始的索引整數(shù);參數(shù)criteria表示的是算法迭代終止條件;參數(shù)attempts表示運(yùn)行kmeans的次數(shù),取結(jié)果最好的那次聚類為最終的聚類,要配合下一個(gè)參數(shù)flages來(lái)使用;參數(shù)flags表示的是聚類初始化的條件。其取值有3種情況,如果為KMEANS_RANDOM_CENTERS,則表示為隨機(jī)選取初始化中心點(diǎn),如果為KMEANS_PP_CENTERS則表示使用某一種算法來(lái)確定初始聚類的點(diǎn);如果為KMEANS_USE_INITIAL_LABELS,則表示使用用戶自定義的初始點(diǎn),但是如果此時(shí)的attempts大于1,則后面的聚類初始點(diǎn)依舊使用隨機(jī)的方式;參數(shù)centers表示的是聚類后的中心點(diǎn)存放矩陣。該函數(shù)返回的是聚類結(jié)果的緊湊性

第四步將對(duì)分類出來(lái)的進(jìn)行顯示

// 用不同顏色顯示分類

img = Scalar::all(255);

for (int i = 0; i < sampleCount; i++) {

int index = labels.at<int>(i);

Point p = points.at<Point2f>(i);

circle(img, p, 2, colorTab[index], -1, 8);

}

// 每個(gè)聚類的中心來(lái)繪制圓

for (int i = 0; i < centers.rows;? i++) {

int x = centers.at<float>(i, 0);

int y = centers.at<float>(i, 1);

printf("c.x= %d, c.y=%d", x, y);

circle(img, Point(x, y), 40, colorTab[i], 1, LINE_AA);

}

imshow("KMeans-Data-Demo", img);


最終代碼:

#include <opencv2/opencv.hpp>

#include <iostream>

using namespace cv;

using namespace std;

int main(int argc, char** argv) {

Mat img(500, 500, CV_8UC3);

RNG rng(12345);

Scalar colorTab[] = {

Scalar(0, 0, 255),

Scalar(0, 255, 0),

Scalar(255, 0, 0),

Scalar(0, 255, 255),

Scalar(255, 0, 255)

};

int numCluster = rng.uniform(2, 5);

printf("number of clusters : %d\n", numCluster);

int sampleCount = rng.uniform(5, 1000);

Mat points(sampleCount, 1, CV_32FC2);

Mat labels;

Mat centers;

// 生成隨機(jī)數(shù)

for (int k = 0; k < numCluster; k++) {

Point center;

center.x = rng.uniform(0, img.cols);

center.y = rng.uniform(0, img.rows);

Mat pointChunk = points.rowRange(k*sampleCount / numCluster,

k == numCluster - 1 ? sampleCount : (k + 1)*sampleCount / numCluster);

rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));

}

randShuffle(points, 1, &rng);

// 使用KMeans

kmeans(points, numCluster, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1), 3, KMEANS_PP_CENTERS, centers);

// 用不同顏色顯示分類

img = Scalar::all(255);

for (int i = 0; i < sampleCount; i++) {

int index = labels.at<int>(i);

Point p = points.at<Point2f>(i);

circle(img, p, 2, colorTab[index], -1, 8);

}

// 每個(gè)聚類的中心來(lái)繪制圓

for (int i = 0; i < centers.rows;? i++) {

int x = centers.at<float>(i, 0);

int y = centers.at<float>(i, 1);

printf("c.x= %d, c.y=%d", x, y);

circle(img, Point(x, y), 40, colorTab[i], 1, LINE_AA);

}

imshow("KMeans-Data-Demo", img);

waitKey(0);

return 0;

}


運(yùn)行效果:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容