浅谈Kmeans聚类
http://www.cnblogs.com/easymind223/archive/2012/10/30/2747178.html
聚类分析是一种静态数据分析方法,常被用于机器学习,模式识别,数据挖掘等领域。通常认为,聚类是一种无监督式的机器学习方法,它的过程是这样的:在未知样本类别的情况下,通过计算样本彼此间的距离(欧式距离,马式距离,汉明距离,余弦距离等)来估计样本所属类别。从结构性来划分,聚类方法分为自上而下和自下而上两种方法,前者的算法是先把所有样本视为一类,然后不断从这个大类中分离出小类,直到不能再分为止;后者则相反,首先所有样本自成一类,然后不断两两合并,直到最终形成几个大类。
常用的聚类方法主要有以下四种: //照搬的wiki,比较懒...
Connectivity based clustering (如hierarchical clustering 层次聚类法)
Centroid-based clustering (如kmeans)
Distribution-based clustering
Density-based clustering
Kmeans聚类是一种自下而上的聚类方法,它的优点是简单、速度快;缺点是聚类结果与初始中心的选择有关系,且必须提供聚类的数目。Kmeans的第二个缺点是致命的,因为在有些时候,我们不知道样本集将要聚成多少个类别,这种时候kmeans是不适合的,推荐使用hierarchical 或meanshift来聚类。第一个缺点可以通过多次聚类取最佳结果来解决。
Kmeans的计算过程大概表示如下
随机选择k个聚类中心. 最终的类别个数<= k
计算每个样本到各个中心的距离
每个样本聚类到离它最近的中心
重新计算每个新类的中心
重复以上步骤直到满足收敛要求。(通常就是中心点不再改变或满足一定迭代次数).
opencv1.0的例子, 随机生机的散点,每个点是一个二维样本


#include "cxcore.h"
#include "highgui.h" #define MAX_CLUSTERS 5 int main( int argc, char** argv )
{
CvScalar color_tab[MAX_CLUSTERS];
IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
CvRNG rng = cvRNG(0xffffffff); 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); cvNamedWindow( "clusters", 1 ); for(;;)
{
int k, cluster_count = cvRandInt(&rng)%MAX_CLUSTERS + 1;
int i, sample_count = cvRandInt(&rng)%1000 + 1;
CvMat* points = cvCreateMat( sample_count, 1, CV_32FC2 );
CvMat* clusters = cvCreateMat( sample_count, 1, CV_32SC1 ); /* generate random sample from multigaussian distribution */
for( k = 0; k < cluster_count; k++ )
{
CvPoint center;
CvMat point_chunk;
center.x = cvRandInt(&rng)%img->width;
center.y = cvRandInt(&rng)%img->height;
cvGetRows( points, &point_chunk, k*sample_count/cluster_count,
k == cluster_count - 1 ? sample_count : (k+1)*sample_count/cluster_count );
cvRandArr( &rng, &point_chunk, CV_RAND_NORMAL,
cvScalar(center.x,center.y,0,0),
cvScalar(img->width/6, img->height/6,0,0) );
} /* shuffle samples */
for( i = 0; i < sample_count/2; i++ )
{
CvPoint2D32f* pt1 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
CvPoint2D32f* pt2 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
CvPoint2D32f temp;
CV_SWAP( *pt1, *pt2, temp );
} cvKMeans2( points, cluster_count, clusters,
cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0 )); cvZero( img ); for( i = 0; i < sample_count; i++ )
{
CvPoint2D32f pt = ((CvPoint2D32f*)points->data.fl)[i];
int cluster_idx = clusters->data.i[i];
cvCircle( img, cvPointFrom32f(pt), 2, color_tab[cluster_idx], CV_FILLED );
} cvReleaseMat( &points );
cvReleaseMat( &clusters ); cvShowImage( "clusters", img ); int key = cvWaitKey(0);
if( key == 27 ) // 'ESC'
break;
}
}

opencv2.4的例子,对一张图片(377*280)的像素点进行聚类,每个像素点是一个五维样本(x,y,r,g,b),聚类结果如下
第一行: 原图; k=2, 用时t=72ms; k=3, t=93ms
第二行:k=4, t= 128ms; k=10, t=330ms; k=20, t=676ms






从图中某些局部可以看出,并不是k越大,细节就越显著(如后两幅图中向日葵的眼睛),这是因为kmean的初始位置是随机的。相同的样本每次聚类会有不同的结果

#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include <iostream>
#include <string>
using namespace cv;
using namespace std; //这是Kmeans算法的一个缺点,在聚类之前需要指定类别个数
const int nClusters = 20; int _tmain(int argc, _TCHAR* argv[])
{
Mat src; //相当于IplImage // src = imread("fruit.jpg"); //只是另一张图
src = imread("zombie.jpg"); //cvLoadImage
imshow("original", src); //cvShowImage blur(src, src, Size(11,11));
imshow("blurred", src); //p是特征矩阵,每行表示一个特征,每个特征对应src中每个像素点的(x,y,r,g,b共5维)
Mat p = Mat::zeros(src.cols*src.rows, 5, CV_32F); //初始化全0矩阵
Mat bestLabels, centers, clustered;
vector<Mat> bgr;
cv::split(src, bgr); //分隔出src的三个通道 for(int i=0; i<src.cols*src.rows; i++)
{
p.at<float>(i,0) = (i/src.cols) / src.rows; // p.at<uchar>(y,x) 相当于 p->Imagedata[y *p->widthstep + x], p是8位uchar
p.at<float>(i,1) = (i%src.cols) / src.cols; // p.at<float>(y,x) 相当于 p->Imagedata[y *p->widthstep + x], p是32位float
p.at<float>(i,2) = bgr[0].data[i] / 255.0;
p.at<float>(i,3) = bgr[1].data[i] / 255.0;
p.at<float>(i,4) = bgr[2].data[i] / 255.0;
} //计算时间
double t = (double)cvGetTickCount(); //kmeans聚类,每个样本的标签保存在bestLabels中
cv::kmeans(p, nClusters, bestLabels,
TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
3, KMEANS_PP_CENTERS, centers); t = (double)cvGetTickCount() - t;
float timecost = t/(cvGetTickFrequency()*1000); //给每个类别赋颜色,其值等于每个类第一个元素的值
Vec3b colors[nClusters];
bool colormask[nClusters]; memset(colormask, 0, nClusters*sizeof(bool));
int count = 0;
for(int i=0; i<src.cols*src.rows; i++)
{
int clusterindex = bestLabels.at<int>(i,0);
for (int j=0; j<nClusters; j++)
{
if(j == clusterindex && colormask[j] == 0)
{
int y = i/src.cols;
int x = i%src.cols;
colors[j] = src.at<Vec3b>(y,x);
colormask[j] = 1;
count++;
break;
}
}
if(nClusters == count)break;
} //显示聚类结果
clustered = Mat(src.rows, src.cols, CV_8UC3);
for(int i=0; i<src.cols*src.rows; i++) {
int y = i/src.cols;
int x = i%src.cols;
int clusterindex = bestLabels.at<int>(i,0);
clustered.at<Vec3b>(y, x) = colors[clusterindex];
} imshow("clustered", clustered); cout<< "time cost = %gms\n"<<timecost ; //保存图像
stringstream s1,s2;
s1<<timecost;
s2<<nClusters;
string name = "n=" + s2.str() + "_timecost=" + s1.str() + ".png";
imwrite(name, clustered);
waitKey();
return 0;
}
浅谈Kmeans聚类的更多相关文章
- 浅谈K-means聚类算法
K-means算法的起源 1967年,James MacQueen在他的论文<用于多变量观测分类和分析的一些方法>中首次提出 “K-means”这一术语.1957年,贝尔实验室也将标准算法 ...
- K-Means 聚类算法
K-Means 概念定义: K-Means 是一种基于距离的排他的聚类划分方法. 上面的 K-Means 描述中包含了几个概念: 聚类(Clustering):K-Means 是一种聚类分析(Clus ...
- [转]python进行中文文本聚类(切词以及Kmeans聚类)
简介 查看百度搜索中文文本聚类我失望的发现,网上竟然没有一个完整的关于Python实现的中文文本聚类(乃至搜索关键词python 中文文本聚类也是如此),网上大部分是关于文本聚类的Kmeans聚类的原 ...
- 转:浅谈Spectral Clustering 谱聚类
浅谈Spectral Clustering Spectral Clustering,中文通常称为“谱聚类”.由于使用的矩阵的细微差别,谱聚类实际上可以说是一“类”算法. Spectral Cluste ...
- 4.无监督学习--K-means聚类
K-means方法及其应用 1.K-means聚类算法简介: k-means算法以k为参数,把n个对象分成k个簇,使簇内具有较高的相似度,而簇间的相似度较低.主要处理过程包括: 1.随机选择k个点作为 ...
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- 浅谈 LayoutInflater
浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
- 浅谈SQL注入风险 - 一个Login拿下Server
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
随机推荐
- Android应用程序模型:应用程序,任务,进程,线程
大多数操作系统,在应用程序所寄存的可执行程序映像(如Windows系统里的.exe).它所运行的进程以及和用户交互的图标和应用之间有一种严格的1对1关系.在Android系统里,这些关联要松散得多.并 ...
- Redis使用小结
Redis官方没有windows版本的,对于Windows环境的redis,有如下两个方案 微软的移植版本,但只支持到3.2 下载地址 win10及以上的版本直接通过win10的liunx子系统执行 ...
- HDU 4739 Zhuge Liang's Mines (2013杭州网络赛1002题)
Zhuge Liang's Mines Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- DMA Stream/Channel Outputting via GPIOC[0..7]
Ok, so quickly mashing up another example using a different TIM, DMA Stream/Channel for illustration ...
- CefSharp 在同一窗口打开链接的方法
摘要 在winform中使用cefsharp的时候,我们在浏览网页的时候,想在同一个窗口打开链接,而不是创建新的窗口.可以通过下面的方法实现. 解决方案 CefSharp 中控制弹窗的接口是 ILif ...
- 对json数据key进行替换
原文:https://blog.csdn.net/qq_39750658/article/details/83411897 import java.util.HashMap; import java. ...
- Android之 MTP框架和流程分析
概要 本文的目的是介绍Android系统中MTP的一些相关知识.主要的内容包括:第1部分 MTP简介 对Mtp协议进行简单的介绍.第2部分 MTP框架 介绍 ...
- self.xxx = nil 可以等效于[_xxx release] _xxx= nil 么
如果属性是copy.retain的话是等价的.如下: - (void)setXXX:(NSString*)axx { if (_xxx != axx) { [_xxx release]; _xxx = ...
- 详细解释如何通过Android自带的方式来实现图片的裁剪——原理分析+解决方案
我们很多时候需要进行图片的裁剪,其实这个功能在android系统中已经有一套解决方案了,虽然界面和效果并不是很优秀但功能毫无疑问是完美实现了.至于,不用自带的方案怎么做自定义,这个就是后话了.本篇主要 ...
- 《HTML5与CSS3基础教程(第8版)》
<HTML5与CSS3基础教程(第8版)> 基本信息 原书名:HTML and CSS:visual quickstart guide 作者: (美)Elizabeth Castro ...