Gradient Map on image

I’m trying to do the equivalent of photoshop gradient map in OF on images or videos.
This is the principle:

What could a be a clever way to do it?


If you want to do it for a video, a good choice is to use an OpenGL shader.
Here’s an example:

The idea is to provide two textures to the shader:

  • the base image to render
  • a color gradient to map, like photoshop do:

    The shader first compute the grayscale color of a base image pixel, then pick in the gradient texture the associated color.

Here’s the fragment shader code:

uniform sampler2DRect tex0;     // base image to render
uniform sampler2DRect gradient; // color gradient to apply
uniform float gradientWidth;    // gradient width

void main (void){
    // Original pixel color
    vec2 pos = gl_TexCoord[0].st;
    vec4 src = texture2DRect(tex0, pos);
    // Convert color to grayscale
    float l = 0.2989 * src.r + 0.5870 * src.g + 0.1140 * src.b;
    // Pick color in gradient, according to grayscale value
    vec4 map = texture2DRect(gradient, vec2(l * gradientWidth, 5.0) );
    // Return this color
    // Keep alpha value from original pixel 
    gl_FragColor = vec4( map.rgb, src.a );

And here’s the app (src and data folders).
You can use it to see the result with a webcam image, but there’s a few changes to use a video or a single image instead. (6.6 KB)


Works great and it’s fast. Thanks a lot for your help!!
Now I’m trying to use it as a shader for iOS and it doesn’t work with gl_MultiTexCoord0
Will post the GLES 2 shader when I figure out the difference with the openGL shader.

My pleasure.
In case you don’t know it, there’s a shader tutorial with a multitextures example, including GLES2 here:

Thanks! the openFrameworks tutorial is very helpful.

Here is the version of the shader for iOS if someone needs

fragment shader

precision highp float;

uniform sampler2D gradient;

varying vec2 texCoordVarying;
uniform sampler2D tex0;

void main()
    vec2 pos = texCoordVarying;
    vec4 src = texture2D(tex0, pos);
   float gray = 0.2989 * src.r + 0.5870 * src.g + 0.1140 * src.b;

    vec4 map = texture2D(gradient, vec2(gray,5.0) );
    gl_FragColor = vec4( map.rgb, src.a );

vertex shader

uniform mat4 modelViewProjectionMatrix;

attribute vec4 position;
attribute vec2 texcoord;

varying vec2 texCoordVarying;

void main()
    texCoordVarying = texcoord;
	gl_Position = modelViewProjectionMatrix * position;}


    shader.setUniformTexture( "gradient", gradient.getTextureReference(),1);
//DRAW something

heya, running this code on iOS gives me a black rectangle instead of the mapped image. the cam is definitely running and working, and the console says that the shader has linked, but no luck… if you could point me in the right direction that would be great, thanks

can you share your code, the draw function and shader part

heya, it turns out that the draw function in the above was missing the tex0 uniform texture, so the draw became:
shader.setUniformTexture( “gradient”, gradient.getTexture(), 0);
shader.setUniformTexture(“tex0”, cam.getTexture(), 1);
cam.getTexture().draw(0, 0);

the issue I’m having now is that the colour is inverted. this doesn’t happen when i just pass the grey values straight into the gl_fragcolor, bypassing the gradient.
as you can see as well as it being inverted, black and white are present, which shouldn’t be the case if the gradient mapping has worked properly.
the large rectangle behind the cam image is me just calling ofDrawRect before the cam.draw(), that shows what i expected, but the cam doesn’t.