Opencv图像识别从零到精通(28)----Kmeans

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_20823641/article/details/52212608

    K-means算法算是个著名的聚类算法了,不仅容易实现,并且效果也不错,训练过程不需人工干预,实乃模式识别等领域的居家必备良品啊,今天就拿这个算法练练手。属于无监督学习中间接聚类方法中的动态聚类

流程:

1.随机选取样本中的K个点作为聚类中心
2.
计算所有样本到各个聚类中心的距离,将每个样本规划在最近的聚类中
3.
计算每个聚类中所有样本的中心,并将新的中心代替原来的中心
4.
检查新老聚类中心的距离,如果距离超过规定的阈值,则重复2-4,直到小于阈值

       聚类属于无监督学习,以往的回归、朴素贝叶斯、SVM等都是有类别标签y的,也就是说样例中已经给出了样例的分类。而聚类的样本中却没有给定y,只有特征x,比如假设宇宙中的星星可以表示成三维空间中的点集clip_image002[10]。聚类的目的是找到每个样本x潜在的类别y,并将同类别y的样本x放在一起。比如上面的星星,聚类后结果是一个个星团,星团里面的点相互距离比较近,星团间的星星距离就比较远了。

     在聚类问题中,给我们的训练样本是clip_image004,每个clip_image006,没有了y。

     K-means算法是将样本聚类成k个簇(cluster),具体算法描述如下:

1、 随机选取k个聚类质心点(cluster centroids)为clip_image008[6]

2、 重复下面过程直到收敛 {

               对于每一个样例i,计算其应该属于的类

               clip_image009

               对于每一个类j,重新计算该类的质心

               clip_image010[6]

    K是我们事先给定的聚类数,clip_image012[6]代表样例i与k个类中距离最近的那个类,clip_image012[7]的值是1到k中的一个。质心clip_image014[6]代表我们对属于同一个类的样本中心点的猜测,拿星团模型来解释就是要将所有的星星聚成k个星团,首先随机选取k个宇宙中的点(或者k个星星)作为k个星团的质心,然后第一步对于每一个星星计算其到k个质心中每一个的距离,然后选取距离最近的那个星团作为clip_image012[8],这样经过第一步每一个星星都有了所属的星团;第二步对于每一个星团,重新计算它的质心clip_image014[7](对里面所有的星星坐标求平均)。重复迭代第一步和第二步直到质心不变或者变化很小。

     下图展示了对n个样本点进行K-means聚类的效果,这里k取2。

     clip_image015

参考;http://blog.csdn.net/holybin/article/details/22969747

Kmeans有以下几个优点:

1、是解决聚类问题的一种经典算法,算法简单、快速。

2、对处理大数据集,该算法是相对可伸缩的和高效率的,因为它的复杂度是线性的,大约是O(nkt),其中n是所有样本的数目,k是簇的数目,t是迭代的次数。通常k<<n。

3、该算法是收敛的(不会无限迭代下去)。

4、算法尝试找出使平方误差函数值最小的k个划分。当簇是密集的、球状或团状的,而簇与簇之间区别明显时,它的聚类效果很好。

Kmeans也存在如下缺点:

1、只有在簇的平均值被定义的情况下才能使用,不适用于某些应用,如涉及有分类属性的数据不适用。它的前提假设是样本数据的协方差矩阵已经归一化。

2、虽然理论证明它是一定可以收敛的,但是不能保证是全局收敛,可能是局部收敛,这样的话找到的聚类中心不一定是最佳方案。

3、要求用户必须事先给出要生成的簇的数目K。对于同一个数据样本集合,选择不同的K值,得到的结果是不一样的,甚至是不合理的。

4、对中心初值敏感,对于不同的初始值,可能会导致不同的聚类结果。

5、对于"噪声"和孤立点数据敏感,少量的该类数据能够对平均值产生极大影响。

6、不适合于发现非凸面形状的簇,或者大小差别很大的簇。

CV_EXPORTS_W double kmeans( InputArray data, int K, InputOutputArray bestLabels,
                            TermCriteria criteria, int attempts,
                            int flags, OutputArray centers = noArray() );
注意,在opencv中,kmeans()函数是在core.h头文件中的,所以首先要包含这个头文件。下面分析其参数:
1 InputArray data:输入的待聚类向量,其中每一行是一个样本,有多少列,就有多少个样本。
2 int K: 要聚类的个数。
3 InputOutputArray bestLabels:行数与data是一样的,每行有一个数字,代表分类的编号。比如聚类的数目是8类,那么每行的数字在0-3。
4 TerCriteria criteria:这个变量用于控制结束条件。其中TerCriteria是一个模板类,在opencv中的定义如下:
TermCriteria::TermCriteria(int _type, int _maxCount, double _epsilon)
    : type(_type), maxCount(_maxCount), epsilon(_epsilon) {}
其中,type的类型有三种:
TermCriteria::COUNT: 代表以运行的步数为结束条件。
TermCriteria::EPS: 代表迭代到阈值时结束。
TermCriteria::COUNT + TermCriteria::EPS:当步数或阈值中有一个达到条件时终止。
_maxCount是运行的步数,_epsilon是阈值。
5 int attempts:这个变量控制kmean算法进行的次数,选择最优的结果做为最后结果。
6 int flags:这个变量可以取以下三个类型。
KMEANS_RANDOM_CENTERS:随机选择初始中心。
KMEANS_PP_CENTERS:以一种算法,确定初始中心。
KMEANS_USE_INITIAL_LABELS:用户自定义中心。
7 centers:这个变量代表具体的聚类中心。
下面来看一个例子

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include <iostream>
using namespace cv;
using namespace std;


int main( int /*argc*/, char** /*argv*/ )
{
    const int MAX_CLUSTERS = 5;
    Scalar colorTab[] =     
    {
        Scalar(0, 0, 255),
        Scalar(0,255,0),
        Scalar(255,100,100),
        Scalar(255,0,255),
        Scalar(0,255,255)
    };

    Mat img(500, 500, CV_8UC3);
    RNG rng(12345); 

    for(;;)
    {
        int k, clusterCount = rng.uniform(2, MAX_CLUSTERS+1);
        int i, sampleCount = rng.uniform(1, 1001);
        Mat points(sampleCount, 1, CV_32FC2), labels;   

        clusterCount = MIN(clusterCount, sampleCount);
        Mat centers(clusterCount, 1, points.type());    

        /* generate random sample from multigaussian distribution */
        for( k = 0; k < clusterCount; k++ ) 
        {
            Point center;
            center.x = rng.uniform(0, img.cols);
            center.y = rng.uniform(0, img.rows);
            Mat pointChunk = points.rowRange(k*sampleCount/clusterCount,
                                             k == clusterCount - 1 ? sampleCount :
                                             (k+1)*sampleCount/clusterCount);   
  
            rng.fill(pointChunk, CV_RAND_NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
		
        }

        randShuffle(points, 1, &rng);  
        kmeans(points, clusterCount, labels,
               TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
               3, KMEANS_PP_CENTERS, centers);  

        img = Scalar::all(0);

        for( i = 0; i < sampleCount; i++ )
        {
            int clusterIdx = labels.at<int>(i);
            Point ipt = points.at<Point2f>(i);
            circle( img, ipt, 2, colorTab[clusterIdx], CV_FILLED, CV_AA );
        }

        imshow("clusters", img);

        char key = (char)waitKey();    
        if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
            break;
    }

    return 0;
}



matlab

K-means聚类算法采用的是将N*P的矩阵X划分为K个类,使得类内对象之间的距离最大,而类之间的距离最小。

使用方法:

Idx=Kmeans(X,K)

[Idx,C]=Kmeans(X,K)

[Idx,C,sumD]=Kmeans(X,K)

[Idx,C,sumD,D]=Kmeans(X,K)

[…]=Kmeans(…,’Param1’,Val1,’Param2’,Val2,…)

各输入输出参数介绍:

X N*P的数据矩阵

K 表示将X划分为几类,为整数

Idx N*1的向量,存储的是每个点的聚类标号

C K*P的矩阵,存储的是K个聚类质心位置

sumD 1*K的和向量,存储的是类间所有点与该类质心点距离之和

D N*K的矩阵,存储的是每个点与所有质心的距离

[…]=Kmeans(…,'Param1',Val1,'Param2',Val2,…)

这其中的参数Param1、Param2等,主要可以设置为如下:

1. ‘Distance’(距离测度)

‘sqEuclidean’ 欧式距离(默认时,采用此距离方式)

‘cityblock’ 绝度误差和,又称:L1

‘cosine’ 针对向量

‘correlation’  针对有时序关系的值

‘Hamming’ 只针对二进制数据

2. ‘Start’(初始质心位置选择方法)

‘sample’ 从X中随机选取K个质心点

‘uniform’ 根据X的分布范围均匀的随机生成K个质心

‘cluster’ 初始聚类阶段随机选择10%的X的子样本(此方法初始使用’sample’方法)

matrix 提供一K*P的矩阵,作为初始质心位置集合

3. ‘Replicates’(聚类重复次数)  整数

<span style="font-size:18px;">X = [randn(100,2)+ones(100,2);...
     randn(100,2)-ones(100,2)];
opts = statset('Display','final');
[idx,ctrs] = kmeans(X,2,...
                    'Distance','city',...
                    'Replicates',5,...
                    'Options',opts);

plot(X(idx==1,1),X(idx==1,2),'r.','MarkerSize',12)
hold on
plot(X(idx==2,1),X(idx==2,2),'b.','MarkerSize',12)
plot(ctrs(:,1),ctrs(:,2),'kx',...
     'MarkerSize',12,'LineWidth',2)
plot(ctrs(:,1),ctrs(:,2),'ko',...
     'MarkerSize',12,'LineWidth',2)
legend('Cluster 1','Cluster 2','Centroids',...
       'Location','NW')
</span>


图像识别算法交流 QQ群:145076161,欢迎图像识别与图像算法,共同学习与交流

猜你喜欢

转载自blog.csdn.net/qq_20823641/article/details/52212608