Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ImageMagick and segmenting contiguous islands in a transparent background image

Tags:

imagemagick

I'm trying to convert something that looks like this into a bunch of smaller image crops or "slices", where each slice might overlap with another, but should contain each island of non-transparent pixels. The long continuous strokes don't have to be converted, but most of the "spots" should be.

enter image description here

So effectively, I'm trying to automatically "slice" it to look some thing like this (rough manual slicing):

enter image description here

How do you use imagemagick to automatically crop the elements of such an image, and to also return the position, width/height that each sub-image was cropped from?

like image 725
ina Avatar asked Oct 22 '25 04:10

ina


1 Answers

You can use "Connect Component Analysis". As your image contains no transparency it is hard to use, so I hacked it and coarsely made the chessboard areas transparent like this:

enter image description here

Then do something along these lines:

magick image.png  -alpha off -colorspace gray -negate -threshold 10%  \
   -define connected-components:verbose=true                          \
   -define connected-components:area-threshold=100                    \
   -connected-components 8 -auto-level output.png

Sample Output

Objects (id: bounding-box centroid area mean-color):
  1: 498x614+0+0 236.9,317.2 219166 srgb(0,0,0)
  2: 112x583+112+0 177.0,268.6 16094 srgb(255,255,255)
  27: 128x210+350+342 403.8,436.5 14195 srgb(255,255,255)
  7: 104x148+338+85 390.0,160.4 10451 srgb(255,255,255)       <--- this one
  3: 103x145+200+0 250.9,70.9 10317 srgb(255,255,255)
  25: 107x132+202+245 252.7,307.8 9227 srgb(255,255,255)
  36: 117x139+213+428 268.3,497.2 9103 srgb(255,255,255)
  12: 139x77+0+112 62.1,152.4 7162 srgb(255,255,255)
  16: 73x93+414+161 459.0,213.4 4104 srgb(255,255,255)
  37: 51x61+249+457 274.6,488.1 2224 srgb(0,0,0)
  4: 71x36+338+0 382.0,19.6 1507 srgb(255,255,255)
  26: 32x47+238+277 253.1,300.2 875 srgb(0,0,0)
  43: 50x30+283+584 310.7,600.0 833 srgb(255,255,255)
  13: 41x17+31+140 51.0,148.1 410 srgb(0,0,0)
  9: 11x11+174+100 178.7,105.3 104 srgb(255,255,255)

Each line of output corresponds to a blob. There is a header at the start that tells you what each field is.

Let's look at the line:

  7: 104x148+338+85 390.0,160.4 10451 srgb(255,255,255)

and draw that blob into your image in semi-transparent red:

magick image.png -fill "rgba(255,0,0,0.5)" -draw "rectangle 338,85 442,243" result.png

enter image description here


Note that I have actually discarded the alpha channel (with -alpha off) in my command and used the RGB channels converted to greyscale as items to detect. Depending how your image is created, you may be better of discarding the RGB channels and just using the alpha or its inverse (-alpha extract -negate).

like image 59
Mark Setchell Avatar answered Oct 24 '25 16:10

Mark Setchell