kmeans算法主要用來實現自動聚類,是一種非監督的機器學習算法,使用非常廣泛。在opencv3.0中提供了這樣一個函數,直接調用就能實現自動聚類,非常方便。
函數原型:
C++: double kmeans(InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() )
有7個參數,分別表示:
data: 需要自動聚類的數據,一般是一個Mat。浮點型的矩陣,每行為一個樣本。
k: 取成幾類,比較關鍵的一個參數。
bestLabels: 返回的類別標記,整型數字。
criteria: 算法結束的標准,獲取期望精度的迭代最大次數
attempts: 判斷某個樣本為某個類的最少聚類次數,比如值為3時,則某個樣本聚類3次都為同一個類,則確定下來。
flags: 確定簇心的計算方式。有三個值可選:KMEANS_RANDOM_CENTERS 表示隨機初始化簇心。KMEANS_PP_CENTERS 表示用kmeans++算法來初始化簇心(沒用過),KMEANS_USE_INITIAL_LABELS 表示第一次聚類時用用戶給定的值初始化聚類,后面幾次的聚類,則自動確定簇心。
centers: 用來初始化簇心的。與前一個flags參數的選擇有關。如果選擇KMEANS_RANDOM_CENTERS隨機初始化簇心,則這個參數可省略。
示例圖片:
學過ps描圖的都知道,頭發絲在摳圖中,是非常難的。這里我們就用kmeans自動聚類來進行自動摳圖。
思路就是將圖片的每個像素點的三通道值作為一個特征,因此會得到一個n行3列的特征矩陣data,然后用這個特征矩陣進行kmeans
代碼:
#include "stdafx.h" #include "opencv2\opencv.hpp" #include <iostream> using namespace std; using namespace cv; int main() { const int MAX_CLUSTERS = 5; Vec3b colorTab[] = { Vec3b(0, 0, 255), Vec3b(0, 255, 0), Vec3b(255, 100, 100), Vec3b(255, 0, 255), Vec3b(0, 255, 255) }; Mat data,labels; Mat pic = imread("d:/woman.png"); for (int i = 0; i < pic.rows;i++) for (int j = 0; j < pic.cols; j++) { Vec3b point = pic.at<Vec3b>(i, j); Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]); data.push_back(tmp); } //根據瀏覽圖片,確定k=3 kmeans(data, 3, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0), 3, KMEANS_RANDOM_CENTERS); int n = 0; //顯示聚類結果,不同的類別用不同的顏色顯示 for (int i = 0; i < pic.rows; i++) for (int j = 0; j < pic.cols; j++) { int clusterIdx = labels.at<int>(n); pic.at<Vec3b>(i, j) = colorTab[clusterIdx]; n++; } imshow("pic", pic); waitKey(0); return 0; }
結果:
效果不是十分理想,畢竟是全自動的。