Kmeans又是一个以点到点距离为判断依据的算法,物理上的质心很好的形容了这个算法的目的。
说的没有做的理解深,还是实践一下。
#include "pch.h"
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::ml;
int main(int /*argc*/, char** /*argv*/)
{
const int CLUSTERS_COUNT = 3; //3个聚类中心
const int smpCount = 300; //300个样本点
const int height = 500;
Mat img(height, height, CV_8UC3);
RNG rng(10000);
int k, i;
Mat points(smpCount, 1, CV_32FC2), labels;
vector<Point2f> centers;
Scalar colorTab[] =
{
Scalar(0, 0, 255),//红
Scalar(0,255,0), //绿
Scalar(255,0,0), //蓝
};
for (k = 0;k < CLUSTERS_COUNT;k++) { //生成随机样本点
Point center;
center.x = rng.uniform(0, height);
center.y = rng.uniform(0, height);
Mat pointChunk = points.rowRange(k*smpCount / CLUSTERS_COUNT, (k+1)*smpCount / CLUSTERS_COUNT);
rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y), Scalar(height*0.05, height*0.05));
}
double compactness = kmeans(points, CLUSTERS_COUNT, labels, //执行kmeans算法
TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0),
3, KMEANS_PP_CENTERS, centers);
img = Scalar::all(0);
for (i = 0;i < smpCount;i++) {
int clusterIdx = labels.at<int>(i);
Point ipt = points.at<Point2f>(i);
circle(img, ipt, 2, colorTab[clusterIdx], FILLED, LINE_AA); //将样本点绘制到img上
}
for (i = 0;i < (int)centers.size();i++) {
Point2f c = centers[i];
circle(img, c, 40, colorTab[i], i, LINE_AA); //画一个聚类中心为中心,半径为40的圆
}
imshow("kmeans", img);
waitKey(0);
return 0;
}
参考文章