1.K-means算法
K-means是一种经典的无监督聚类算法。
算法原理:
(1)从N个数据对象中取K个点作为聚类中心。
(2)计算N个数据对象到各个聚类中心的距离,将N个数据对象划分到距离最近的中心,形成K个聚类。
(3)计算每个聚类的中心,将新的中心代替原来的中心。
(4)检查新老聚类中心的距离,重复(2)-(3)直到距离小于规定阈值。
2.opencv函数
cvKMeans2(const CvArr* samples, int nclusters, CvArr* labels, CvTermCriteria criteria, int attempts=1, CvRNG*rng=0, int flags=0, CvArr* centers=0, double* compactness=0)
kmeans(InputArray samples, int clusterCount, InputOutputArray labels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() )
Parameters: |
|
---|
输入样本的浮点矩阵,每个样本一行
clusterCount
给定的聚类数目
labels
输出整数向量:每个样本对应的类别标识
criteria
迭代终止条件:迭代最大次数和精度
attempts
运行K-means的次数,取结果最好的聚类为最终聚类,和flags一起使用
flags
KMEANS_RANDOM_CENTERS 每次尝试选取随机初始化中心
KMEANS_PP_CENTERS 使用Arthur and Vassilvitskii算法进行中心初始化
KMEANS_USE_INITIAL_LABELS使用用户自定义初始点
3.实现
处理图像:
将图像的颜色数据进行K-means聚类,这里有黑、白、红三色,所以分为3类进行效果测试。
将图像每个像素三通道值按行存给样本samples。
for (int i = 0; i < img->width;i++)
{
for (int j = 0; j < img->height;j++)
{
CvScalar s;
s.val[0] = (float)cvGet2D(img, j, i).val[0];
s.val[1] = (float)cvGet2D(img, j, i).val[1];
s.val[2] = (float)cvGet2D(img, j, i).val[2];
cvSet2D(samples,k++,0,s);
}
}
nCluster定义为3。
进行K-means聚类分析
cvKMeans2(samples,nCluster,clusters,cvTermCriteria(CV_TERMCRIT_ITER,100,1.0));
保存结果给clusters,这里是根据图像坐标对应颜色的聚类结果分别标志为0,1,2。
测试分类效果:
将图像基于聚类标签结果进行提取。
(1)提取标签0
k = 0;
int val = 0;
for (int i = 0; i < img->width;i++)
{
for (int j = 0; j < img->height;j++)
{
val = (int)clusters->data.i[k++];
CvScalar s1;
if (val == 0)
{
s1.val[0] = 255;
}
else
{
s1.val[0] = 0;
}
cvSet2D(bin,j,i,s1);
}
}
将图像基于bin进行mask复制,显示标签0对应的区域
cvThreshold(bin,bin,200,255,CV_THRESH_BINARY);
IplImage *img1=cvCreateImage(cvSize(img->width,img->height),img->depth,img->nChannels);
cvCopy(img,img1,bin);
cvShowImage("原图", img);
cvShowImage("bin",bin);
cvShowImage("聚类图像",img1);
cvWaitKey(0);
得到图像效果如下:
将val改为1,得到图像效果如下:
(3)提取标签2
将val改为2,得到图像效果如下: