我已经从openCV源代码分发的samples文件夹中读取了c ++示例,如果省略随机图片生成,kmeans调用看起来很简单 - 作者甚至不分配中心/标签数组(你可以找到它{{3 }})。但是,我不能在C中做同样的事。如果我没有分配标签,我会得到断言错误:
OpenCV错误:断言失败(labels.isContinuous()&& labels.type() == CV_32S&& (labels.cols == 1 || labels.rows == 1)&& cvKMeans2文件中的labels.cols + labels.rows - 1 == data.rows) /tmp/opencv-xiht/opencv-2.4.9/modules/core/src/matrix.cpp,第3094行
好的,我尝试创建空labels
矩阵,但断言消息根本没有变化。
IplImage* image = cvLoadImage("test.jpg", -1);
IplImage* normal = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, image->nChannels);
cvConvertScale(image, normal, 1/255.0, 0);
CvMat* points = cvCreateMat(image->width, image->height, CV_32F);
points->data.fl = normal->imageData;
CvMat* labels = cvCreateMat(1, points->cols, CV_32S);
CvMat* centers = NULL;
CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0);
// KMEANS_PP_CENTERS is undefined
int KMEANS_PP_CENTERS = 2;
cvKMeans2(points, 4, labels, criteria, 3, NULL, KMEANS_PP_CENTERS, centers, 0);
让我疯狂的事情:
CvMat* labels = cvCreateMat(1, points->cols, CV_32S);
int good = labels->type == CV_32S; // FALSE here
显然是一个(不确定是否唯一的)导致断言失败的问题。这应该怎么样?我不能使用С++ API,因为整个应用程序都在普通的C中。
答案 0 :(得分:2)
断言告诉你:
类型必须是CV_32S
,这似乎是您的代码中的情况,也许您的if语句为false,因为类型自动更改为CV_32SC1?不知道......
您可以将每个点放在一行或一列中,因此行/列is set to 1
和其他维度必须设置为data.rows
,表示data
保存要以每个点放在一行中的格式聚类的点,从而导致#points行。因此,您的错误似乎是CvMat* labels = cvCreateMat(1, points->cols, CV_32S);
而应该是CvMat* labels = cvCreateMat(1, points->rows, CV_32S);
,以使断言消失,但您对points
的使用似乎在概念上是错误的。
您可能必须在cvMat
n rows
和2 cols of type CV_32FC1
或1 col and type CV_32FC2
中保持您的积分(您希望群集)(可能两个版本都有效,也许只有一个,或者我可能在那里错了。)
编辑:我已经编写了一个适合我的简短代码段:
// here create the data array where your input points will be hold:
CvMat* points = cvCreateMat( numberOfPoints , 2 /* 2D points*/ , CV_32F);
// this is a float array of the
float* pointsDataPtr = points->data.fl;
// fill the mat:
for(unsigned int r=0; r<samples.size(); ++r)
{
pointsDataPtr[2*r] = samples.at(r).x; // this is the x coordinate of your r-th point
pointsDataPtr[2*r+1] = samples.at(r).y; // this is the y coordinate of your r-th point
}
// this is the data array for the labels, which will be the output of the method.
CvMat* labels = cvCreateMat(1, points->rows, CV_32S);
// this is the quit criteria, which I did neither check nor modify, just used your version here.
CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0);
// call the method for 2 cluster
cvKMeans2(points, 2, labels, criteria);
// now labels holds numberOfPoints labels which have either value 0 or 1 since we searched for 2 cluster
int* labelData = labels->data.i; // array to the labels
for(unsigned int r=0; r<samples.size(); ++r)
{
int labelOfPointR = labelData[r]; // this is the value of the label of point number r
// here I use c++ API to draw the points, do whatever else you want to do with the label information (in C API). I choose different color for different labels.
cv::Scalar outputColor;
switch(labelOfPointR)
{
case 0: outputColor = cv::Scalar(0,255,0); break;
case 1: outputColor = cv::Scalar(0,0,255); break;
default: outputColor = cv::Scalar(255,0,255); break; // this should never happen for 2 clusters...
}
cv::circle(outputMat, samples.at(r), 2, outputColor);
}
给我一些生成的点数据的结果:
也许您也需要这些中心,C API为您提供了返回它们的选项,但没有检查它是如何工作的。