Ask Your Question
1

KMeans Clustering for vector<Point2f> Data Structure

asked 2014-07-10 01:22:49 -0600

IlSc gravatar image

updated 2014-07-10 01:27:33 -0600

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?

edit retag flag offensive close merge delete

Comments

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

berak gravatar imageberak ( 2014-07-10 01:26:17 -0600 )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 ( 2014-07-10 01:36:03 -0600 )edit

ah, second. that needs a real answer now.

berak gravatar imageberak ( 2014-07-10 01:53:16 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
3

answered 2014-07-10 02:10:29 -0600

berak gravatar image

updated 2014-07-10 02:55:53 -0600

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 );
edit flag offensive delete link more

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 ( 2014-07-10 02:59:08 -0600 )edit

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

berak gravatar imageberak ( 2014-07-10 03:03:50 -0600 )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 ( 2014-07-10 04:04:00 -0600 )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 ( 2014-07-10 04:15:01 -0600 )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 ( 2014-07-10 05:10:13 -0600 )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 ( 2014-07-10 05:21:03 -0600 )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 ( 2014-07-10 07:35:23 -0600 )edit

Output:

---
1 3 2
[3, 4]
---
2 3 1
[3, 4]
---
3 2 1
[3, 4]
Guanta gravatar imageGuanta ( 2014-07-10 07:36:20 -0600 )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 ( 2014-07-10 08:01:51 -0600 )edit

cool link!

Guanta gravatar imageGuanta ( 2014-07-10 08:32:46 -0600 )edit

Question Tools

Stats

Asked: 2014-07-10 01:22:49 -0600

Seen: 3,170 times

Last updated: Jul 10 '14