Skip to content

Instantly share code, notes, and snippets.

@kishmiryan-karlen
Created August 13, 2014 12:59
Show Gist options
  • Save kishmiryan-karlen/559c190f6c20856ee323 to your computer and use it in GitHub Desktop.
Save kishmiryan-karlen/559c190f6c20856ee323 to your computer and use it in GitHub Desktop.
A function that helps to apply LUT to image. Make sure to change the canvas IDs or to create temporary canvases.
/**
* Created by Karlen on 13-Aug-14.
*/
var imageContext = document.getElementById('imageCanvas').getContext('2d'),
lutContext = document.getElementById('lutCanvas').getContext('2d');
function applyLUT(image, lut) {
var imageData, lutData, iData, lData;
imageContext.clearRect(0, 0, image.naturalWidth, image.naturalHeight);
imageContext.drawImage(image, 0, 0);
imageData = imageContext.getImageData(0, 0, image.naturalWidth, image.naturalHeight);
iData = imageData.data;
lutContext.clearRect(0, 0, lut.naturalWidth, lut.naturalHeight);
lutContext.drawImage(lut, 0, 0);
lutData = lutContext.getImageData(0, 0, lut.naturalWidth, lut.naturalHeight);
lData = lutData.data;
for (var i = 0, l = iData.length; i < l; i += 4) {
var r, g, b;
r = Math.floor(iData[i] / 4);
g = Math.floor(iData[i + 1] / 4);
b = Math.floor(iData[i + 2] / 4);
var lutX, lutY, lutIndex;
lutX = (b % 8) * 64 + r;
lutY = Math.floor(b / 8) * 64 + g;
lutIndex = (lutY * lut.naturalWidth + lutX) * 4;
var lutR, lutG, lutB;
lutR = lData[lutIndex];
lutG = lData[lutIndex + 1];
lutB = lData[lutIndex + 2];
iData[i] = lutR;
iData[i + 1] = lutG;
iData[i + 2] = lutB;
}
imageData.data = iData;
imageContext.clearRect(0, 0, image.naturalWidth, image.naturalHeight);
imageContext.putImageData(imageData, 0, 0);
}
@CesarVonc
Copy link

CesarVonc commented May 30, 2024

If you use r = Math.floor(iData[i] / 4); to get the color value and then the index in the LUT, you will have steps in gradients and not very clean result, because you get the lower index in a 64 array from a 256 array.

The result is better if you get the lower value, the upper value, and the interpolation between them :

function getT(a, b, c) {
    let ba = b - a;
    if (ba === 0) return 0;
    return (c - a) / ba;
}

function mix(a, b, t) {
    return a + (b - a) * t;
}
r = iData[i] / 4;
r1 = Math.floor(r);
r2 = Math.ceil(r);
r_t = getT(r1, r2, r);

// ... Same things with g and b ...

lutX1 = (b1 % 8) * 64 + r1;
lutY1 = Math.floor(b1 / 8) * 64 + g1;
lutIndex1 = (lutY1 * lut.naturalWidth + lutX1) * 4;

lutX2 = (b2 % 8) * 64 + r2;
lutY2 = Math.floor(b2 / 8) * 64 + g2;
lutIndex2 = (lutY2 * lut.naturalWidth + lutX2) * 4;

lutR = Math.min(255, Math.round(mix(lData[lutIndex1], lData[lutIndex2], r_t)));

// ... Same with g and b ... 

@kishmiryan-karlen
Copy link
Author

@CesarVonc Do you have image comparison of both options? I wonder how different they are.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment