Extracting pixels within a certain hue bracket

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
skunkuncle
Posts: 3
Joined: 2016-03-20T01:29:33-07:00
Authentication code: 1151

Extracting pixels within a certain hue bracket

Post by skunkuncle »

I would like to extract only pixels within a certain hue bracket - let's say within 15% of pure yellow - from an image.

My purpose is to separate post-its of different colors from a picture of a whiteboard.

Ideally it's shown here:

http://imgur.com/a/nXmkq

Where this Image is the original image and these

http://imgur.com/NTOEsfA

http://imgur.com/qxmg9Wx

http://imgur.com/euyG7jd

are the separated ones - which I've obtained by using the color selector in GIMP

I've tried separating the image by hue like this

Code: Select all

convert whited.jpg -colorspace HSL -channel Hue -separate -fill white -draw "color 0,0 floodfill"  hue.jpg
And then using levels as masks, but it always mixes up yellow and green post-its.

I'm comfortable with perl, so I am close to desperation - and converting the whole image, filtering in perl, and converting back. There surely must be a better way than that.

Thanks.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Extracting pixels within a certain hue bracket

Post by snibgo »

What image processing has already been done? Perhaps this was a photograph of a whiteboard. The lighting wasn't even, so the top was lighter than the bottom. This could be corrected, except that the background has been removed. Without that information, the job of separating the green from yellow postits is hard.

However, it isn't too bad. The yellow postits have the red channel values greater than the green channel values. The green postits have green channel greater than red channel. So subtracting these differentiates them. Windows BAT syntax.

Code: Select all

set SRC=0HDxdpj.jpg

%IM%convert ^
  %SRC% ^
  -channel RG ^
  -separate ^
  +channel ^
  -compose Mathematics -define "compose:args=0,-1,1,0.5" ^
  -composite ^
  m.png
m.png is grayscale. The postits with gray > 50% are yellow. The postits darker than 50% are green or blue.

In fact, blue postits are 23% to 29%, and green are 40% to 47%. So this also distinguishes blue from green; threshold at say 35%.
snibgo's IM pages: im.snibgo.com
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Extracting pixels within a certain hue bracket

Post by snibgo »

Distinguishing by just a hue channel isn't so clear.

Code: Select all

%IM%convert ^
  %SRC% ^
  -colorspace HCL ^
  -set colorspace sRGB ^
  -channel R -separate +channel ^
  h.png
h.png records hue on a grayscale. Yellow postits are 13% to 15%. Green postits are 18% to 26%. Blue postits are 58% to 59%. So they don't overlap, and could be thresholded at say 16% and 41%. But there is wide variation in the green postits, with only a small margin between yellow and green postits.
snibgo's IM pages: im.snibgo.com
skunkuncle
Posts: 3
Joined: 2016-03-20T01:29:33-07:00
Authentication code: 1151

Re: Extracting pixels within a certain hue bracket

Post by skunkuncle »

Thanks - following your hints and a bit of googling I ended up using the -fx option like this (unix syntax):

Code: Select all

convert "$1" -fuzz 15% -fill white -draw "color 0,0 floodfill" whited.jpg

convert whited.jpg -fx "(hue > 0.17 && hue < 0.28) && lightness < 0.9 ? black : white" \
	-morphology Erode  Octagon -morphology Dilate Octagon mask_green.jpg && \
	composite mask_green.jpg whited.jpg -compose Screen out_green.jpg &

convert whited.jpg -fx "(hue > 0.53 && hue < 0.60) && lightness < 0.9 ? black : white" \
	-morphology Erode  Octagon -morphology Dilate Octagon mask_blue.jpg && \
	composite mask_blue.jpg whited.jpg -compose Screen out_blue.jpg &

convert whited.jpg -fx "(hue > 0.09 && hue < 0.16) && lightness < 0.9 ? black : white" \
	-morphology Erode Octagon  -morphology Dilate Octagon mask_yellow.jpg && \
	composite mask_yellow.jpg whited.jpg -compose Screen out_yellow.jpg &
It works OK, though it could stand some improvement.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Extracting pixels within a certain hue bracket

Post by fmw42 »

convert whited.jpg -fx "(hue > 0.17 && hue < 0.28) && lightness < 0.9 ? black : white" \
-morphology Erode Octagon -morphology Dilate Octagon mask_green.jpg && \
composite mask_green.jpg whited.jpg -compose Screen out_green.jpg
NOTE you can make this one command by using the convert -compose syntax so you do not have to save the mask_green.jpg to disk, nor read the whited.jpg image twice.

Code: Select all

convert whited.jpg \
\( -clone 0 -fx "(hue > 0.17 && hue < 0.28) && lightness < 0.9 ? black : white" \
-morphology Erode  Octagon -morphology Dilate Octagon \) \
-compose Screen -composite out_green.jpg
See http://www.imagemagick.org/Usage/compose/#compose
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Extracting pixels within a certain hue bracket

Post by snibgo »

skunkuncle wrote:It works OK, though it could stand some improvement.
You write intermediate results to JPG. JPG compression is lossy, which means it mangles pixels. As a rule of thumb, you should NEVER use JPG for intermediate results. Especially not when you a reducing images to flat colours, which JPG will mangle horribly.
snibgo's IM pages: im.snibgo.com
skunkuncle
Posts: 3
Joined: 2016-03-20T01:29:33-07:00
Authentication code: 1151

Re: Extracting pixels within a certain hue bracket

Post by skunkuncle »

Hi snibgo, hi fmw42 - thanks a lot!

I'd never used the "\(...\)" syntax - now I get it. Nice learning for me.

And yes, writing to JPG sucks, I shouldn't have! I'll fix it in the next version - today.

Thanks again to all.
Post Reply