Ask Your Question
1

KMeans Clustering for vector<Point2f> Data Structure

asked Jul 10 '14

IlSc gravatar image

updated Jul 10 '14

berak gravatar image

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?

Preview: (hide)

Comments

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

berak gravatar imageberak (Jul 10 '14)edit

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?

IlSc gravatar imageIlSc (Jul 10 '14)edit

ah, second. that needs a real answer now.

berak gravatar imageberak (Jul 10 '14)edit

1 answer

Sort by » oldest newest most voted
3

answered Jul 10 '14

berak gravatar image

updated Jul 10 '14

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 );
Preview: (hide)

Comments

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 gravatar imageGuanta (Jul 10 '14)edit

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

berak gravatar imageberak (Jul 10 '14)edit

@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?

Guanta gravatar imageGuanta (Jul 10 '14)edit

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 gravatar imageberak (Jul 10 '14)edit

@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...)

Guanta gravatar imageGuanta (Jul 10 '14)edit

^^ 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 gravatar imageberak (Jul 10 '14)edit

@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[0]));

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;

Guanta gravatar imageGuanta (Jul 10 '14)edit

Output:

---
1 3 2
[3, 4]
---
2 3 1
[3, 4]
---
3 2 1
[3, 4]
Guanta gravatar imageGuanta (Jul 10 '14)edit

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.

berak gravatar imageberak (Jul 10 '14)edit

cool link!

Guanta gravatar imageGuanta (Jul 10 '14)edit

Question Tools

Stats

Asked: Jul 10 '14

Seen: 3,479 times

Last updated: Jul 10 '14