2

I have a binary image (black and white pixels), and I'd like to cluster the white pixels into groups (objects), depending on the distance to each other, and retrieve the centroid of each cluster.

This is an example image in which I have to work on:

Image

(frame on purple)

I'd like to check if a clustering approach would provide the results I am looking for, which means that I'm trying to avoid implementing an algorithm myself before knowing it will be worth it.
Does OpenCV have a method to do what I need?

1
  • besides k-means, ISODATA clustering will be more suitable Commented Sep 21, 2020 at 10:05

2 Answers 2

2

I know this is quite old, but maybe this answer could be helpful.


You can use partition, which will split an element set into equivalency classes.

You can define an equivalence class as all points within a given euclidean distance. This can be either a lambda function (C++11) or a functor (see both examples in the code).

Starting from this image (I removed purple border manually):

enter image description here

using an euclidean distance of 20 I got:

enter image description here

You can see that all white pixels that are within the euclidean distance are assigned to the same cluster (same color). The circles denotes the centroids for each cluster.

Code:

#include <opencv2\opencv.hpp> #include <vector> #include <algorithm> using namespace std; using namespace cv; struct EuclideanDistanceFunctor { int _dist2; EuclideanDistanceFunctor(int dist) : _dist2(dist*dist) {} bool operator()(const Point& lhs, const Point& rhs) const { return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < _dist2; } }; int main() { // Load the image (grayscale) Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); // Get all non black points vector<Point> pts; findNonZero(img, pts); // Define the distance between clusters int euclidean_distance = 20; // Apply partition // All pixels within the the given distance will belong to the same cluster vector<int> labels; // With functor //int n_labels = partition(pts, labels, EuclideanDistanceFunctor(euclidean_distance)); // With lambda function int th2 = euclidean_distance * euclidean_distance; int n_labels = partition(pts, labels, [th2](const Point& lhs, const Point& rhs) { return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < th2; }); // Store all points in same cluster, and compute centroids vector<vector<Point>> clusters(n_labels); vector<Point> centroids(n_labels, Point(0,0)); for (int i = 0; i < pts.size(); ++i) { clusters[labels[i]].push_back(pts[i]); centroids[labels[i]] += pts[i]; } for (int i = 0; i < n_labels; ++i) { centroids[i].x /= clusters[i].size(); centroids[i].y /= clusters[i].size(); } // Draw results // Build a vector of random color, one for each class (label) vector<Vec3b> colors; for (int i = 0; i < n_labels; ++i) { colors.push_back(Vec3b(rand() & 255, rand() & 255, rand() & 255)); } // Draw the points Mat3b res(img.rows, img.cols, Vec3b(0, 0, 0)); for (int i = 0; i < pts.size(); ++i) { res(pts[i]) = colors[labels[i]]; } // Draw centroids for (int i = 0; i < n_labels; ++i) { circle(res, centroids[i], 3, Scalar(colors[i][0], colors[i][1], colors[i][2]), CV_FILLED); circle(res, centroids[i], 6, Scalar(255 - colors[i][0], 255 - colors[i][1], 255 - colors[i][2])); } imshow("Clusters", res); waitKey(); return 0; } 
Sign up to request clarification or add additional context in comments.

Comments

0

If you know the number of clusters in the image, you could use the K-Means algorithm, which is implemented in OpenCV.

Besides that, i do not know any other easy solution for this task. If you like to implement this clustering yourself, this paper could help you, it is about an adaption of the k-means which must not have a fixed number of clusters.

1 Comment

The number of clusters may vary and there is no way to know beforehand how many they are. Yes, I guess i'll have to implement something myself

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.