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

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

流程:

1.随机选取样本中的K个点作为聚类中心

2.计算所有样本到各个聚类中心的距离,将每个样本规划在最近的聚类中

3.计算每个聚类中所有样本的中心,并将新的中心代替原来的中心

4.检查新老聚类中心的距离,如果距离超过规定的阈值,则重复2-4,直到小于阈值

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

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

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

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

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

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

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

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

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

参考;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,欢迎图像识别与图像算法,共同学习与交流

时间: 2024-08-05 11:12:18

Opencv图像识别从零到精通(28)----Kmeans的相关文章

Opencv图像识别从零到精通(26)---分水岭

分水岭是区域分割三个方法的最后一个,对于前景背景的分割有不错的效果. 分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭.分水岭的概念和形成可以通过模拟浸入过程来说明.在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭. 分水岭

Opencv图像识别从零到精通(30)---重映射,仿射变换

一.序言 面对图像处理的时候,我们会旋转缩放图像,例如前面所提高的resize 插值改变,也是几何变换: 几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定为整数坐标.这时就需要灰度级差值将映射的新坐标匹配到输出像素之间.最简单的插值方法是最近邻插值,就是令输出像素的灰度值等于映射最近的位置像素,该方法可能会产生锯齿.这种方法也叫零阶插值,相应比较复杂的还有一阶和高阶插值. 除了插值算法感觉只要了解就可以了,图像处理中比较需要理

Opencv图像识别从零到精通(29)-----图像金字塔,向上上下采样,resize插值

金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似.我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低 一.两个金字塔 高斯金字塔(Gaussianpyramid): 用来向下采样,主要的图像金字塔 拉普拉斯金字塔(Laplacianpyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用. 高斯金字塔不同(DoG)又称为拉普拉斯金字塔,给出计算方式前,先加强一下定义 记得在上面我

Opencv图像识别从零到精通(33)----moravec角点、harris角点

一.角点 图像处理和与计算机视觉领域,兴趣点(interest points),或称作关键点(keypoints).特征点(feature points) 被大量用于解决物体识别,图像识别.图像匹配.视觉跟踪.三维重建等一系列的问题.我们不再观察整幅图,而是选择某些特殊的点,然后对他们进行局部有的放矢的分析.如果能检测到足够多的这种点,同时他们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就有使用价值. 图像特征类型可以被分为如下三种: <1>边缘                   

Opencv图像识别从零到精通(7)----图像平移、旋转、镜像

根据vc6.0c++的学习经验,如果可以很好的自己编程,让图像进行平移旋转这些操作,那么就好像能够清楚的看见图像的内部结构当然这里你怎么访问像素,这个可以自己选一种适合的,最多的是ptr指针,at也是挺多的.看着很简单的变换,可以对图像处理上手的更快,当然对于旋转可能就稍微i难了一点,不过opencv提供了resize(0,remap()等这样的函数,可以方便的让我们进行学习-特别是旋转的时候,有很多的变换,你可以任意旋转一个角度,也可能一直旋转,当然还可以保持图像大小不变的旋转和大小变换的旋转

Opencv图像识别从零到精通(24)------漫水填充,种子填充,区域生长、孔洞填充

可以说从这篇文章开始,就结束了图像识别的入门基础,来到了第二阶段的学习.在平时处理二值图像的时候,除了要进行形态学的一些操作,还有有上一节讲到的轮廓连通区域的面积周长标记等,还有一个最常见的就是孔洞的填充,opencv这里成为漫水填充,其实也可以叫种子填充,或者区域生长,基本的原理是一样的,但是应用的时候需要注意一下,种子填充用递归的办法,回溯算法,漫水填充使用堆栈,提高效率,同时还提供了一种方式是扫描行.经常用来填充孔洞,现在来具体看看. 漫水填充:也就是用一定颜色填充联通区域,通过设置可连通

Opencv图像识别从零到精通(27)---grabcut

这是基于图论的分割方法,所以开始就先介绍了 Graph cuts,然后再到Grab cut   一. Graph cuts Graph cuts是一种十分有用和流行的能量优化算法,在计算机视觉领域普遍应用于前背景分割(Image segmentation).立体视觉(stereo vision).抠图(Image matting)等. 此类方法把图像分割问题与图的最小割(min cut)问题相关联.首先用一个无向图G=<V,E>表示要分割的图像,V和E分别是顶点(vertex)和边(edge)

Opencv图像识别从零到精通(34)---SIFI

   一.理论知识 Scale Invariant Feature Transform,尺度不变特征变换匹配算法,对于算法的理论介绍,可以参考这篇文章http://blog.csdn.net/qq_20823641/article/details/51692415,里面很详细,可以更好的学习.这里就不多介绍.后面就挑选重点的来说 二.SIFT 主要思想 SIFT算法是一种提取局部特征的算法,在尺度空间寻找极值点,提取位置,尺度,旋转不变量. 三.SIFT算法的主要特点: a) SIFT特征是图像

Opencv图像识别从零到精通(31)----图像修补,分离合并通道

一.图像修复简介 图像修复是图像复原中的一个重要内容,其目的是利用图像现有的信息来恢复丢失的信息.可用于旧照片中丢失信息的恢复,视频文字去除以及视频错误隐藏等.简言之,图像修复就是对图像上信息缺损区域进行信息填充的过程,其目的就是为了对有信息缺损的图像进行复原,并且使得观察者无法察觉到图像曾经缺损或者已经修复      图像修复技术简单来说,就是利用那些被破坏区域的边缘,即是边缘的颜色和结构,繁殖和混合到损坏的图像中,来进行修复图像 目前存在两大类图像修复技术:一类是用于修复小尺度缺损的数字图像