# KMeans Clustering for vector<Point2f> Data Structure

I notice that KMeans Clustering in OpenCV is reserved for the Mat data Structures. However, I need to do some clustering for a vector og Point2f. What should I do?

edit retag close merge delete

vector<Point2f> points; kmeans(Mat(points),...); // just wrap it into a Mat

Since the output of the method is also in Mat data structures, is it possible to wrap it to the vector<Point2f> data structure as well?

Sort by » oldest newest most voted

there you go..

vector<Point2f> points;
points.push_back(Point2f(1,1));
points.push_back(Point2f(3,1));
points.push_back(Point2f(1,5));
points.push_back(Point2f(2,5));

Mat labels,centers;
int K=2, attempts=3, flags=cv::KMEANS_RANDOM_CENTERS; // hey, just guessing here
TermCriteria tc;

kmeans(points,K,labels,tc,attempts,flags, centers);   // points will get cast implicitly to Mat

for ( int i=0; i<labels.rows; i++ )
{
int idx = labels.at<int>(i);
Point2f original_point = points[i];
Point2f clustered_center;
clustered_center.x = centers.at<float>( idx,0 );
clustered_center.y = centers.at<float>( idx,1 );
cerr << i << " " << idx << " " << original_point << " " << clustered_center << endl;
}


0 1 [1, 1] [2, 1]
1 1 [3, 1] [2, 1]
2 0 [1, 5] [1.5, 5]
3 0 [2, 5] [1.5, 5]


you could also make the centers a Mat of Point2f again:

    Mat centers_point = centers.reshape(2,centers.rows);
...
clustered_center = centers_point.at<Point2f>( idx );

more

1

@IlSc: In a real scenario, one should use KMEANS_PP_CENTERS instead of KMEANS_RANDOM_CENTERS (and maybe more attempts).

@berak: Maybe Mat_<cv::Vec2f> would have worked?

@Guanta, like Mat_<Vec2f> centers; ? crashes in kmeans while copying.

@berak: thought of clustered_cetner = centers.at<cv::Vec2f>(idx) , since you commented that cv::Point2f doesnt work here, however I don't know if this works either, or did you mean sth else?

Mat(vector<Point2f>) gets wrapped to a Mat(npoints,2,CV_32F), and the resulting centers are a Mat(nclusters,2, CV_32F) . imho, there's no way to access it as either at<Point2f>() or at<Vec2f>() without the reshape() (but please, prove me wrong here ;)

@berak: hm, for me both variants work, but maybe I missunderstood you again:

cv::Point2f a(1,2);
cv::Point2f b(3,4);


std::vector<cv::Point2f > t;

t.push_back(a);
t.push_back(b);
cv::Mat tt(t);


std::cerr << tt.at<cv::Vec2f>(0) << std::endl;

std::cerr << tt.at<cv::Vec2f>(1) << std::endl;

std::cerr << tt.at<cv::Point2f>(0) << std::endl;

std::cerr << tt.at<cv::Point2f>(1) << std::endl;

(grml how do I add '<'/'>' in code, always the same...)

^^ true, that works. your tt is a Mat(2,1,CV_32FC2)

unfortunately, the centers are Mat(K,2,CV_32F), so let's reshape your example:

Mat t2 = tt.reshape(1,tt.rows);

tt.at<Point2f>(0); // fine

t2.at<Point2f>(0); // have a good laugh at the errormsg ;)

@berak: sry to disappoint you, but any of the following works for me (OpenCV 2.4.9):

cv::Point2f a(1,2), b(3,4), c(5,6);

static const cv::Point2f arr[] = {a, b, c};

std::vector<cv::Point2f> t(arr, arr+sizeof(arr)/sizeof(arr));

std::cerr << "---\n";

cv::Mat tt(t);

std::cerr << tt.cols << " " << tt.rows << " " << tt.channels() << std::endl;

std::cerr << tt.at<cv::Vec2f>(1) << std::endl;

std::cerr << "---\n";

cv::Mat t2 = tt.reshape(1, tt.rows);

std::cerr << t2.cols << " " << t2.rows << " " << t2.channels() << std::endl;

std::cerr << t2.at<cv::Point2f>(1) << std::endl;

std::cerr << "---\n";

cv::Mat t3 = tt.reshape(1, 2);

std::cerr << t3.cols << " " << t3.rows << " " << t3.channels() << std::endl;

std::cerr << t3.at<cv::Point2f>(1) << std::endl;

Output:

---
1 3 2
[3, 4]
---
2 3 1
[3, 4]
---
3 2 1
[3, 4]


wow, you're right

something must be broken here ...

hey, @Guanta, thanks for taking that challenge (though the results are alarming...)

just can't do it on my own box.

Official site

GitHub

Wiki

Documentation