Reputation: 298
I have a colour in greyscale, rgb(128, 128, 128), and I want to find the colour in a certain hue, 0 (red) that has the same lightness as the grey colour, in Javascript.
I know how to find the lightness of the grey, using ((0.3 * r + 0.59 * g + 0.11 * b)), but I want to know how I could then add a hue to that colour. I want white to become white, light grey to become light red, medium grey to become bright red, dark grey to become dark red, and black to become black etc.. The hue may change.
Currently I've tried this but it gives bright red rather than white when white is given.
// lightness = 0 - 255
// color = {r: 1, g: 0, b: 0}
newcolor = {};
newcolor.r = lightness * color.r;
newcolor.g = lightness * color.g;
newcolor.b = lightness * color.b;
return newcolor;
Upvotes: 4
Views: 2978
Reputation:
You need to use HSV or HSL color-space instead of RGB, at least this makes things a bit easier to relate to.
Answer has been updated after accepted to implement a solution for HSL instead of HSV which I is capable of doing this within its standard range compared to HSV (sorry, I forgot about this detail as the main difference between the two). The result is the same however, but HSL simplifies the code a bit.
In order to use HSV (shown below) to colorize based on luminance you simply extend the input scale used by luminance and saturation to the double and then use a threshold to toggle which of the two you are affecting (HSL would do this directly, please see update below).
Lets say luminance and saturation goes from [0, 100]. Then extend your input value to go [0, 200]. Now make threshold that toggles the component it's used for:
if (lum > 100) {
col = hsv2rgb(angle, 100 - (lum - 100), 100);
} else {
col = hsv2rgb(angle, 100, lum);
}
Now your color will go from black to vivid, and from vivid to white.
For pixels in an image you just normalize the lum value to extend double scale for each pixel. If your luma values are in the range [0, 255]:
lum = luma / 255 * 200;
HSL is probably better fitted for this specific task (colorizing) as its entire range do already the same as HSV above without using threshold and scaled range. This is also the main difference between HSV and HSL.
This following demo is using HSL method on a pre-grayscaled image:
Which approach you choose to use could be determined by for example performance (HSV + threshold seem to be more performant).
In any case, here is a code snippet that converts HSL to RGB:
function hsl2rgb(h, s, l) {
var r, g, b, q, p;
if (s == 0) {
r = g = b = l;
} else {
function hue2rgb(p, q, t) {
if (t < 0) t++;
if (t > 1) t--;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
q = l < 0.5 ? l * (1 + s) : l + s - l * s;
p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return {
r: r * 255,
g: g * 255,
b: b * 255};
}
Upvotes: 2