IM really needs this feature

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
VanGog
Posts: 308
Joined: 2012-02-05T02:46:58-07:00
Authentication code: 8675308

IM really needs this feature

Post by VanGog »

The standard fuzz command which is used to calculate distance from specified color in RGB seems to be very limiting for my needs. It is very general. I want to achieve high performance when comparing high range of colors in HSL. In my case I am working with aerial photos of city, where I want to work only with certain areas defined by colors range in HSL. For example: a) shadows on routes and on buildings b) shadows on grass or trees (green shadows) c) select all routes or buildings with similar color

This threads explains what I was trying to do:
viewtopic.php?f=1&t=25660

Here I give simple example how the command to select shadows on routes could look:
example 1:

Code: Select all

convert -HSLRangeMin(197, 21, 29) -HSLRangeMax(222, 40, 33) ...  // checking one set of colors
or just
convert -HSLRange(197, 21, 29, 222, 40, 33) ... // checking one set of colors
or using multiple options:
convert -HSLRange(197, 21, 29, 222, 40, 33),(104, 8, 31, 216, 33, 46) ... // checking multiple sets of colors
or yet improved with fuzz:
convert -fuzz 4 -HSLRange(197, 21, 29, 222, 40, 33),(104, 8, 31, 216, 33, 46) ... // checking multiple sets of colors. You could have as many sets of colors as you want, but usually 1-3 could be enough
This would get very precise definition of colors ...

To type it in the programming way ...

Code: Select all

HSL_min1 = { H:197, S:21, L:29}; // meaning: ( color is in range of H>=197 && S>=21 && L >=29
HSL_max1 = { H:222, S:40, L:33}; // and H<=222 && S<=40 && L <=33 ) // dark shadows
// or
HSL_min2 = { H:104, S:8, L:31}; // ( color is in range of H>=104 && S>=8 && L >=31
HSL_max2 = { H:216, S:33, L:46}; // and H<=216 && S<=33 && L <=46 ) // light shadows
// and so on ... 
The limitation of the fuzz is that you have to define huge numbers of colors with little fuzz if you want to be exact. In the HSL range way there are differences between the H S L components which standard fuzz command ignores. I did not find any compensation for this.

In addition I add here some example of code in PHP how I am used to work with colors in HSL. This is not exactly the same situation, but very similar, the example calculates average color from image and defines colors based on HSL/HSV module:
http://paste.ofcode.org/W8hFyRZmZHzNaJMriQwSWw
(The colors definition is yet more improved there. I can select how many componenst I am interested. I can look for colors based on Hue, Saturation or Lightness ... or combination of two of them.) PHP works differently then IM, but the essence is similar.
E.g. example of lips - create conditions to turn the red colors more dark

Code: Select all

$lessSingle = new less_exceptions('single',53,'s'); // I created exception for colors which means that colors which have saturation <=53 should be excluded from result...

$Interval_teeth = new interval_exceptions( 'three', array('ll'=>array(array(12,12,79)),'ul'=>array(array(13,17,83))) ); // ll - lower limit, ul - upper limit
$exceptionsToken = array($Interval_teeth,$lessSingle); // exceptionsToken keeps my exceptions (these colors wont be included in result - wont be effected

// The following are based on RGB but the core works with HSL/HSV model
// Also the exceptions are defined in HSL model. Just for html I use RGB model in HEX
$myColorsForAvarage = array( 'cc825f', 'f21a1a','9b5042', '933f31', 'ff9393', 'd09e9e');
$nextColorsForReplace = array('d0d0d0', '7a7a7a'); // this will be added to $myColorsForAvarage 
// Finally I use this to replace the colors: I pass all color limits and color exceptions
color_math::replaceColors($file,$myColorsForAvarage,$nextColorsForReplace,$exceptionsToken, $replaceColor, true);	
// So this is yet advanced example
PS: The example of PHP has some Czech comments
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: IM really needs this feature

Post by fmw42 »

HSL_min1 = { H:197, S:21, L:29}; // meaning: ( color is in range of H>=197 && S>=21 && L >=29
HSL_max1 = { H:222, S:40, L:33}; // and H<=222 && S<=40 && L <=33 ) // dark shadows
Assuming your // means comments, then your two commands make no sense. You have the same syntax, but in the first case it finds colors larger than specified and in the second case it finds colors less than specified. How can this be distinguished by the same syntax?

Nevertheless, I think you can do what you want with -fx. At least it will find all those colors and can be make to output a binary mask for later processing by -mask or using -compose

P.S. I see snibgo gave you the advice about how to use -fx in your post to the Users forum. Looks like he has given you a solution.
VanGog
Posts: 308
Joined: 2012-02-05T02:46:58-07:00
Authentication code: 8675308

Re: IM really needs this feature

Post by VanGog »

I used the code just as illustration.

I tried fx and it's slow like hell. I have big images. It is expected that the image will be at least 1500x1500 px or possibly 2000x2000 or more. I've read "Making IM Faster (in general)" here http://www.imagemagick.org/Usage/api/
Avoid using FX, The Special Effects Image Operator, if you can use Alpha Composition, or the simpler Evaluate, Simple Math Operations, or other techniques instead.

If you do need to use these, try restricting its use to the smallest image possible, or to a single channel of the image (when handling grayscale).
fmw42 wrote:P.S. I see snibgo gave you the advice about how to use -fx in your post to the Users forum. Looks like he has given you a solution.
Solution that doesn't work. I need high performance. Normally I use Photoshop to manually edit images. Photoshop can select the colors in the image which has 2000x2000px (which is relatively "small" image) within milliseconds. If IM does not do it it indicates, that something is wrong or missing. Notice that the definition of colors to create mask is just low grade command (the other jobs which should take more time have to come after the colors are defined). I expect that such simple thing like selection of colors, copy pixels to new layer, adjust levels and apply some special effect should be made within miliseconds (according Photoshop). Simply if it takes too long, it indicates, there is something wrong and should be improved, simplified or enhanced.
Last edited by VanGog on 2014-05-31T13:35:26-07:00, edited 1 time in total.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: IM really needs this feature

Post by fmw42 »

You are welcome to contribute code to IM. Or wait for a response from the IM development team, if they want to undertake this functionality.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: IM really needs this feature

Post by snibgo »

VanGog wrote:The standard fuzz command which is used to calculate distance from specified color in RGB ...
That is not correct.

Fuzz works with pixel values, whatever the colorspace. If you want to use fuzz in HSL, just convert to HSL before the operation, and convert back to sRGB after the operation.
snibgo's IM pages: im.snibgo.com
VanGog
Posts: 308
Joined: 2012-02-05T02:46:58-07:00
Authentication code: 8675308

Re: IM really needs this feature

Post by VanGog »

Exactly, that is what I am going to wait for. I am not C/C++ guru to make code contribution, only thing I can do is to give my recommendation.
VanGog
Posts: 308
Joined: 2012-02-05T02:46:58-07:00
Authentication code: 8675308

Re: IM really needs this feature

Post by VanGog »

If you want to use fuzz in HSL, just convert to HSL before the operation, and convert back to sRGB after the operation.
Hmm, but it still does not have the possibility to select exact values for different components. Am I wrong?
Last edited by VanGog on 2014-06-01T01:29:55-07:00, edited 1 time in total.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: IM really needs this feature

Post by snibgo »

VanGog wrote:Hmm, but it still does not have the possibility to select exact values for different components.
Correct.

Think of the 3 channels (RGB, HSL, Lab or anything) as coordinates of a 3-D cube, containing all possible colours. "-fuzz" defines the radius of a sphere. All colours inside the sphere are considered equal to the colour in the centre of the sphere, so the cutoff is on the circumference of the sphere.

If you want cutoffs at six planes within the cube, you could do this separately for each channel.
snibgo's IM pages: im.snibgo.com
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: IM really needs this feature

Post by fmw42 »

The solution is easy. Just use -fx to create a 1D binary lookup table from your ranges of allowed H,S,L. Then apply the lut using -clut to the HSL version of the image to make a binary mask. Then apply the mask using -mask with your image (HSL or RGB) to do what further processing you want to do.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: IM really needs this feature

Post by fmw42 »

Here is what I have in mind.

It takes little time with -fx to create a 1D lut of size say 360x1 or even 3600x1. Then use -clut to apply the lut to the HSL image, which makes it a mask. This takes little time also since it is a lookup table. The mask is then used to limit the processing only to those pixels that were selected by the -fx expression.

The fx expression is made for each channel H, S, L so you get 3 1D grayscale luts that are combined to make one color lut. This is applied to the HSL image to make a mask.

The fx expressions are just ranges of values (r>X && r<Y)?white:black, for the hue channel

You will have to scale the S and L channels by 360x255, if you are working with HSL color values as 0-360, 0-256, 0-255

So something like the following:

Code: Select all

fact=`convert xc: -format "%[fx:360/255]" info:`
convert -size 360x1 xc: -colorspace HSL -fx "(r>Xr && r<Yr)?white:black" redlut.png
convert -size 360x1 xc: -colorspace HSL -fx "(g>Xg*$fact && g<Yg*$fact)?white:black" greenlut.png
convert -size 360x1 xc: -colorspace HSL -fx "(b>Xb*$fact && b<Yb*$fact)?white:black" bluelut.png

convert redlut.png greenlut.png bluelut.png -combine lut.png

convert \( image -colorspace HSL \) lut.png -clut mask.png

convert image -mask mask.png <processing> result
You can make the expressions as complicated as you want.
VanGog
Posts: 308
Joined: 2012-02-05T02:46:58-07:00
Authentication code: 8675308

Re: IM really needs this feature

Post by VanGog »

snibgo wrote:Fuzz works with pixel values
What do you mean by pixel value? Do you mean RGB or any value colorspace value? It's not clear to me weather fuzz can work for HSL and if can I use it similar in the way of: convert -HSL -fuzz 15% HSL_values_here ... or even convert -HSL -fuzz 15% RGB_value_here ... in the second case it would be expected that the RGB will be converted to HSL... Also I didnt find out what does function hsl() which I have seen somewhere regarding IM.
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: IM really needs this feature

Post by magick »

Grab the source and look at magick/color.c/IsColorSimilar(). You'll find this code:

Code: Select all

  if ((image->colorspace == HCLColorspace) ||
      (image->colorspace == HSBColorspace) ||
      (image->colorspace == HSLColorspace) ||
      (image->colorspace == HWBColorspace))
    {
      /* This calculates a arc distance for hue.  Really it should be a vector
         angle of 'S'/'W' length with 'L'/'B' forming appropriate cones.  In
         other words this is a hack - Anthony
      */
      if (fabs((double) pixel) > (QuantumRange/2))
        pixel-=QuantumRange;
      pixel*=2;
    }
VanGog
Posts: 308
Joined: 2012-02-05T02:46:58-07:00
Authentication code: 8675308

Re: IM really needs this feature

Post by VanGog »

For me it's hard to understand the function. What are p and q? Is it color and fuzz? Why is there scale, what is it good for? What is quantum range? Is it the difference between two colors? Finally why is there scale*pixel*pixel ... why power?
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: IM really needs this feature

Post by snibgo »

VanGog wrote:
snibgo wrote:Fuzz works with pixel values
What do you mean by pixel value? Do you mean RGB or any value colorspace value?
Each pixel is recorded as some numbers or values, one number per channel, typically 3.

VanGog wrote:It's not clear to me weather fuzz can work for HSL and if can I use it similar in the way of:...
Yes, it can. For example:

Code: Select all

convert 20r45mo.jpg -colorspace HSL -fuzz 20% -fill Black -opaque #999933332222 -colorspace sRGB r.png
This converts the image to HSL, and converts pixels that have a value within 20% of #999933332222 to black. "#999933332222" is a hex number, with three values, being #9999, #3333 and #2222. As the image is HSL, the three numbers represent H, S and L.

But I think Fred's method using cluts gives what you ask for.
snibgo's IM pages: im.snibgo.com
VanGog
Posts: 308
Joined: 2012-02-05T02:46:58-07:00
Authentication code: 8675308

Re: IM really needs this feature

Post by VanGog »

But I think that the -fuzz is usable. When I can pass the HSL number in. I can use the average values, which I did not think about. But explain me how to convert the HSL numbers to HEX. My HSL values are H:0,581944444 S:0,305 L:0,31 .
Post Reply