Nested Regions Isolation

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
alexanderz
Posts: 4
Joined: 2017-01-04T09:31:46-07:00
Authentication code: 1151

Nested Regions Isolation

Post by alexanderz »

Hi,

I have a set of satellite footprint images like this:
Image

I need to isolate each nested region as a separate image:
Image

One way to do this would be to use 'convert src.png -threshold [1%-100%] dest.png' creating a hundred files and removing visually similar images.

I was thinking if there was a way to:
- automatically detect the number of shades the image has
- execute threshold exactly the desired number of times with the right threshold value

Both of these steps are a bit tricky. Does anyone has a better idea?
Thanks
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Nested Regions Isolation

Post by fmw42 »

You can find the peaks in the histogram and threshold half way between them

Code: Select all

convert 143.png -format "%c" histogram:info:
or visually using

Code: Select all

convert 143.png histogram:hist.png
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Nested Regions Isolation

Post by fmw42 »

You can also use connected components to make the colors a small unique set, since your image has thousands of colors. See http://magick.imagemagick.org/script/co ... onents.php

Code: Select all

convert 143.png \
-define connected-components:verbose=true \
-connected-components 8 \
null:

Code: Select all

Objects (id: bounding-box centroid area mean-color):
  0: 800x800+0+0 349.2,420.7 494667 graya(255,1)
  31: 313x357+420+72 578.4,202.9 49630 graya(55,1)
  1040: 144x194+504+221 576.5,302.7 13546 graya(49,1)
  869: 342x252+401+193 550.9,317.9 13268 graya(70,1)
  4948: 354x113+388+446 581.3,516.3 11492 graya(239,1)
  4077: 358x116+387+411 573.5,481.3 9070 graya(224,1)
  1441: 352x194+393+265 551.4,365.9 8545 graya(106,1)
  3311: 360x128+387+377 565.6,451.1 7918 graya(207,1)
  2080: 359x165+388+309 559.2,398.0 7852 graya(139,1)
  1746: 91x110+529+287 573.6,341.9 7731 graya(37,1)
  2673: 359x143+387+346 565.5,425.7 7436 graya(172,1)
  3455: 1x29+746+382 746.0,396.0 29 graya(170,1)
  3456: 1x28+747+382 747.0,395.5 28 graya(202,1)
  4317: 19x19+662+419 671.0,428.0 19 graya(144,1)
  4303: 18x18+451+419 459.5,427.5 18 graya(173,1)
  6548: 18x1+572+505 580.5,505.0 18 graya(210,1)
  4342: 18x18+663+420 671.5,428.5 18 graya(164,1)
  6563: 18x1+572+506 580.5,506.0 18 graya(223,1)
  6829: 18x1+582+527 590.5,527.0 18 graya(234,1)
  4327: 17x17+451+420 459.0,428.0 17 graya(191,1)
  4076: 1x17+386+411 386.0,419.0 17 graya(227,1)
  3285: 1x16+385+376 385.0,383.5 16 graya(248,1)
  3712: 1x16+386+393 386.0,400.5 16 graya(206,1)
  4075: 1x16+385+411 385.0,418.5 16 graya(250,1)
  ...
But you can see a big change in the area between id 2673 and 3455. So if you pick the area 7436, you can merge all the smaller areas into the larger ones so that you can have an image with a small fixed number of graylevels.

Code: Select all

convert 143.png \
-define connected-components:area-threshold=7436 \
-define connected-components:verbose=true \
-define connected-components:mean-color=true \
-connected-components 8 \
143b.png

Code: Select all

Objects (id: bounding-box centroid area mean-color):
  0: 800x800+0+0 349.9,420.2 496464 graya(255,1)
  31: 313x357+420+72 578.6,204.6 50855 graya(55,1)
  869: 343x253+400+193 552.6,320.2 14215 graya(70,1)
  1040: 144x194+504+221 576.5,303.9 14047 graya(49,1)
  4948: 354x113+388+446 581.1,516.7 11952 graya(239,1)
  4077: 359x116+387+411 573.5,481.7 9638 graya(224,1)
  1441: 354x195+392+265 553.0,367.9 9436 graya(106,1)
  2080: 359x167+388+308 560.3,399.6 8679 graya(139,1)
  3311: 361x129+386+377 565.9,451.9 8572 graya(207,1)
  2673: 360x145+387+346 565.4,426.9 8262 graya(172,1)
  1746: 92x110+529+287 573.7,342.0 7880 graya(37,1)
So image 143b.png has only 12 different graylevels and you can threshold to isolate those.
alexanderz
Posts: 4
Joined: 2017-01-04T09:31:46-07:00
Authentication code: 1151

Re: Nested Regions Isolation

Post by alexanderz »

Thank you so much for the effort answering my question. The second method looks promising.

Though I'm not sure if I can automate the process for many images.

Just another quick question. How do I calculate the right threshold % values according to the objects' data?
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Nested Regions Isolation

Post by fmw42 »

Here is another way. Unix syntax and scripting. Please always provide your IM version and platform, since syntax may vary especially for scripting.

Code: Select all

convert 143.png -alpha off \
-define connected-components:verbose=true \
-connected-components 8 \
null:
The above makes the following list:

Code: Select all

Objects (id: bounding-box centroid area mean-color):
  0: 800x800+0+0 349.2,420.7 494667 gray(255)
  31: 313x357+420+72 578.4,202.9 49630 gray(55)
  1040: 144x194+504+221 576.5,302.7 13546 gray(49)
  869: 342x252+401+193 550.9,317.9 13268 gray(70)
  4948: 354x113+388+446 581.3,516.3 11492 gray(239)
  4077: 358x116+387+411 573.5,481.3 9070 gray(224)
  1441: 352x194+393+265 551.4,365.9 8545 gray(106)
  3311: 360x128+387+377 565.6,451.1 7918 gray(207)
  2080: 359x165+388+309 559.2,398.0 7852 gray(139)
  1746: 91x110+529+287 573.6,341.9 7731 gray(37)
  2673: 359x143+387+346 565.5,425.7 7436 gray(172)
  3455: 1x29+746+382 746.0,396.0 29 gray(170)
  ...

Then pick the threshold (7436). You may have to script more here to automate it by stepping along each row and finding where there is a large jump in area. Any way for now just pick it manually.

The following puts all the graylevels for areas 7436 and above in an array.

Code: Select all

arr=(`convert 143.png -alpha off \
-define connected-components:area-threshold=7436 \
-define connected-components:verbose=true \
-define connected-components:mean-color=true \
-connected-components 8 \
143b.png |\
tail -n +2 | sed -n 's/^.*gray[(]\(.*\)[)]$/\1/p'`)

num=${#arr[*]}
Then sort the array

Code: Select all

sortarr=(`echo ${arr[*]} | tr " " "\012" | sort -n | tr "\012" " "`)
Now loop over each graylevel and threshold the image.

Code: Select all

for ((i=0; i<num; i++)); do
val=`echo ${sortarr[$i]}`
pct=`convert xc: -format "%[fx:100*($val+1)/255]" info:`
ii=`printf %02d $i`
echo "$i, $ii, $val, $pct"
convert 143b.png -threshold $pct% 143b_$ii.png
done
You will now have one image per each graylevel and below as black and the rest white.
alexanderz
Posts: 4
Joined: 2017-01-04T09:31:46-07:00
Authentication code: 1151

Re: Nested Regions Isolation

Post by alexanderz »

Again, appreciate your detailed answer. I'm on a Mac, ImageMagick 6.9.7-2. Everything above worked perfectly, though it took me some time to figure out how the shell script works. I think I'm going to focus on finding the largest jump in area, sounds like a classic programming challenge, but that's beyond the scope of this forum. Thanks again!

P.S. if only I may ask for a link that explains this gray level to percentage conversion:

Code: Select all

pct=`convert xc: -format "%[fx:100*($val+1)/255]" info:`
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Nested Regions Isolation

Post by fmw42 »

It is simply using the IM fx calculator. I divide the value (in the range 0 to 255) by 255 and multiply by 100 to get percent. But the IM threshold needs a slightly larger values to get your regions properly. So I added 1 to the value before converting to percent as a quick an dirty way to fix it. It seemed to work.
alexanderz
Posts: 4
Joined: 2017-01-04T09:31:46-07:00
Authentication code: 1151

Re: Nested Regions Isolation

Post by alexanderz »

Great, my task was accomplished.
Also you inspired my to learn more about UNIX scripts. Here is how I decided to go with the percentage calculation:

Code: Select all

sortarr=(`echo ${arr[*]} | tr " " "\012" | sort -n -r | uniq | tr "\012" " "`)
shades=(`echo ${sortarr[*]} | tr " " "\012" | awk '{s=100*($1+1)/255; printf "%3.0f\n", s}' | uniq | tr "\012" " "`)
This gives me the possibility to further remove similar shades and avoid regions duplication. Again, I can't be thankful enough :)
Post Reply