zoukankan      html  css  js  c++  java
  • cvKMeans2接受Seq数据

    最近,开始学习openCV,准备用openCV来加强自己对图像处理和算法的理解与应用。

    下面是自己最近学习cvKMeans2时的一点经验——

    在《opencv基础》与《学习opencv》中介绍cvKMeans2时,都只说samples输入样例的浮点矩阵,每个样例一行。而在实际运用时,很多情况都是在运行时才知道样本的大小,并且会随时改变,那只有求助于CvSeq。研究cvKMeans的源码,如下:

     1 CV_IMPL int
     2 cvKMeans2( const CvArr* _samples, int cluster_count, CvArr* _labels,
     3            CvTermCriteria termcrit, int attempts, CvRNG*,
     4            int flags, CvArr* _centers, double* _compactness )
     5 {
     6     cv::Mat data = cv::cvarrToMat(_samples), labels = cv::cvarrToMat(_labels), centers;
     7     if( _centers )
     8         centers = cv::cvarrToMat(_centers);
     9     CV_Assert( labels.isContinuous() && labels.type() == CV_32S &&
    10         (labels.cols == 1 || labels.rows == 1) &&
    11         labels.cols + labels.rows - 1 == data.rows );
    12     double compactness = cv::kmeans(data, cluster_count, labels, termcrit, attempts,
    13                                     flags, _centers ? &centers : 0 );
    14     if( _compactness )
    15         *_compactness = compactness;
    16     return 1;
    17 }

    第6行中,用cv::cvarrToMat将_sample和_labels都转化成Mat,而cvarrToMat的源码如下:

     1 static inline Mat cvarrToMat(const CvArr* arr, bool copyData=false,
     2                              bool allowND=true, int coiMode=0)
     3 {
     4     if( CV_IS_MAT(arr) )
     5         return Mat((const CvMat*)arr, copyData );
     6     else if( CV_IS_IMAGE(arr) )
     7     {
     8         const IplImage* iplimg = (const IplImage*)arr;
     9         if( coiMode == 0 && iplimg->roi && iplimg->roi->coi > 0 )
    10             CV_Error(CV_BadCOI, "COI is not supported by the function");
    11         return Mat(iplimg, copyData);
    12     }
    13     else if( CV_IS_SEQ(arr) )
    14     {
    15         CvSeq* seq = (CvSeq*)arr;
    16         CV_Assert(seq->total > 0 && CV_ELEM_SIZE(seq->flags) == seq->elem_size);
    17         if(!copyData && seq->first->next == seq->first)
    18             return Mat(seq->total, 1, CV_MAT_TYPE(seq->flags), seq->first->data);
    19         Mat buf(seq->total, 1, CV_MAT_TYPE(seq->flags));
    20         cvCvtSeqToArray(seq, buf.data, CV_WHOLE_SEQ);
    21         return buf;
    22     }
    23     else
    24     {
    25         CvMat hdr, *cvmat = cvGetMat( arr, &hdr, 0, allowND ? 1 : 0 );
    26         if( cvmat )
    27             return Mat(cvmat, copyData);
    28     }
    29     return Mat();
    30 }

    其中,有对arr进行判断的,判断其是否为Mat,Image或者是Seq。我们先不管其是如何判断的,有这个判断在这,就说明cvKMeans2可以支持Seq数据,于是自己开始尝试写代码。

    以下是自己的代码:

     1 void test2() //有缺陷,运行到23行会出错。因为clusters中没有元素,故没有位置存放结果
     2 {
     3     int width=500,height=500;
     4     int sample_count=3;
     5     int cluster_count=2;
     6 
     7     CvScalar color_tab[2];
     8     color_tab[0] = CV_RGB(255,0,0);
     9     color_tab[1] = CV_RGB(0,255,0);
    10     
    11     CvMemStorage *memPoints=cvCreateMemStorage(0);
    12     CvMemStorage *memClu=cvCreateMemStorage(0);
    13 
    14     CvSeq *points=cvCreateSeq(CV_32SC2,sizeof(CvSeq),sizeof(CvPoint),memPoints);
    15     CvSeq *clusters=cvCreateSeq(CV_32SC1,sizeof(CvSeq),sizeof(int),memClu);
    16     CvSeqWriter writer; 
    17     cvStartAppendToSeq(points,&writer);
    18     CV_WRITE_SEQ_ELEM(cvPoint(10,20),writer);
    19     CV_WRITE_SEQ_ELEM(cvPoint(50,100),writer);
    20     CV_WRITE_SEQ_ELEM(cvPoint(100,50),writer);
    21     cvEndWriteSeq(&writer);
    22 
    23     cvKMeans2( points, cluster_count, clusters,
    24         cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 
    25         10, 0.1));
    26     IplImage *img=cvCreateImage(cvSize(width,height),8,3);
    27     cvZero( img );
    28     CvSeqReader readerPoints;
    29     CvSeqReader readerClu;
    30     cvStartReadSeq(points,&readerPoints,0);
    31     cvStartReadSeq(clusters,&readerClu,0);
    32 
    33     for (int i=0;i<sample_count;++i)
    34     {
    35         CvPoint2D32f point;
    36         int cl;
    37         CV_READ_SEQ_ELEM(point,readerPoints);
    38         CV_READ_SEQ_ELEM(cl,readerClu);
    39         cvCircle(img,cvPointFrom32f(point),2,color_tab[cl],CV_FILLED);
    40     }
    41  
    42     cvShowImage( "clusters", img );
    43     cvWaitKey(0);
    44 }

    运行,发现提示如下的错误:

    OpenCV Error: Assertion failed (seq->total > 0 && CV_ELEM_SIZE(seq->flags) == se
    q->elem_size) in unknown function, file c:\user\vp\ocv\opencv\include\opencv\cxm
    at.hpp, line 225

    打开源码,发现是cvarrToMat执行转化时,检测参数出错了。于是先检查了points,确定其没有问题;再看clusters,于是明白了,cvKMeans2不会为我们分配内存,clusters应该在函数调用前就用值进行填充,使其与points有一样的大小。于是有一如下的代码

     1 void test2()//有缺陷,points应该为浮点型的坐标
     2 {
     3     int width=500,height=500;
     4     int sample_count=3;
     5     int cluster_count=2;
     6 
     7     CvScalar color_tab[2];
     8     color_tab[0] = CV_RGB(255,0,0);
     9     color_tab[1] = CV_RGB(0,255,0);
    10     
    11     CvMemStorage *memPoints=cvCreateMemStorage(0);
    12     CvMemStorage *memClu=cvCreateMemStorage(0);
    13 
    14     CvSeq *points=cvCreateSeq(CV_32SC2,sizeof(CvSeq),sizeof(CvPoint),memPoints);
    15     CvSeq *clusters=cvCreateSeq(CV_32SC1,sizeof(CvSeq),sizeof(int),memClu);
    16     CvSeqWriter writer; 
    17     cvStartAppendToSeq(points,&writer);
    18     CV_WRITE_SEQ_ELEM(cvPoint(10,20),writer);
    19     CV_WRITE_SEQ_ELEM(cvPoint(50,100),writer);
    20     CV_WRITE_SEQ_ELEM(cvPoint(100,50),writer);
    21     cvEndWriteSeq(&writer);
    22 
    23     int i=0;
    24     cvStartAppendToSeq(clusters,&writer); //这里是新添加的,这里的i可以是随意值,只要添加一个占位即可
    25     CV_WRITE_SEQ_ELEM(i,writer);
    26     CV_WRITE_SEQ_ELEM(i,writer);
    27     CV_WRITE_SEQ_ELEM(i,writer);
    28     cvEndWriteSeq(&writer);
    29  
    30     cvKMeans2( points, cluster_count, clusters,
    31         cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 
    32         10, 0.1));
    33     IplImage *img=cvCreateImage(cvSize(width,height),8,3);
    34     cvZero( img );
    35     CvSeqReader readerPoints;
    36     CvSeqReader readerClu;
    37     cvStartReadSeq(points,&readerPoints,0);
    38     cvStartReadSeq(clusters,&readerClu,0);
    39 
    40     for (int i=0;i<sample_count;++i)
    41     {
    42         CvPoint2D32f point;
    43         int cl;
    44         CV_READ_SEQ_ELEM(point,readerPoints);
    45         CV_READ_SEQ_ELEM(cl,readerClu);
    46         cvCircle(img,cvPointFrom32f(point),2,color_tab[cl],CV_FILLED);
    47     }
    48  
    49     cvShowImage( "clusters", img );
    50     cvWaitKey(0);
    51 }

    运行,又提示如下错误

    OpenCV Error: Assertion failed (type == CV_32F && K > 0) in unknown function, fi
    le ..\..\..\..\ocv\opencv\src\cxcore\cxmatrix.cpp, line 860

    这次是在cv::kmeans函数中,points的类型不为CV_32F?? 哦~~  cvKMenas2只指定浮点数。故将points的构建代码改成如下所示:

      CvSeq *points=cvCreateSeq(CV_32FC2,sizeof(CvSeq),sizeof(CvPoint2D32f),memPoints);

    故最后的代码如下:

     1 void test2()
     2 {
     3     int width=500,height=500;
     4     int sample_count=3;
     5     int cluster_count=2;
     6 
     7     CvScalar color_tab[2];
     8     color_tab[0] = CV_RGB(255,0,0);
     9     color_tab[1] = CV_RGB(0,255,0);
    10     
    11     CvMemStorage *memPoints=cvCreateMemStorage(0);
    12     CvMemStorage *memClu=cvCreateMemStorage(0);
    13 
    14     CvSeq *points=cvCreateSeq(CV_32FC2,sizeof(CvSeq),sizeof(CvPoint2D32f),memPoints);
    15     CvSeq *clusters=cvCreateSeq(CV_32SC1,sizeof(CvSeq),sizeof(int),memClu);
    16     CvSeqWriter writer; 
    17     cvStartAppendToSeq(points,&writer);
    18     CV_WRITE_SEQ_ELEM(cvPoint2D32f(10,20),writer);
    19     CV_WRITE_SEQ_ELEM(cvPoint2D32f(50,100),writer);
    20     CV_WRITE_SEQ_ELEM(cvPoint2D32f(100,50),writer);
    21     cvEndWriteSeq(&writer);
    22 
    23     int i=0;
    24     cvStartAppendToSeq(clusters,&writer);
    25     CV_WRITE_SEQ_ELEM(i,writer);
    26     CV_WRITE_SEQ_ELEM(i,writer);
    27     CV_WRITE_SEQ_ELEM(i,writer);
    28     cvEndWriteSeq(&writer);
    29  
    30     cvKMeans2( points, cluster_count, clusters,
    31         cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 
    32         10, 0.1));
    33     IplImage *img=cvCreateImage(cvSize(width,height),8,3);
    34     cvZero( img );
    35     CvSeqReader readerPoints;
    36     CvSeqReader readerClu;
    37     cvStartReadSeq(points,&readerPoints,0);
    38     cvStartReadSeq(clusters,&readerClu,0);
    39 
    40     for (int i=0;i<sample_count;++i)
    41     {
    42         CvPoint2D32f point;
    43         int cl;
    44         CV_READ_SEQ_ELEM(point,readerPoints);
    45         CV_READ_SEQ_ELEM(cl,readerClu);
    46         cvCircle(img,cvPointFrom32f(point),2,color_tab[cl],CV_FILLED);
    47     }
    48  
    49     cvShowImage( "clusters", img );
    50     cvWaitKey(0);
    51 }

    上面的代码有内存泄漏,cvCreateImage出来的图像,应该用cvReleaseImage释放
    cvCreateMemStorage出来的内存,应该用ReleaseMenStorage释放。

  • 相关阅读:
    Java多线程问题
    pattern-matching as an expression without a prior match -scala
    从Zero到Hero,OpenAI重磅发布深度强化学习资源
    What-does-git-remote-and-origin-mean
    flink source code
    如何生成ExecutionGraph及物理执行图
    rocketmq 源码
    Flink source task 源码分析
    flink 获取上传的Jar源码
    fileupload
  • 原文地址:https://www.cnblogs.com/xiangism/p/2740937.html
Copyright © 2011-2022 走看看