Xiangism

从一个无知角落里开始,蹒跚学步,一个未知到另一个未知,在跌跌撞撞中越走越快,越走越远,最后宇宙也为之开源。对于探索者来说,最后他们的思想总是变得和自己的足迹一样伟大。
随笔 - 62, 文章 - 1, 评论 - 220, 阅读 - 20万
  博客园  :: 首页  :: 联系 :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

cvKMeans2接受Seq数据

Posted on   Xiangism  阅读(1665)  评论(0编辑  收藏  举报

最近,开始学习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释放。

复制代码
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示