Kmeans算法是非常经典的聚类算法,在数据挖掘中kmeans经常用来做数据预处理,在图像处理中也可以用作图像的分割。
原理:首先选择要聚成几个类,然后初始化中心点。比如说要聚成3类,就随机生成3个中心点,然后每个数据点选择离它最近的中心点作为一类,对组成的类取平均值就会得到三个新的中心点,再对其进行聚类,不断迭代,当迭代的次数超过某一阈值或者前后两次中心点位置不变了或变化很小就终止聚类。
kmeans( InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers = noArray() );
- data表示用于聚类的数据点,是N维的数组类型(Mat型),必须浮点型;
- K表示需要聚类的类别数;
- bestLabels聚类后的标签数组,Mat型;
- criteria迭代收敛准则(MAX_ITER最大迭代次数,EPS最高精度);
- attemps表示尝试的次数,防止陷入局部最优;
- flags 表示聚类中心的选取方式(KMEANS_RANDOM_CENTERS 随机选取,KMEANS_PP_CENTERS使用Arthur提供的算法,KMEANS_USE_INITIAL_LABELS使用初始标签);
- centers 表示聚类后的类别中心;
#include<opencv2\opencv.hpp>
using namespace cv;
int main(int arc, char** argv) {
Mat src = imread("1.jpg");
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
int width = src.cols;
int height = src.rows;
int pointCount = width * height;
int dims = src.channels();
//将图像像素转换为数据点
Mat points(pointCount, dims, CV_32F);
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
index = i * width + j;
points.at<float>(index, 0) = src.at<Vec3b>(i, j)[0];
points.at<float>(index, 1) = src.at<Vec3b>(i, j)[1];
points.at<float>(index, 2) = src.at<Vec3b>(i, j)[2];
}
}
//进行KMeans聚类
Mat bestLabels;
Mat centers(3, 3, CV_32F);
kmeans(points, 3, bestLabels, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 0.1), 3, KMEANS_PP_CENTERS, centers);
//将数据点转换为图像,并显示图像
Scalar color[] = { Scalar(0,0,255),Scalar(0,255,0),Scalar(255,0,0) };
Mat result = Mat::zeros(src.size(), src.type());
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
index = i * width + j;
int lable = bestLabels.at<int>(index, 0);
result.at<Vec3b>(i, j)[0] = color[lable][0];//color[lable][0]指的是颜色三通道的第一个值B
result.at<Vec3b>(i, j)[1] = color[lable][1];
result.at<Vec3b>(i, j)[2] = color[lable][2];
}
}
//打印聚类中心点的坐标,这里的坐标指的是三通道的像素值
printf("the center of class 1:%3.2f , %3.2f ,%3.2f\n", centers.at<float>(0, 0),centers.at<float>(0, 1), centers.at<float>(0, 2));
printf("the center of class 2:%3.2f , %3.2f ,%3.2f\n", centers.at<float>(1, 0), centers.at<float>(1, 1),centers.at<float>(1, 2));
printf("the center of class 3:%3.2f , %3.2f ,%3.2f\n", centers.at<float>(2, 0), centers.at<float>(2, 1), centers.at<float>(2, 2));
imshow("output", result);
waitKey(0);
return 0;
}