Sort clusters using K-means by intensity

8 views (last 30 days)
Hello everyone. I am using K-means to segment some grayscale images. Unfortunately, the values of the generated clusters are not repeatable, i.e. every time I run the code the clusters have a different value. For example, if I use k=2 sometimes the darker areas of the original image have a cluster value of 1 and sometimes 2 (before normalisation). How to sort/order the generated clusters to have a value corresponding to the actual grayscale intensities, i.e. darkest = 1, less dark = 2,... brightest = k ? Thanks. Here is the code:
% Clustering.
clustered = reshape(kmeans(inputimage(:), k), size(inputimage));
% Normalise intensities from 0 to 1.
clustered = clustered - min(clustered(:));
clustered = clustered / max(clustered(:));

Accepted Answer

Walter Roberson
Walter Roberson on 29 May 2015
You are normalizing the indices, not by cluster intensities.
kidx = kmeans(inputimage(:), k);
clustermeans = accumarray(kidx, inputimage(kidx),[], @mean);
[sortedmeans, sortidx] = sort(clustermeans);
kidxmapped = sortidx(kidx);
clustered = reshape(kidxmapped, size(inputImage));
  9 Comments
Xen
Xen on 31 May 2015
Yeeess! I finally cracked this. I created a method to sort the clustermeans appropriately, and also had to use a different method to create clustermeans otherwise it kept failing. This is quite slow for large k values. If you have any suggestions for improvement I would be glad to know.
% Cluster.
clustered = reshape(kmeans(image(:), k), size(image));
% Sort clusters.
clustermeans = zeros(k, 1);
for j = 1:k
[row, col] = find(clustered == j);
pixelsKvalued = zeros(length(row), 1);
for l = 1:length(row)
pixelsKvalued(l) = image(row(l), col(l));
end
clustermeans(j) = mean(pixelsKvalued);
end
sortidx = zeros(k, 1);
for j = 1:k
sortidx(find(clustermeans == min(clustermeans))) = j;
clustermeans(clustermeans == min(clustermeans)) = NaN;
end
clustered = sortidx(clustered);
Xen
Xen on 31 May 2015
Edited: Xen on 31 May 2015
No need to estimate the mean of all pixels representing each cluster. Just a single pixel will do. Thanks Walter, this was inspired by your suggestions.
% Cluster.
clustered = reshape(kmeans(image(:), k), size(image));
% Sort clusters.
clusterintensity = zeros(k, 1);
for j = 1:k
clusterintensity(j) = image(find(clustered == j, 1));
end
clusteridx = zeros(k, 1);
for j = 1:k
clusteridx(find(clusterintensity == min(clusterintensity))) = j;
clusterintensity(clusterintensity == min(clusterintensity)) = NaN;
end
clustered = clusteridx(clustered);

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!