Below is a map of India (img).

enter image description here

and I can visualize it in the following way:

imgbin = Binarize@img;
MorphologicalComponents[imgbin] // Colorize

and the result is:

enter image description here

Edit

Following a manual approach, I can isolate the small components:

sc = SelectComponents[imgbin, #Count < 60 &];

However, this gives me

enter image description here

Now I find the coordinates of the centroids:

centroids = ComponentMeasurements[sc, "Centroid"];

This gives me

{1 -> {523.425, 182.274}, 2 -> {545.125, 182.563}, 3 -> {521.089, 154.518}, 
 4 -> {96.2778, 154.722}, 5 -> {101.5, 150.625}, 6 -> {285.375, 146.667}, 
 7 -> {111.7, 136.}, 8 -> {517.868, 133.947}, 9 -> {91.8846, 134.885}, 
 10 -> {99.3889, 135.167}, 11 -> {95.0882, 122.382}, 12 -> {531.136, 105.409}, 
 13 -> {535.5, 94.}, 14 -> {541.4, 92.6}, 15 -> {551.833, 93.8333}, 
 16 -> {540.333, 86.5833}, 17 -> {564., 63.5}, 18 -> {557.929, 61.5}, 
 19 -> {558.833, 55.8333}, 20 -> {567.5, 27.}, 21 -> {575.689, 20.3491}}

From this information, I think, the grouping can be done. I need to choose two thresholds for the X coordinates of the centroids. Manually, I can set the thresholds as 100 and 200. Then, the components having centroids with x < 100 will be grouped into one, the component having the centroid with 100 < x < 200 will be grouped into another one (this component should be discarded as it is already considered as a component earlier) and finally the components having centroids with x > 200 will be grouped into the second one.


However, I wish to group some of the components as shown below:

enter image description here

That is, the components inside the circle at the bottom left should be grouped into a single component and visualized with a single color and the components inside the ellipse at the bottom right should be grouped into another single component and visualized with another unique color while keeping the rest of the map unchanged.

How can I do so?

Edit 2: I can now group the components desired in a very manual way as follows:

scleft = SelectComponents[
  imgbin, #Count < 80 && #Centroid[[1]] < 130 &];
scright = 
 SelectComponents[imgbin, #Count < 80 && #Centroid[[1]] > 350 &];

and the components for the rest of the parts

mc = MorphologicalComponents[
  ImageSubtract[imgbin, ImageAdd[scleft, scright]]];

Now how can I join these components - scleft, scright and mc and get the desired result?

Edit 3: Both the answers by @kglr and @Chip Hurst are acceptable to me. However, I don't like the way they have colorized scleft and scright. I would prefer to append these two components into mc so that I can have all the components together and then visualize using simply Colorize.

  • What have you tried so far ? Understand your original attempts will help us get started in helping you. – user6014 Oct 12 at 13:43
  • @user6014 I am not sure. Maybe group them by the components' centroid coordinates. – Majis Oct 12 at 13:51
  • If you post code examples of your best attempt so far it will be a good starting point for someone to build off of and hopefully get you to the next step. – user6014 Oct 12 at 13:52
  • @user6014 see my edit. – Majis Oct 12 at 14:27
  • 2
    Majis, may i suggest you re-visit your previous questions and check if any of the answers is worth accepting? – kglr Oct 12 at 15:53
up vote 4 down vote accepted

A manual way (since OP has suggested that this question is not about clustering, more about how to deal with groups of labels) to do this would be to right click on the image, then get indices. Select the upper left corner and the bottom right corner of the bounding box of a group of components and then use ctrl+c to copy the indices. Paste it into the notebook. Do this for both groups. Then rearrange the indices for use in Part, in the following way:

img = Import["https://i.stack.imgur.com/6wQT9.jpg"];
comps = MorphologicalComponents[Binarize[img]];
comps[[492 ;; 549, 76 ;; 125]] = comps[[492 ;; 549, 76 ;; 125]] /. Except[0, _Integer] -> 1000;
comps[[459 ;; 648, 498 ;; 593]] = comps[[459 ;; 648, 498 ;; 593]] /. Except[0, _Integer] -> 1001;
comps = ArrayComponents[comps];
Colorize[comps]

Mathematica graphics

This code works also without ArrayComponents. What ArrayComponents does is that it reindexes the components so that they are consecutive integers rather than the 1000 and 1001 that we arbitrarily used in the code.

comps // Flatten // DeleteDuplicates

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, \ 19, 20, 21, 22, 23, 24, 25, 26, 27}

If I were to finish what OP started, I'd do it similarly:

binimg = Binarize[img];
scleft = SelectComponents[binimg, #Count < 80 && #Centroid[[1]] < 130 &];
scright = SelectComponents[binimg, #Count < 80 && #Centroid[[1]] > 350 &];
mc = MorphologicalComponents[ImageSubtract[binimg, ImageAdd[scleft, scright]]];
mc += 1000 ImageData[scleft];
mc += 1001 ImageData[scright];
Colorize[
 mc,
 ColorRules -> Join[
   Table[i -> Green, {i, 25}], {
    1000 -> Blue,
    1001 -> Red
    }]
 ]

Mathematica graphics

  • This is also a very good approach. However, I am having a problem with all the three answers. I don't want to colorize the map with the default color scheme. I have my own set of colors and I want to render the map with my colors. However, ColorFunction is not an option for Image. Is it possible to do so in any other way? – Majis Oct 12 at 21:13
  • @CE Secondly, I don't understand what are the purposes of using the values 1000 and 1001. Can you please explain this to me? – Majis Oct 12 at 21:16
  • @Majis The colors should be specified as an option to Colorize, not Image. Colorize accepts both ColorRules and ColorFunction. Those are arbitrary labels. We have to give them some labels, right? So we can give them the labels 235 and 367, or 10323023 and 29301490. It doesn't matter which, but they must be unique. For this particular image, since we have 25 other components, the label number must be larger than 25. – C. E. Oct 12 at 21:24
  • @CE This means I can use ColorRules or ColorFunction with Colorize. Yes, I understand that they are just labels. Then how can I use it to apply custom colors? – Majis Oct 12 at 21:35
  • @Majis I updated the last example to demonstrate this. Is it more understandable now? – C. E. Oct 12 at 21:46

Another idea is to dilate the image slightly to find 'connected' components.

img = Import["https://i.stack.imgur.com/6wQT9.jpg"];

mask = Binarize[Dilation[img, DiskMatrix[15]]];
comps = MorphologicalComponents[mask];

{chain2, chain1, mainland} = SortBy[Table[
  Binarize[img*Image[1 - Unitize[comps - i]]], {i, 3}], Total];

Colorize[MorphologicalComponents[mainland, CornerNeighbors -> False]] + 
  ImageMultiply[chain1, Green] + 
  ImageMultiply[chain2, Red]

enter image description here


Edit

To color the island chains from within Colorize:

mcomp = MorphologicalComponents[mainland, CornerNeighbors -> False];
max = Max[mcomp];

Colorize[mcomp + (max + 1)ImageData[chain1] + (max + 2)ImageData[chain2]]

enter image description here

  • It's not what I need. mc is a list of components while, scleft and scright are images. I want to convert scleft and scright into components and append them to mc and then apply Colorize[mc]. – Majis Oct 12 at 17:51
  • @Majis see my edit. – Chip Hurst Oct 12 at 18:12
  • Yes, Now this is very straightforward. Thanks a lot. – Majis Oct 12 at 18:40

Update 2: have all the components together and then visualize using simply Colorize:

Modify the MorphologicalComponents matrix to assign the same label to members of a cluster:

replace = Thread[Alternatives @@ # -> First[#]] & /@ clusters;
MorphologicalComponents[imgbin] /. replace // Colorize

enter image description here

Update:

clusters = FindClusters[#[[2, 1]] -> # & /@ 
  ComponentMeasurements[MorphologicalComponents[imgbin], 
    {"Centroid", "Count"}, #2 < 80 && (#[[1]] < 130 || #[[1]] > 350) &], 2][[All, All, 1]];

Colorize[MorphologicalComponents[imgbin], 
 ColorRules -> Join @@ (Thread /@ Thread[clusters -> {Red, Green}])]

enter image description here

Original answer:

clusters = FindClusters[#[[2, 1]] -> # & /@ 
   ComponentMeasurements[imgbin, {"Centroid", "Count"}, #2 < 65 &], 2][[All, All, 1]];
Colorize[MorphologicalComponents[imgbin], 
 ColorRules -> Join @@ (Thread /@ Thread[clusters -> {Red, Green}])]

enter image description here

Note: Need further refinement to exclude the red elements on the continent.

  • see my edit to the question. – Majis Oct 12 at 16:41
  • @Majis, please see the update. – kglr Oct 12 at 17:00
  • Thanks. This is exactly what I need. However, I am having a small problem. Do you really get the regions at the bottom right of the same color? When I run your code, I get the top 4 elements yellow. – Majis Oct 12 at 18:04
  • 1
    Don't worry, (#[[1]] < 130 || #[[1]] > 250) gives me the desired result. Thanks a lot. – Majis Oct 12 at 18:07

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.