Kmeans算法是非常经典的聚类算法,在数据挖掘中kmeans经常用来做数据预处理,在图像处理中也可以用作图像的分割。opencv中提供了完整的kmeans算法,其函数原型为:
double 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 表示聚类后的类别中心;
关于Kmeans的理论可以参考:Kmeans理论
下面是Kmeans示例:
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("E://testimage//image.png");
namedWindow("input_image", WINDOW_AUTOSIZE);
imshow("input_image", src);
Scalar colorTab[] = {
Scalar(0,0,255),
Scalar(0,255,0),
Scalar(255,0,0),
Scalar(255,0,255),
Scalar(0,255,255),
Scalar(255,255,0),
};
int width = src.cols;
int height = src.rows;
int dims = src.channels();
int SampleCount = width*height;
int clusterCount = 4;//簇群
//RGB数组转换到样本数据
Mat points(SampleCount, dims, CV_32F,Scalar(10));
Mat lables;
Mat centers(clusterCount, 1, points.type());
int index = 0;
for (int j = 0;j < height;j++)
{
for (int i = 0;i < width;i++)
{
index = j* width+ i;
Vec3b rgb = src.at(j, i);
points.at<float>(index, 0) = static_cast<int>(rgb[0]);
points.at<float>(index, 1) = static_cast<int>(rgb[1]);
points.at<float>(index, 2) = static_cast<int>(rgb[2]);
}
}
//运行kmeans;
kmeans(points, clusterCount, lables, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1), 3, KMEANS_PP_CENTERS, centers);
//显示图像分割结果
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 = lables.at<int>(index, 0);
result.at(i, j)[0] = colorTab[lable][0];
result.at(i, j)[1] = colorTab[lable][1];
result.at(i, j)[2] = colorTab[lable][2];
}
}
namedWindow("output_image", WINDOW_AUTOSIZE);
imshow("output_image", result);
waitKey(0);
return 0;
}