opencv之聚类算法

算法介绍:
k-means 算法接受参数 k ,然后将事先输入的n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高,而不同聚类中的对象相似度较小。
聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。


K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一。
K-means算法的基本思想是:
以空间中k个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果。

假设要把样本集分为c个类别,算法描述如下:
(1)适当选择c个类的初始中心;
(2)在第k次迭代中,对任意一个样本,求其到c个中心的距离,将该样本归到距离最短的中心所在的类;
(3)利用均值等方法更新该类的中心值;
(4)对于所有的c个聚类中心,如果利用(2)(3)的迭代法更新后,值保持不变,则迭代结束,否则继续迭代。
该算法的最大优势在于简洁和快速。算法的关键在于初始中心的选择和距离公式。



//opencv库函数


CvRNG cvRNG( int64 seed CV_DEFAULT(-1))  //产生随机数种子,返回CvRNG

unsigned cvRandInt( CvRNG* rng );//产生随机的unsigned int值

void cvRandArr( CvRNG* rng, CvArr* arr, int dist_type, CvScalar param1, CvScalar param2 );//用随机数填充数组并更新 RNG 状态 
参考:http://www.opencv.org.cn/index.php/Cxcore%E6%95%B0%E7%BB%84%E6%93%8D%E4%BD%9C
void cvKMeans2( const CvArr* samples, int cluster_count,CvArr* labels, CvTermCriteria termcrit );//按照给定的类别数目对样本集合进行聚类

参考:http://www.opencv.org.cn/index.php/Cxcore%E5%85%B6%E5%AE%83%E6%B7%B7%E5%90%88%E5%87%BD%E6%95%B0
CvTermCriteria //迭代算法的终止准则

typedef struct CvTermCriteria
 {
  int    type;  /* CV_TERMCRIT_ITER 和CV_TERMCRIT_EPS二值之一,或者二者的组合 */
  int    max_iter; /* 最大迭代次数 */
  double epsilon; /* 结果的精确性 */
 }
 CvTermCriteria;

精简的测试代码

#include<cv.h>
#include<highgui.h>
#include<stdio.h>
#include<malloc.h>
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cxcore.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cvaux.lib")
/********************************************************************************
*
*
*  本程序是精简的聚类算法演示例程
*  作者:xlh145
*  博客:http://blog.csdn.net/xlh145/
*
*
********************************************************************************/
#define MAX_POINTS 1000  /*最多产生1000个样本点*/
#define CLASS_COUNT  5 /*生成5个分类*/
int main()
{
	CvRNG rng = cvRNG(-1);//产生随机数种子
	CvScalar color_tab[5];//定义5种颜色
    color_tab[0] = CV_RGB(255,0,0);
    color_tab[1] = CV_RGB(0,255,0);
    color_tab[2] = CV_RGB(100,100,255);
    color_tab[3] = CV_RGB(255,0,255);
    color_tab[4] = CV_RGB(255,255,0);
	IplImage* img = cvCreateImage(cvSize(500,500),8,3);//用于显示结果
	cvNamedWindow("result",1);//产生窗体
	//定义数组
	int sample_count = cvRandInt(&rng)%MAX_POINTS+1;//样本的数量
	int clusters_count = cvRandInt(&rng)%CLASS_COUNT+1;//分类的数量
	CvMat* points = cvCreateMat(sample_count,1,CV_32FC2);//双通道的数组,储存点的坐标
	CvMat * clusters = cvCreateMat(sample_count,1,CV_32SC1);//单通道的数组,储存分类的标识
	//创建样本数据
	for(int i=0;i<clusters_count;i++)
	{
		CvPoint center; //每一个分类样本的中心
		CvMat ptemp;//临时的数组对象
		center.x = cvRandInt(&rng)%img->width;
		center.y = cvRandInt(&rng)%img->height;
		int count = sample_count/clusters_count;//均分每一个分类包含的样本
		cvGetRows(points,&ptemp,i*count,(i==clusters_count-1)?sample_count:(i+1)*count);//获取数组中的指定行数的指针 存储到ptemp中
		//按照正态分布随机化数组数据
		cvRandArr(&rng,&ptemp,CV_RAND_NORMAL,cvScalar(center.x,center.y,0,0),cvScalar(img->width*0.1,img->height*0.1,0,0));

	}
	//随机洗牌
	for(i = 0; i<sample_count/2;i++)
	{
		CvPoint2D32f* p = (CvPoint2D32f*)points->data.fl;//数组的数据存放指针
		CvPoint2D32f* p1 = p+cvRandInt(&rng)%sample_count;
		CvPoint2D32f* p2 = p+cvRandInt(&rng)%sample_count;
		CvPoint2D32f t;
		CV_SWAP(*p1,*p2,t);
	}

	 //Kmeans聚类
	 cvKMeans2(points,clusters_count,clusters,cvTermCriteria(CV_TERMCRIT_NUMBER|CV_TERMCRIT_ITER,10,1.0));
	 cvZero(img);
	 //在图像上显示分类的点
	 for(i=0;i<sample_count;i++)
	 {
		 int id = clusters->data.i[i];//得到点的分类聚合ID
		 CvPoint pt;
		 pt.x = (int)points->data.fl[i*2+0];
		 pt.y = (int)points->data.fl[i*2+1];
		 cvCircle( img, pt, 2, color_tab[id], CV_FILLED, CV_AA, 0 );
	 }

	cvShowImage("result",img);
	cvWaitKey(0);
	//释放存储空间
	cvReleaseImage(&img);
	cvReleaseMat(&points);
	cvReleaseMat(&clusters);
	cvDestroyWindow("result");
	return 0;
}
    原文作者:聚类算法
    原文地址: https://blog.csdn.net/xlh145/article/details/8862680
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞