Search code examples
opengl-esglslfragment-shaderglsles

Using LUT in OpenGLES shader for false coloring


I am trying to use a fragment shader to convert a grayscale image to colored output. The idea is fairly straightforward; make three arrays of length 256 and map greyscale values [0,255] to RGB (3 * [0,255]). Below is the code I've written:

#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 vTextureCoord;
uniform samplerExternalOES sTexture;

const int red[256] = int[256](255, 128, 240, ... , 143); // declaring as const/non-const changes the output
const int green[256] = int[256](230, 120, 34, ... , 100);
const int blue[256] = int[256](90, 73, 99, ... , 42);

void main (void) {
    float r, g, b, y;
    y = texture2D(sTexture, vTextureCoord).r; // using only the r value from YUV received
    y = y * 255.0; // convert y from [0,1] to [0,255]

    int index = int(y); // use y as an index to map value to the lookup arrays

    r = float(red[index]) / 255.0;
    g = float(green[index]) / 255.0;
    b = float(blue[index]) / 255.0;

    // Set the RGB color of our pixel
    gl_FragColor = vec4(r, g, b, 1.0); 
    // here, if I were to instead assign gl_FragColor = vec4(y,y,y, 1.0); I'd see the expected greyscale output
}

I'm fairly new to OpenGL, but I've been able to use simple equations and get a false-colored output, the code for which looks something as follows:

y = y * 255;
r = y * 0.47446 + 0.65658;
g = y * 0.16213 + 0.58145;
b = y * 0.047524+ 0.75203;
gl_FragColor = vec4(r / 255.0, g / 255.0, b / 255.0, 1.0); 

The output using the LUT however is fairly bizarre. Declaring the int arrays as const gives only the 0th index and 255th index's output; no color from in between. Without the const the code crashes with aSIGSEGV.

Has anyone else attempted this / know what I may be doing wrong in the LUT code?


Solution

  • I'm not sure why this isn't working, but the more traditional way to do this is to store the LUT as a 256x1 texture, and just do a texture lookup.

    void main (void) {
        float luminance = texture2D(inputTexture, vTextureCoord).r;
        gl_FragColor = texture2D(lutTexture, vec2(luminance, 0.5));
    }
    

    ... is probably going to be a lot faster and more flexible.