3

I have an complex problem, but it could be solved via this little problem. I would like to make a colorizer, which works per pixel.

I have a defined base color for the picture (the picture has some pixels with this color and a lot of other pixels, which are near to this color):

Hex: #188DD9
HSL: 204° 80% 47%
RGB: 24 141 217

I know my target base color:

Hex: #23752E
HSL: 128° 54% 30%
RGB: 35 117 46

So, I would like to colorize an image.

My assumption is that if I find the correlation in this two HSL values, I can colorize my picture pixel by pixel.

Currently I found that if I move the base color hue with (target hue - base hue) = -76, the hue will be fine.

Could you direct me where is the connexion between saturation and lightness to solve this problem?

Roland Soós
  • 3,125
  • 4
  • 36
  • 49

1 Answers1

2

I assume that, whatever mapping you end up using, you want to map black to black, white to white and grays to grays.

The additive mapping

H' = H + (Htarget - Hbase)

(with wrap-around) you use for hue is indeed probably fine. For saturation, the need to preserve gray values suggest a multiplicative mapping

S' = S * (Starget / Sbase),

with values exceeding 100% saturation clipped. However, for lightness, a linear map just isn't going to do it, since you want to fix both 0% and 100% lightness while adjusting intermediate values. A natural choice might instead be a gamma-type map, i.e.

L' = pow( L, log(Ltarget) / log(Lbase) ) = exp( log(L) * log(Ltarget) / log(Lbase) ).

where the lightness values are scaled to between 0 and 1. (Note: To calculate this map efficiently for lots of pixels, you probably want to precompute a lookup table of, say, 256 entries.)

Of course, there are plenty of other maps you could use, but I'd start with these and see if they give good enough results. Note that, ultimately, the quality of your results may also be limited by the perceptual non-uniformity of the HSL color space; for details, see this Wikipedia page.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • Thank you! It worked fine. I made only one improvement. With some target values, which was near to the end colors(red or green or blue), there were wrong colors after the colorization. The improvement was: if(S > Sbase) S = Sbase; before calculating S' – Roland Soós Jul 27 '11 at 15:46
  • Did you first try using `if (S' > Smax) S' = Smax;`, where Smax is your maximum valid saturation (typically something like 1.0, 100 or 255). Ps. I'd suggest doing the intermediate calculations using long ints or floats, otherwise you might get bitten by arithmetic overflow. Also, if using ints, remember to do multiplication first before division. – Ilmari Karonen Jul 27 '11 at 16:01
  • No, I didn't try it. Now I tried and it produce the same result and your solution is logical. :) Thank you again! – Roland Soós Jul 27 '11 at 16:06