0

I'm having difficulty understanding what the labels and centres are in kmeans, specifically OpenCV's kmeans() function.

I understand that kmeans will find k clusters in a data sample. And that the centres parameter tells me the centre/centroid of each cluster.

But what are the labels and when I tried to inspect my centres it said I have 2 rows and 3 columns but I ran kmeans with 6 clusters - Shouldn't `centres' then have 6 rows (1 for each cluster)? Finally inspecting centres' values is outputting float values - shouldn't they be indexes (ints)? As in indexes of the data sample array.

How the heck can I get the cluster centres (in data coordinates) after running kmeans? Ultimately I'm trying to find the most common colours - so the cluster centres I assume would be BGR/HSV/Lab values depending on my Mat type?

kmeans(collapsedImage, 6, labels,
    TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0),
    3, KMEANS_PP_CENTERS, centres);


printf("rows: %d, cols: %d", centres.rows, centres.cols); 
// outputs 'rows : 2, cols : 3'

for (int i = 0; i < centres.rows; i++) {
    for (int j = 0; j < centres.cols; j++) {
        std::cout << centres.at<float>(i, j) << " ";
    }

    std::cout << std::endl;
}

// Outputs: Why are these floats???
// 1.48938 0.578623 0.464539
// 242.628 131.947 80.5347
sazr
  • 24,984
  • 66
  • 194
  • 362
  • 1
    Probably I already pointed you to [this](http://stackoverflow.com/a/34734939/5008845) and [this](http://stackoverflow.com/a/35482205/5008845). The second link is probably exactly what you're trying to do. However: 1) yeah, wierd. The rows should be 6. Maybe your images has only 2 colors? 2) `centres` contains the coordinates of the cluster centers. They are float. The rows in `centres` correspond to the integer values in `labels`. – Miki Aug 31 '16 at 11:33
  • @Miki can you expand on that last bit about the rows in centres corresponding to the integer values, maybe with an example? Maybe an example how to retrieve one cluster centre from `centres` – sazr Aug 31 '16 at 11:36
  • 1
    The input image size is `rows x cols x 3` (3 = color image). The data you feed to `kmeans` is `N x 3` (where `N = rows*cols`). The `labels` will be a matrix of indices (integer values) with size `Nx1` where each index has value in `0 <= index < K`, and `centres` is `Kx3` (3 = color image). So, each row in `label` is basically the linear index to a pixel location, and each index in `labels` corresponds to a cluster center, i.e. a row in `centres`. You can find in the first link I gave you how to recover the pixels new value according to `labels` and `centres` – Miki Aug 31 '16 at 11:45
  • @Miki thanks. And one last query, why are the centre values in floats? – sazr Aug 31 '16 at 12:00
  • @Miki never mind, I'm still wrapping my head around that colours can be represented by floats `Vec3f` and not just always ints `Vec3b` (and Scalar I think?) – sazr Aug 31 '16 at 12:09
  • 1
    Because its values are coordinates of points in a 3D space. I recommend to use always `Vec3b` for images. You can then convert to float and back if needed, such as in this case. The example I gave you shows also this conversion – Miki Aug 31 '16 at 12:10

1 Answers1

0

Ok so @Miki has explained what labels are and below solves how to get the cluster centres (I'm pretty sure this is correct):

printf("cols: %d, rows: %d", centres.cols, centres.rows);
int x = 0;
for (int i = 0; i < centres.rows; i++) {

    Vec3b s(centres.at<float>(i, 0), centres.at<float>(i, 1), centres.at<float>(i, 2));
    std::cout << "Dominant Colour (aka Cluster centre?): " << s << std::endl;

    rectangle(image, Rect(x, 10, 10, 10), s, 3, 0);
    x += 22;
}
sazr
  • 24,984
  • 66
  • 194
  • 362