3D LUT module in darktable 2.7 (dev)

It’s easy to create HaldClut.png files with G’Mic, you just have to have an identity.png file and apply a movie profile to it in Gimp. I wrote a French .pdf to create dtStyles so the first part explains how to do it: https://drive.google.com/file/d/0B1cvWUEQ2QwiUUg2eXE4T3N5VGs/view
I also used this method with DxO and I think it can be done with PS and his presets.
I hope the translation with Deepl is Ok.

1 Like

I think your are doing here manually what @anon41087856 was suggesting in this issue:

The limited number of points of dt color checker LUT and the small number of keypoints of the 3D LUT compression algorithm sing the same music for me.

Would the limited number of keypoints from 3D LUT compression fit into the color checker LUT EDIT: (lab<->rgb transform apart) ?
@hanatos, would you have any idea about this ?
EDIT: I rephrase my question. Instead of rebuilding the full 3D LUT from the compressed keypoints, would it be possible to interpolate directly an image with the keypoints themselves, as color checker does with 6x4 or 7x7 patches ?

I didn’t see this post from Aurelien Pierre, thank you for the link.
For the method I edit in my Acrobat, I started from the Dutch_Wolf video: https://youtu.be/m_cLCL5PJk4
that I have translated for French users. Dutch_Wolf kindly provided the modified.cht file to make it work.
I had opened a topic on darktable FR : Convertir Film Emulation de G'Mic en DTStyle
I have a big archive of HaldCLUT in uncompressed.pdf so the ones I made with the G’Mic profiles in Gimp, also the ones with FilmPack from DxO and the profiles proposed by Fuji.

yes the gmic compression is very similar as it solves a very similar problem. there are subtle differences. the system in dt allows unbounded input (extends outside the cube bounds, we have an extra two “hdr patches” usually in the mix to steer the behaviour for bright values). it’s simple to apply it to rgb or camera rgb, just needs a refit (and i think this is indeed what we should be doing to profile cameras too).

there is a trade off in speed. our RBF are global, i.e. for every point you always need to evaluate all 49 nodes (49 is just because 7x7 still looked manageable in the gui). the gmic diffusion approach uses about 10x this number of nodes, at which point a global RBF should maybe be slower (hence my question in the other thread).

i like the RBF system because you can manually edit it to taste after the fact, and because it has a linear part it degenerates to. i’m positive speed could be improved, too.

gmic’s diffusion-based approach would probably mean if you want to edit the nodes you’d be best off re-running the uncompression as a whole rather than doing it on the fly for the whole image (even 256^3 is still only 16MP).

I’ve made work the decompress_clut.cpp (+ CImg.h) stuff from @David_Tschumperle inside my local dt copy.
But, to make it work I’d to cheat with the build and remove the option-Wshadow from CXX_FLAGS in build\src\iop\CMakeFiles\lut3d.dir\flags.make to allow decompress_clut.cpp to compile.
This can be a show stopper as the CImg.h is a huge and heavy concrete C++ library, in case we cannot disable the option -Wshadow specifically for it. It would be a huge work to modify the code to avoid shadowing (I don’t even know if it would be possible).
The code is available here: GitHub - phweyland/darktable: darktable is an open source photography workflow application and raw developer branch lut3d.

I’ve made my tests with the following files:

image
I’ve extracted the compressed files from the GMIC clut library but one should be able, thanks to GMIC tool, to compress any cube or png haldclut file of his choice (there is still some work to be done here).

As announced by the GMIC team, one cannot see the difference with the uncompressed file ! However, there is a price, at least with the current code, we get a one second overhead when opening the applying the compressed lut.

1 Like

gmic caches the extracted cluts. you could use the same cache dir as them and have the benefit that both tools benefit from one tool extracting the clut.

I can do this probably. Will check today.

I’ve done some cleaning this morning, and I can say CImg now compiles with -Wshadow, at least for g++ version 5.5.0 (and later).
The modified CImg.h file can be downloaded from the repo : Sign in · GitLab

2 Likes

Works for dt build too ! Thanks a lot for this huge (at least for me :slight_smile: ) work.

Sounds interesting. Could you be more precise about the sources I can look at ?

When G’MIC decompress one CLUT, it stores a version of the decompressed CLUT in ~/.cache/gmic/clut_name.cimgz .
The cimgz format is a CImg-specific format (using lossy compression this time), which is able to represent a 3d volumetric image of colors (which is what a CLUT is).
With the CImg library, you can load it with CImg<T>::load_cimg().

The ‘decompressed’ CLUT is not stored as an HaldCLUT in .png because this is limited to a few resolutions (siz^2 = SIZ^3).

I realize that decompress_lut accepts whatever dimension. Using dimension (SIZ) = 64, as currently coded, produced luts png compatible. However, not to be as specific, may preserve some future enhancement.

dt and G’MIC can share the same cache as long as they share the same set of lut names (same clut library gmic_cluts.png or at least same naming convention). But that can be confusing is the user has built his own collection of luts (different from gmic_cluts.png), right ?

I’d add that G’MIC uses a resolution of 48x48x48 for decompressing the CLUTs. This is IMHO a good compromise between speed/memory usage/storage size and precision of the color data.
At the moment, I don’t really see any interest for switching to storing the decompressed CLUTs as .png files (with resolution 64^3 = 512^2) which would be larger and slower to decompress.

see this discussion:

@darix
For dt under Windows g_get_user_cache_dir() returns:
C:\Users\philippe\AppData\Local\Microsoft\Windows\INetCache
I don’t know what is returned under Linux and if that could correspond to .cache.
Any thought ?

@David_Tschumperle
With the filename C:\Users\philippe\AppData\Local\Microsoft\Windows\INetCache\gmic\edgyember.cimgz
The code:

cimg::exception_mode(0);
CImg img(1,1,1,3,0);
try { img.load_cimg(filename); }
catch (…) { return 0; } // or catch(CImgIOException&) as well

catches the exception when the file doesn’t exist (that’s ok) but not when the folder just below doesn’t exist (gmic for example). And dt is killed (that isn’t ok). Any advice ?

EDIT. cimgz files for 48x48x48 weigh 1297Kb. Is that correct ?

Arggg, why does dt use the browser cache for luts?

C:\Users\philippe\AppData\Local\Microsoft\Windows\INetCache
This looks so wrong.

Because it’s the only sane and portable solution to get a location for cache data?

it is not DT or GMIC that picked this location but glib/gtk. so your complains would need to go there. and IIRC you can override it with an environment variable if you want. (XDG_CACHE_DIR IIRC)

That is strange, I’ll check later.

If I take the CLUT ‘summer’, it’s more like:

  • 116Kb in .png (64^3 = 512^2).
  • 50Kb in .cimgz (48^3).
  • 94Kb in .cimgz (64^3).

Exception. Setting (instead using exception_mode()=0;):
#define cimg_verbosity 0
let me catch all errors.

File size, setting:
#define cimg_use_zlib 1 (not sure that’s the right syntax…)
plus saving the image as unsigned char instead of float gives me numbers aligned with yours (48^3):

image
Lossy compression + integer rounding … to be checked visually I guess.

I don’t have this behavior here, on my Ubuntu Linux.
Could you please give me one example of code where the issue happens?
Does it happen on Windows, or Linux ?

Also, cimg::exception_mode(0) is roughly equivalent to #define cimg_verbose 0, for the exceptions thrown by CImg, so we shouldn’t see any difference with the sample code you provided.

Integer rounding won’t change anything I guess, as it’s already almost impossible to distinguish between two colors with a +/-1 step on R,G or B.