3

This may be not the perfect question for stackoverflow but I have asked this in graphicdesign network of stackexchange but did not get any answer so posting it here. I am trying to implement gradient map of Photoshop programmatically using glsl fragment shader. Consider below shown gradient map where all white components are replaced by green and black by blue. For other color components Photoshop calculates based on the linear gradient between blue and green. I know there is a math behind this calculation. Does any one know formula to find output color for particular input color value?

enter image description here

Praveena
  • 6,340
  • 2
  • 40
  • 53

2 Answers2

7

Based on the image and description, it looks like this maps the original grayscale value of the image to the blue-green gradient.

There are various ways of converting color to grayscale, depending on the color system used. Many of the simple one are just a weighted sum of the RGB components. For example a widely used formula for converting RGB to brightness (Y) is:

Y = 0.299 * R + 0.587 * G + 0.114 * B

See the Grayscale wikipedia page for more background on the topic and all the different options.

Then you can use a linear interpolation of blue and green with the grayscale value as the parameter. The math for this would be easy anyway, but GLSL even has a built-in mix() function for this purpose.

Some possible code fragments for GLSL, based on reading the original color from a texture Tex using texture coordinates TexCoord:

uniform sampler2D Tex;
in vec2 TexCoord;
out vec4 FragColor;
...
    vec4 origColor = texture(Tex, TexCoord);
    float grayscaleValue = dot(origColor.rgb, vec3(0.299, 0.587, 0.114));
    FragColor = mix(vec4(0.0, 0.0, 1.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), grayscaleValue);

In this code, vec3(0.299, 0.587, 0.114) contains the coefficients from the RGB to grayscale (brightness) formula above. The first two arguments of the mix() function are the start and end colors of the gradient:

  • blue: vec4(0.0, 0.0, 1.0, 1.0)
  • green: vec4(0.0, 1.0, 0.0, 1.0)

Note that a simple linear interpolation between the two colors in RGB space is not ideal, particularly if the colors are very different. You can make this more elaborate, and potentially get better quality, by operating in a different color space like HLS.

Another option to possibly improve the visual appearance is that you use more than two colors to specify the gradient. For example, you could assign blue to brightness 0.0, cyan to brightness 0.5, and green to brightness 1.0. It requires a little more logic than the GLSL code above, but it's just an extension of the same principle.

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • works perfectly but small clarification. This is for blue green gradient but what if I want different color gradient. How did you get `vec3(0.299, 0.587, 0.114)` this value? – Praveena Jun 13 '15 at 06:28
  • I added some more explanation. Those numbers were already explained farther up in the answer, in the formula for converting RGB to grayscale. – Reto Koradi Jun 13 '15 at 06:42
  • Thank you Sir. I got it now.. Now I am fine with RGB as I have no idea about HLS.. Started reading about image processing. Do you write any blog about these kind of things or could you refer me any such blogs or books to read about? – Praveena Jun 13 '15 at 07:15
  • I did some test by processing simple image with both Photoshop gradient map and the formula given here, but they do not match. For example, if you take as a starting image a white to black linear gradient, and apply a blue to green gradient map in Photoshop, black remains black, white remains white, and every shade of grey between gets converted to a gradient between blue and green. What are the maths behind that ? – Fabien Quatravaux Jun 16 '15 at 08:48
  • Note that with "smoothness" on, the gradient isn't actually linear. To make the photoshop gradient match the shader effect you therefore need to use gradients with smoothness at 0% or figure out the smoothing algorithm. – Nuoji Jan 25 '18 at 12:14
2

I tried different gradient maps in Photoshop, and my settings seams different from the ones of the OP. In my case, applying the gradient map filter to a black to white gradient image is showing that black remains black and white remains white. Every shade of grey between is replaced by some color between green and blue. If you map directly shades of grey to the linear gradient, blacks and whites will disappear. Photoshop gradient map seams to retain the Luminescence of the original colors.

Here is the formula I get to match Photoshop gradient map for my settings.

Given (Rg1,Gg1,Bg1) and (Rg2,Gg2,Bg2) the gradient values, (Ro,Go,Bo) the original color value and (Rr,Gr,Br) the resulting color.

  1. get the color to be converted in the HSL space :

(Ho, So, Lo) = rgb2hsl(Ro, Go, Bo)

  1. calculate the linear interpolation of the gradient (in RGB) for Lo value :

(Rt,Gt,Bt) = (Rg1+[Rg2-Rg1]*Lo, Gg1+[Gg2-Gg1]*Lo), Bg1+[Bg2-Bg1]*Lo)

  1. get this value in the HSL space :

(Ht,St,Lt) = rgb2hsl(Rt, Gt, Bt)

  1. Retain the L value from the original color

(Rr,Gr,Br) = hsl2rgb(Ht,St,Lo)

rgb2hsl and hsl2rgb code examples can be found here : HSL to RGB color conversion

Community
  • 1
  • 1
Fabien Quatravaux
  • 3,737
  • 2
  • 27
  • 33