从前也练习使用过OpenCV的Kmean算法,但是那版本低,而且也是基于C的开发。这两天由于造论文的需要把它重新翻出来在研究一下C++,发现有了些改进
Flag that can take the following values:
centers:输出聚类中心,每行一个中心(第一列是聚类中心,但是还有其他列,这里不太明白,大家谁懂,求科普啊!~~)
compactness: 测试初始中心是否最优
上代码:
#include <string> #include <iostream> #include <math.h> #include <vector> #include <map> #include "opencv/cv.h" #include "opencv/highgui.h" #include "opencv/cxcore.h" #define ClusterNum (6) using namespace cv; using namespace std; string filename="D:/demo1.jpg"; Mat clustering(Mat src) { int row = src.rows; int col = src.cols; unsigned long int size = row*col; Mat clusters(size, 1, CV_32SC1); //clustering Mat, save class label at every location; //convert src Mat to sample srcPoint. Mat srcPoint(size, 1, CV_32FC3); Vec3f* srcPoint_p = (Vec3f*)srcPoint.data;////////////////////////////////////////////// Vec3f* src_p = (Vec3f*)src.data; unsigned long int i; for(i = 0;i < size; i++) { *srcPoint_p = *src_p; srcPoint_p++; src_p++; } Mat center(ClusterNum,1,CV_32FC3); double compactness;//compactness to measure the clustering center dist sum by different flag compactness = kmeans(srcPoint, ClusterNum, clusters, cvTermCriteria (CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0.1),ClusterNum, KMEANS_PP_CENTERS , center); cout<<"center row:"<<center.rows<<" col:"<<center.cols<<endl; for (int y = 0; y < center.rows; y++) { Vec3f* imgData = center.ptr<Vec3f>(y); for (int x = 0; x < center.cols; x++) { cout<<imgData[x].val[0]<<" "<<imgData[x].val[1]<<" "<<imgData[x].val[2]<<endl; } cout<<endl; } double minH,maxH; minMaxLoc(clusters, &minH, &maxH); //remember must use "&" cout<<"H-channel min:"<<minH<<" max:"<<maxH<<endl; int* clusters_p = (int*)clusters.data; //show label mat Mat label(src.size(), CV_32SC1); int* label_p = (int*)label.data; //assign the clusters to Mat label for(i = 0;i < size; i++) { *label_p = *clusters_p; label_p++; clusters_p++; } Mat label_show; label.convertTo(label_show,CV_8UC1); normalize(label_show,label_show,255,0,CV_MINMAX); imshow("label",label_show); map<int,int> count; //map<id,num> map<int,Vec3f> avg; //map<id,color> //compute average color value of one label for (int y = 0; y < row; y++) { const Vec3f* imgData = src.ptr<Vec3f>(y); int* idx = label.ptr<int>(y); for (int x = 0; x < col; x++) { avg[idx[x]] += imgData[x]; count[idx[x]] ++; } } //output the average value (clustering center) //计算所得的聚类中心与kmean函数中center的第一列一致, //以后可以省去后面这些繁复的计算,直接利用center, //但是仍然不理解center的除第一列以外的其他列所代表的意思 for (i = 0; i < ClusterNum; i++) { avg[i] /= count[i]; if (avg[i].val[0]>0&&avg[i].val[1]>0&&avg[i].val[2]>0) { cout<<i<<": "<<avg[i].val[0]<<" "<<avg[i].val[1]<<" "<<avg[i].val[2]<<" count:"<<count[i]<<endl; } } //show the clustering img; Mat showImg(src.size(),CV_32FC3); for (int y = 0; y < row; y++) { Vec3f* imgData = showImg.ptr<Vec3f>(y); int* idx = label.ptr<int>(y); for (int x = 0; x < col; x++) { int id = idx[x]; imgData[x].val[0] = avg[id].val[0]; imgData[x].val[1] = avg[id].val[1]; imgData[x].val[2] = avg[id].val[2]; } } normalize(showImg,showImg,1,0,CV_MINMAX); imshow("show",showImg); waitKey(); return label; } int main() { Mat img=imread(filename,1); GaussianBlur(img,img,Size(3,3),0); img.convertTo(img,CV_32FC3); Mat pixId=clustering(img); }