(1)随机选择两个中心点;
(2)计算每个点到这两个中心点的距离,最近的分成一类(连接起来);
(3)重新计算中心点(平均值计算),计算新的中心点到久的中心点的差值如果小于输入的值,就说明中心的位置发生了变化,,那么到(2)步重新计算中心点到每个点的距离,开始下一次循环;
(4)执行多个迭代之后,满足收敛时,得到最终的分类。
double cv::kmeans( InputArray data, int K, InputOutputArray bestLabels
TermCriteria citeria, int attempts, int flags, OutputArray)
(1)data: 需要自动聚类的数据,一般是一个Mat。浮点型的矩阵,每行为一个样本。
(2)k: 取成几类,比较关键的一个参数。
(3)bestLabels: 返回的类别标记,整型数字。
(4)criteria: 算法结束的标准,获取期望精度的迭代最大次数
(5)attempts: 判断某个样本为某个类的最少聚类次数,比如值为3时,则某个样本聚类3次都为同一个类,则确定下来。
(6)flags: 确定簇心的计算方式。有三个值可选:KMEANS_RANDOM_CENTERS 表示随机初始化簇心。KMEANS_PP_CENTERS 表示用kmeans++算法来初始化簇心(没用过),KMEANS_USE_INITIAL_LABELS 表示第一次聚类时用用户给定的值初始化聚类,后面几次的聚类,则自动确定簇心。
(7)centers: 用来初始化簇心的。与前一个flags参数的选择有关。如果选择KMEANS_RANDOM_CENTERS随机初始化簇心,则这个参数可省略。
#include
#include
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("D:/source/image/dlrb.png");
if (src.empty())
{
printf("read image error\n");
system("pause");
return -1;
}
imshow("src", src);
Scalar colorTab[] = {
Scalar(0, 0, 255),
Scalar(0, 255, 0),
Scalar(255, 0, 0),
Scalar(0, 255, 255),
Scalar(255, 0, 255)
};
int width = src.cols;
int height = src.rows;
int dims = src.channels();
// 初始化定义
int sampleCount = width * height;
int clusterCount = 4;
Mat points(sampleCount, dims, CV_32F, Scalar(10));
Mat labels;
Mat centers(clusterCount, 1, points.type());
// RGB 数据类型转化到样本数据
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
// 多维转一维
index = row * width + col;
Vec3b bgr = src.at(row, col);
points.at(index, 0) = static_cast(bgr[0]);
points.at(index, 1) = static_cast(bgr[1]);
points.at(index, 2) = static_cast(bgr[2]);
}
}
// KMeans
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);
// 显示图像分割后的结果,一维转多维
Mat result = Mat::zeros(src.size(), src.type());
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
index = row * width + col;
int label = labels.at(index, 0);
result.at(row, col)[0] = colorTab[label][0];
result.at(row, col)[1] = colorTab[label][1];
result.at(row, col)[2] = colorTab[label][2];
}
}
// 中心点显示
for (int i = 0; i < centers.rows; i++)
{
int x = centers.at(i, 0);
int y = centers.at(i, 1);
circle(result, Point(x, y), 10, Scalar(255,255,255), 1, LINE_AA);
}
imshow("result", result);
waitKey(0);
return(0);
}