K-means之C++及OpenCV实现
2012-03-29 17:13
417 查看
K-means算法算是个著名的聚类算法了,不仅容易实现,并且效果也不错,训练过程不需人工干预,实乃模式识别等领域的居家必备良品啊,今天就拿这个算法练练手。
总结来说,这个算法的步骤如下:
1.随机选取样本中的K个点作为聚类中心
那么,现在,我实现的程序的步骤也是按照上面一步一步来的,
为了方便,我直接在平面上随机产生n个点,选取前K个点作为聚类中心,
距离就定义为平面上的欧式距离,
然后为了形象化地观察过程和结果,我将过程以图像的方式显示。
代码如下:
首先是主体:
然后是其他函数的实现:
看下效果:
而通过几次运行和观察,阈值不必取的很小,首先是迭代次数越来越多,时间越来越长,但结果差别却是越来越小,即,到几次迭代之后就能取得好的效果了,再迭代下去取的结果跟原来相差不大。
然后,Kmeans的缺点:
K值完全是凭经验自己定义,无法自动计算
结果跟初始时取的聚类中心差别很大,即每次计算都将有误差
总结来说,这个算法的步骤如下:
1.随机选取样本中的K个点作为聚类中心
2.计算所有样本到各个聚类中心的距离,将每个样本规划在最近的聚类中
3.计算每个聚类中所有样本的中心,并将新的中心代替原来的中心
4.检查新老聚类中心的距离,如果距离超过规定的阈值,则重复2-4,直到小于阈值
那么,现在,我实现的程序的步骤也是按照上面一步一步来的,为了方便,我直接在平面上随机产生n个点,选取前K个点作为聚类中心,
距离就定义为平面上的欧式距离,
然后为了形象化地观察过程和结果,我将过程以图像的方式显示。
代码如下:
首先是主体:
int iter_times = 0;//迭代次数 while(!good_result())//检查是否是需要的聚类中心 { for(int i = 0;i < POINT_NUM;i++) { double min = 10000; int min_k = 0; for(int j = 0;j < K;j++) { double tmp = DIS(c[j].center,s[i].p); if(tmp < min) { min = tmp; min_k = j; } } s[i].cluster = min_k; c[min_k].count++; } update_center();//更新聚类中心 iter_times++; show_outcome(); }
然后是其他函数的实现:
void update_center() { double x[K],y[K]; memset(x,0,sizeof(x)); memset(y,0,sizeof(y)); for(int i = 0;i < POINT_NUM;i++) { x[s[i].cluster] += s[i].p.x; y[s[i].cluster] += s[i].p.y; } for(int i = 0;i < K;i++) { c[i].pre_center = c[i].center; c[i].center.x = x[i] / c[i].count; c[i].center.y = y[i] / c[i].count; c[i].count = 0; } }判断是否是需要的:
bool good_result() { for(int i = 0;i < K;i++) { if(DIS(c[i].center,c[i].pre_center) > TH) return false; } return true; }显示结果:
void show_outcome() { for(int y = 0;y < HEIGHT;y++)//这里将平面中所有的点都标记,就可以看到平面是怎样被划分的了 for(int x = 0;x < WIDTH;x++) { double min = 1000; int min_k = 0; CvPoint p = cvPoint(x,y); for(int i = 0;i < K;i++) { double tmp = DIS(c[i].center,p); if(tmp < min) { min = tmp; min_k = i; } } IMG_B(img,x,y) = color[min_k].val[0]; IMG_G(img,x,y) = color[min_k].val[1]; IMG_R(img,x,y) = color[min_k].val[2]; IMG_A(img,x,y) = 200;//4通道图像,就是说可以是透明的,纯试验而已,哪知道直接显示没效果,要保存之后才能看出来。 } CvScalar scalar = cvScalar(255,255,255,255); for(int i = 0;i < POINT_NUM;i++)//画每个样本点 { int x = s[i].p.x; int y = s[i].p.y; cvLine(img,cvPoint(x - 5,y),cvPoint(x + 5,y),scalar,2); cvLine(img,cvPoint(x,y - 5),cvPoint(x,y + 5),scalar,2); } for(int i = 0;i < K;i++)//画聚类中心 { int x = c[i].center.x; int y = c[i].center.y; cvCircle(img,cvPoint(x,y),20,scalar,2); } cvShowImage("Image",img); cvWaitKey(100);//100毫秒是个差不多的数值,可以完整的看到聚类过程 }
看下效果:
而通过几次运行和观察,阈值不必取的很小,首先是迭代次数越来越多,时间越来越长,但结果差别却是越来越小,即,到几次迭代之后就能取得好的效果了,再迭代下去取的结果跟原来相差不大。
然后,Kmeans的缺点:
K值完全是凭经验自己定义,无法自动计算
结果跟初始时取的聚类中心差别很大,即每次计算都将有误差
相关文章推荐
- K-means之C++及OpenCV实现
- 利用数组操作实现灰度图像的上下左右翻转(C++&opencv)
- 小波变换 C++ opencv 实现
- 协方差矩阵介绍及C++/OpenCV/Eigen的三种实现
- Android(安卓)开发通过NDK调用JNI,使用opencv做本地c++代码开发配置方法实现边缘检测代码(2)
- [algorithm,c++] 基于c++的二维k-means代码实现
- SIFT算法的c++实现(VS2010+OpenCV2.3.1)
- C++实现K-means,聚类原理解析(并用在图片像素点聚类)
- 贪吃蛇小游戏—C++、Opencv编写实现
- 【机器学习实战之三】:C++实现K-均值(K-Means)聚类算法
- opencv2.0以后新增C++接口的 Mat矩阵 单行赋值及矩阵合并的问题与实现(苦心研究多天才解决!)
- 数学之美之分形——C++及OpenCV实现Julia集和Mandelbrot集绘制
- SIFT特征2-基于OpenCV和C++的算法实现
- 【图像特征提取12】OpenCv的SIFT图像局部特征提取描述算法C++代码的实现
- 矩阵伪逆介绍及C++/OpenCV/Eigen的三种实现
- 匈牙利算法的C++实现(基于OpenCV)
- RANSAC之opencv和C++实现
- 二维凸包convex hull之C++及OpenCV实现
- 多目标跟踪计数opencv(C++实现)
- 基于OpenCV的人脸检测——C++和Python实现