I am working with 3D color LUTs (color lookup tables) in javascript and I was wondering is there a way to combine two or more 3D LUTs to export them in one single file. Let me explain:
I get .cube (3D color lookup file). I parse it and store parsed color values into an array and apply it to existing image. After that I apply new 3D LUT onto existing (changed) image, and I apply new LUT once more. So now I have original image with 3 different 3D LUTs applied onto each other.
Now, I can successfully export every 3D LUT in separate file and download it, but I don't know how to combine them into a single .cube file. I believe I need some algorithm for "combining" different LUTs into one file?
This is example how photoshop does it:
LUT1:
0.024536 0.000183 0.000244
0.049103 0.000336 0.000458
LUT2:
0.041260 0.021149 0.009125
0.067230 0.023804 0.009125
COMBINED LUT (result):
0.035034 0.020660 0.009308
0.054810 0.022766 0.009430
Thank you!
After some research I have found a solution. Essentially, I needed to pipe the output of the first LUT into the input of the second LUT. This requires to have an interpolation function in-program (not just a 3D LUT shader).
Process goes something like this:
Function looks something like this:
function mapColorsFast(out, image, clut, clutMix){
let od = out.data,
id = image.data,
w = out.width,
h = out.height,
cd = clut.data,
cl = Math.floor(Math.pow(clut.width, 1/3)+0.001),
cs = cl*cl,
cs1 = cs-1;
var x0 = 1 - clutMix, x1 = clutMix;
for(var y = 0; y < h; y++) {
for(var x = 0; x < w; x++) {
let i = (y*w+x)*4,
r = id[i]/255*cs1,
g = id[i+1]/255*cs1,
b = id[i+2]/255*cs1,
a = id[i+3]/255,
ci = (dither(b)*cs*cs+dither(g)*cs+dither(r))*4;
od[i] = id[i]*x0 + x1*cd[ci];
od[i+1] = id[i+1]*x0 + x1*cd[ci+1];
od[i+2] = id[i+2]*x0 + x1*cd[ci+2];
od[i+3] = a*255;
}
}
}
Function accepts few arguments: out - buffer into which the result is written image - a buffer containing the image in imageData format clut - color LUT that we're applying to the image clutMix - affecting the strength of the effect (0-1)
In this case, we needed to create identity LUT, save it as image and pass it as image argument to the function, and then apply new LUT onto it. Then we pipe the result again into same function and apply new LUT onto it. We do that for every LUT we want to mix with other LUTs.
I found this function on https://github.com/jwagner/analog-film-emulator/blob/master/src/image-processing.js - Javascript Film Emulation project.
There's a lot of interesting material to find if you're working with canvas 2d image processing, and there's also a working example included: https://29a.ch/film-emulator/
Hope it will help someone in the future!