[Gimp-developer] Incorrect Hue-Saturation results in obscure cases



(Apologies if this is a duplicate post; I tried sending it the other day but it didn't seem to go through)

I've found some obscure conditions under which the Hue-Saturation tool produces incorrect results up to and including current 2.8.0 .

The first one I encountered "in the wild" sometime in 2.6:  I had recently finished a pencil drawing and scanned it into an image file, but the "pink" areas of the drawing were not a warm enough shade for my preference.  At the time I felt the easiest method to fix this was via Hue-Saturation tool, so I went to the tool, slid the Overlap to 100%, then adjusted the Magenta hue by about +10º.  (I chose the Magenta range instead of Red because the image also contained colors in the red/orange region, and I didn't want them affected.)  Suddenly my pink pixels were now magenta and blue!  As if GIMP was calculating it around the wrong side of the HSV wheel, but that was apparently reported, patched and fixed four years ago (bug #527085) so the explanation can't be that simple.

I've also found another condition that, while it's so improbable a user might never encounter it in the wild, it is still incorrect:

- Adjust the Cyan channel hue by +100º ( -> Magenta/blue)
- Adjust the Blue channel hue by -100º ( -> Cyan/green)
- Set Overlap to 100%

So if a hue falls between Cyan and Blue ranges, it should get mapped to a Magenta -> Blue -> Cyan -> Green range, right?
But instead, GIMP maps them to a Magenta -> Red -> Yellow -> Green range; here it IS going the wrong way around the circle.

This is because of the way GIMP calculates the hue adjustment:

mapped_primary_hue = (input_hue + primary_hue_adjustment)
mapped_secondary_hue = (input_hue + secondary_hue_adjustment)
...
final_hue = (mapped_primary_hue * primary_intensity) + (mapped_secondary_hue * secondary_intensity)

A.k.a. it maps both ranges independently then interpolates the result between them.  Meanwhile, GIMP ensures that mapped_primary_hue and mapped_secondary_hue are kept inside the (0.0 - 1.0) range, and if there is more than a 180º difference between them, GIMP wraps mapped_secondary_hue again to yield a "shortest circle" route.  This is correct 99% of the time, but in the above case, it fails because there's a 200º difference between mapped_primary_hue and mapped_secondary_hue (regardless of the actual input value or master hue adjustement); GIMP assumes it is going the wrong way around the HSV circle when it actually isn't (the actual difference between blue and cyan after these adjustments is 140º, not 200º).

Another testcase to confirm why it's a bug:
- Cyan hue +90
- Blue hue -90
Result: Correct (overlap fades from magenta/blue -> cyan/green).

- Cyan hue +91
- Blue hue -91
Result:  Incorrect (overlap fades from blue/magenta -> red -> yellow -> green/cyan)

Who knew a humble 2º made such difference?  The patch that fixed #527085 cannot tell whether a difference of > 180º is due to crossing the red/magenta wraparound or if that was deliberate on the part of the user.  (And it's not the tool's job to question whether the user's adjustments are sane.)

I can submit a patch for this that may fix the issue permanently - but let me know if my algebra is correct first:

Given that:
 mapped_primary_hue = input_hue + (master_hue_adjustment + primary_hue_adjustment)
 mapped_secondary_hue = input_hue + (master_hue_adjustment + secondary_hue_adjustment)
 (primary_intensity + secondary_intensity) = 1

And:
 final_hue = mapped_primary_hue * primary_intensity + mapped_secondary_hue * secondary_intensity

THEN:
 final_hue = (input_hue + master_hue_adjusment + primary_hue_adjusment) * primary_intensity + (input_hue + master_hue_adjusment + secondary_hue_adjustment) * secondary_intensity
 = (input_hue + master_hue_adjustment) * (primary_intensity + secondary_intensity) + primary_hue_adjustment * primary_intensity + secondary_hue_adjustment * secondary_intensity
 = input_hue + master_hue_adjusment + (primary_hue_adjustment * primary_intensity + secondary_hue_adjustment + secondary_intensity)

In other words, when dealing with pixels in an overlap region the tool should interpolate the hue adjustment from the respective primary and secondary ranges, THEN map that adjustment to the pixel.  And since the output value is subsequently converted from HSL back to RGB space with essentially no further processing, there's no need to worry about crossing the red/magenta wraparound at all.

-- Stratadrake
strata_ranger hotmail com
--------------------
Numbers may not lie, but neither do they tell the whole truth.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]