zoukankan      html  css  js  c++  java
  • cvKMeans2函数用法概述

         一般情况下,我们通过C++/Matlab/Python等语言进行实现K-means算法,结合近期我刚刚学的C++,先从C++实现谈起,C++里面我们一般采用的是OpenCV库中写好的K-means函数,即cvKmeans2,首先来看函数原型:

         从OpenCV manual看到的是:
         int cvKMeans2(const CvArr* samples, int nclusters,
            CvArr* labels, CvTermCriteria termcrit,
            int attempts=1, CvRNG* rng=0,int flags=0,
            CvArr* centers=0,double* compactness=0);


        由于除去已经确定的参数,我们自己需要输入的为:
    void cvKMeans2( 
        const CvArr* samples, //输入样本的浮点矩阵,每个样本一行。 
        int cluster_count,  //所给定的聚类数目 
         * labels,    //输出整数向量:每个样本对应的类别标识 ,注意:该变量的行数必须与samples的行数是一致的
         CvTermCriteria termcrit //指定聚类的最大迭代次数和/或精度(两次迭代引起的聚类中心的移动距离)
     ); 

    一个例程如下所示:

     1 #ifdef _CH_
     2 #pragma package <opencv>
     3 #endif
     4 
     5 #define CV_NO_BACKWARD_COMPATIBILITY
     6 
     7 #ifndef _EiC
     8 #include "cv.h"
     9 #include "highgui.h"
    10 #include <stdio.h>
    11 #endif
    12 
    13 int main( int argc, char** argv )
    14 {
    15     #define MAX_CLUSTERS 5    //设置类别的颜色,个数(《=5)
    16     CvScalar color_tab[MAX_CLUSTERS];
    17     IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
    18     CvRNG rng = cvRNG(-1);
    19     CvPoint ipt;
    20 
    21     color_tab[0] = CV_RGB(255,0,0);
    22     color_tab[1] = CV_RGB(0,255,0);
    23     color_tab[2] = CV_RGB(100,100,255);
    24     color_tab[3] = CV_RGB(255,0,255);
    25     color_tab[4] = CV_RGB(255,255,0);
    26 
    27     cvNamedWindow( "clusters", 1 );
    28 
    29     for(;;)
    30     {
    31         char key;
    32         int k, cluster_count = cvRandInt(&rng)%MAX_CLUSTERS + 1;
    33         int i, sample_count = cvRandInt(&rng)%1000 + 1;
    34         CvMat* points = cvCreateMat( sample_count, 1, CV_32FC2 );//这里实际上的列数可以是很多列,并不一定仅仅是局限于这种两列(因为这里每列是一个二元数组)                             
    35 CvMat* clusters = cvCreateMat( sample_count, 1, CV_32SC1 ); 36 cluster_count = MIN(cluster_count, sample_count); 37 38 /** generate random sample from multigaussian distribution */ 39 for( k = 0; k < cluster_count; k++ ) 40 { 41 CvPoint center; 42 CvMat point_chunk; 43 center.x = cvRandInt(&rng)%img->width; 44 center.y = cvRandInt(&rng)%img->height; 45 cvGetRows( points, &point_chunk, k*sample_count/cluster_count, 46 k == cluster_count - 1 ? sample_count : 47 (k+1)*sample_count/cluster_count, 1 ); 48 49 cvRandArr( &rng, &point_chunk, CV_RAND_NORMAL, 50 cvScalar(center.x,center.y,0,0), 51 cvScalar(img->width*0.1,img->height*0.1,0,0)); 52 } 53 54 /** shuffle samples */ 55 for( i = 0; i < sample_count/2; i++ ) 56 { 57 CvPoint2D32f* pt1 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count; 58 CvPoint2D32f* pt2 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count; 59 CvPoint2D32f temp; 60 CV_SWAP( *pt1, *pt2, temp ); 61 } 62 63 printf( "iterations=%d ", cvKMeans2( points, cluster_count, clusters, 64 cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0 ), 65 5, 0, 0, 0, 0 ));//作者备注:cvKMeans2返回值为迭代次数?用户手册里面的意思应该是返回体现各个类别与类中心的差别的 compactness量度吧
    66 67 cvZero( img ); 68 69 for( i = 0; i < sample_count; i++ ) 70 { 71 int cluster_idx = clusters->data.i[i]; 72 ipt.x = (int)points->data.fl[i*2]; 73 ipt.y = (int)points->data.fl[i*2+1]; 74 cvCircle( img, ipt, 2, color_tab[cluster_idx], CV_FILLED, CV_AA, 0 ); 75 } 76 77 cvReleaseMat( &points ); 78 cvReleaseMat( &clusters ); 79 80 cvShowImage( "clusters", img ); 81 82 key = (char) cvWaitKey(0); 83 if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC' 84 break; 85 } 86 87 cvDestroyWindow( "clusters" ); 88 return 0; 89 } 90 91 #ifdef _EiC 92 main(1,"kmeans.c"); 93 #endif

    另外,关于KMeans与SIFT算子的一个结合应用,有一个很好的帖子就是参考[2]中的内容。

    此处为了说明其对KMeans使用的理解,将其第四部分step2内容备份于此。

    Step2——Kmeans应用

      Step1里面的feature只是“预备单词”,在成为单词之前还要通过Step2生成“单词表”和Step3将“文档”中的“预备单词”找到“单词表”中最相近的“单词”替换之(并不是真正操作上的替换,只是当成“单词表”中的“单词”统计出来而已)。

      在Step2中,关键操作如下:

        

    ...
    CvMat *samples=cvCreateMat(featureNum, dims, CV_32FC1); //包含所有图片的所有feature信息的矩阵,featureNum个feature,每个feature为dims(128)维向量,每一维的元素类型为32位浮点数
    CvMat *clusters=cvCreateMat(featureNum, 1, CV_32SC1); //每个feature所在“质心”的指针(实际上本例程中没有用到该信息)
    CvMat *centers=cvCreateMat(k, dims, CV_32FC1); //“质心”信息的数组,k个“质心”每个质心都是dims(128)维向量,每一维的元素类型为32位浮点数
    cvSetZero(clusters); //将矩阵初始化为0
    cvSetZero(centers); //将矩阵初始化为0
    while(file.ReadString(strLine)) 
    {
        ...
        n = import_features(CIni::CStrToChar(fileName), FEATURE_LOWE, &features); //导入feature文件,n为导入的feature个数
        ...
        //将feature文件内所有feature信息存入samples矩阵结构内
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < dims; j++)
            {
                samples->data.fl[temp++] = features[i].descr[j];
            }
        }
    }
    cvKMeans2(samples, k, clusters,cvTermCriteria(CV_TERMCRIT_EPS,10,1.0), 3, (CvRNG *)0, KMEANS_USE_INITIAL_LABELS, centers); //Kmeans聚类
    ...
    cvSave(CIni::CStrToChar(ini.getWordListFilePath()), centers); //保存单词表
    ...
    

     其中关键函数当然是import_features(...)和cvKMeans2(...),前者是sift源码里的方法,用来导入feature文件使之成为内存数据结构,后者是Opencv里的kmeans算法之一(cvKMeans2(...)内部调用了kmeans(...))。

    Reference

    [1]聚类算法——K-means(下) http://www.cnblogs.com/moondark/archive/2012/03/08/2385870.html

    [2]基于SIFT+Kmeans+LDA的图片分类器的实现 http://www.cnblogs.com/freedomshe/archive/2012/04/24/2468747.html

  • 相关阅读:
    'Undefined symbols for architecture i386,clang: error: linker command failed with exit code 1
    The codesign tool requires there only be one 解决办法
    XCode iOS project only shows “My Mac 64bit” but not simulator or device
    Provisioning profile XXXX can't be found 的解决办法
    UIView 中的控件事件穿透 Passthrough 的实现
    Xcode4.5出现时的OC新语法
    xcode 快捷键(持续更新)
    打越狱包
    php缓存与加速分析与汇总
    浏览器的判断
  • 原文地址:https://www.cnblogs.com/jiayouwyhit/p/3670357.html
Copyright © 2011-2022 走看看