# Clustering image data by intensity and position

I'd like to apply FindClusters or ClusteringComponents to image data of an indistinct edge, with the goal of segmenting the image into three categories (background, foreground, and border region).

This is an example of input image data:

This approach works fine for simple configurations, but I would like to take advantage of the form of my image data to get a clustering that reflects the distinctness of the edge. My code so far looks like this:

Module[{data = ClusteringComponents[image, 3, Method -> "KMeans"],
widths, label},
widths = Table[Count[data[[i]], 2], {i, Length[data]}];
label = "Avg. width = " <> ToString@N@Mean[widths];
GraphicsGrid[{{Colorize@data,
ListPlot[widths, Joined -> True, PlotMarkers -> {Red, 4},
PlotLabel -> label]}}]]


How can I specify a distance function that relates pixels by intensity and horizontal distance, but not vertical position?

Not very efficient, but here's a way. Let me know if it's more or less what you want and I may try to improve the performance.

i = Import["http://i.stack.imgur.com/CHoxa.png"];
pp = ImageData@i;
mi = Flatten[MapIndexed[{Sequence @@ #2, #1} &, pp, {2}], 1];
d = (ImageDimensions@i)[[1]];
flat = {1/d, 1} # & /@ mi[[All, 2 ;; 3]];
data = FindClusters[flat, 3];
c[i_, j_] := Position[data, {j/d , pp[[i, j]]}, 2][[1, 1]]
ss = SparseArray[{i_, j_} :> c[i, j], Dimensions@pp];
ss // Colorize


• +1 nice work, and a very interesting approach. It seems to work well, but might be hard to extend? If I've understood your method it seems the distance function is in some sense built into the ordering of the data, allowing you to get results applying FindClusters in the standard way? Oct 29, 2014 at 19:27
• @dionys In my experience, trying to use FindClusters[] with other than the default distance is computational prohibitive. So I managed to accommodate the data to the default distance Oct 29, 2014 at 19:34