Ask Your Question
2

Partition() - Finding the number of Clusters

asked 2015-08-17 10:00:40 -0600

Karthikeyan gravatar image

updated 2015-08-17 10:07:42 -0600

Hi all,

I am evaluating few of the openCV api's for my application, in the process I came through this Partition api. Basically I want to know the number of clusters in the part of image using this api. I have seen this link here explaining the usage, but I cant comprehend.

The thing is I want to find the cluster count in a image using partition api. For example, (for a image like this) I should get the cluster count return value from the Partition function as 6 since there area 6 different coloured clusters are there.

Any help could be really appreciated. Thanks in advance!

Find_ClusterCount_using_partition

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
5

answered 2015-08-18 00:14:33 -0600

berak gravatar image

updated 2015-08-18 04:11:48 -0600

if you want to partition color data, not points, ofc. you need to adapt the Distance function:

struct ColorDist {
    bool operator()(const Vec3b& a, const Vec3b &b) {
        return norm(a,b) < 65; // experimental value.
    }
};

// ----

Mat m=imread("part.bmp",1);
resize(m,m,Size(), 0.2, 0.2); // i'm in a hurry ;)
cerr << m.total() << " pixels." << endl;

// pack our pixels into a vector (better idea, anyone ?)
vector<Vec3f> data;
data.insert(data.begin(), m.begin<Vec3b>(), m.end<Vec3b>());

// partition labels:
vector<int> labels;
int k = partition(data, labels, ColorDist());
cerr << k << " clusters." << endl;

alternatively, you could just throw an integer representation of the pixel into a map, and count the uniques directly:

map<int,int> clusters2; // color as key, count as value
for (size_t i=0; i<m.total(); i++)
{
    Vec3b v = m.at<Vec3b>(i);
    int c = (v[0] << 16) | (v[1] << 8) | (v[2]);
    if (clusters2.find(c) != clusters2.end())
        clusters2[c] ++;
    else
        clusters2[c] = 0;
}
cerr << clusters2.size() << " clusters2." << endl;
// 26 clusters. 

// now, let's remove the small, noisy ones:
for (map<int,int>::iterator it=clusters2.begin(); it != clusters2.end(); )
{
    if (it->second < 50) // throw away all clusters < 50 elements
        it = clusters2.erase(it);
    else
        it++;
}
cerr << clusters2.size() << " clusters2." << endl;
// 6 clusters. ;)

the problem with both methods is, that your image seems to have come a long way. if you take a close look, you'll see a lot of grey, dithered (compression) artefacts around your shapes, which will be unique colors, too !

image description

edit flag offensive delete link more

Comments

2

Thanks a lot @berak!! As you suggested the code works very well in detecting the unique colours (including the artifacts) but still it depends on the predicate function as rightly mentioned. Very Thanks.!!

For the cluster count, the partition function itself returns an int value which would be suffice for now, I was not able to understand that part in your code both the methods. if possible tell a little bit about those part. Anyways thanks a lot for your help!

Karthikeyan gravatar imageKarthikeyan ( 2015-08-18 03:55:38 -0600 )edit
1

ah, sure, forgot, that it returns the count already. ;)

berak gravatar imageberak ( 2015-08-18 04:01:33 -0600 )edit
1

answered 2015-08-17 15:18:22 -0600

LBerger gravatar image

I use this message from @berak to build this program :

struct Dist {
    bool operator()(const Point& a, const Point &b) {
        return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y)) < 15;
    }
};
Mat m=imread("Downloads/kmeans.bmp",CV_LOAD_IMAGE_ANYCOLOR);
vector<Point> data;
for (int i = 0; i<m.rows; i++)
    for (int j = 0;j<m.cols; j++)
        if (m.at<Vec3b>(i,j)!=Vec3b(0,0,0))
            data.push_back(Point(j,i));
vector<int> labels;

partition(data, labels, Dist());
Mat cluster(m.rows,m.cols,CV_8UC1);
for (int i=0;i<data.size();i++)
    cluster.at<uchar>(data[i])=labels[i];
imwrite("label.bmp",cluster);

I must say that with your image it is much more efficiency to use canny or threshold

edit flag offensive delete link more

Comments

@LBerger: Thanks for your effort. Yes it is possible to use canny or threshold for this image. But in original scenario, real time images with different objects and textures would be the input. For now, I was interested in the partition api evaluation.

Karthikeyan gravatar imageKarthikeyan ( 2015-08-18 03:58:29 -0600 )edit

I haven't read last line of your post "there area 6 different coloured clusters are there."

LBerger gravatar imageLBerger ( 2015-08-18 10:18:25 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-08-17 10:00:40 -0600

Seen: 5,745 times

Last updated: Aug 18 '15