3D LUT module in darktable 2.7 (dev)

On Windows, with that code. But I’m happy with#define cimg_verbose 0 which is probably better in the dt context.

I’ve got a travis shadow error:

/usr/bin/clang+±7 -DGDK_DISABLE_DEPRECATED -DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_22 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_MIN_REQUIRED -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_40 -DGTK_DISABLE_DEPRECATED -DGTK_DISABLE_SINGLE_INCLUDES -DHAVE_BUILTIN_CPU_SUPPORTS -DHAVE_CONFIG_H -DHAVE_GPHOTO2 -DHAVE_GPHOTO_25_OR_NEWER -DHAVE_GRAPHICSMAGICK -DHAVE_HTTP_SERVER -DHAVE_KWALLET -DHAVE_LENSFUN -DHAVE_LIBSECRET -DHAVE_MAP -DHAVE_OPENCL -DHAVE_OPENEXR -DHAVE_OPENJPEG -DHAVE_OSMGPSMAP_110_OR_NEWER -DHAVE_PRINT -DUSE_COLORDGTK -DUSE_LUA -D_XOPEN_SOURCE=700 -D__GDK_KEYSYMS_COMPAT_H__ -Dlut3d_EXPORTS -I/build/darktable/src -Isrc -I/build/darktable/src/external/LuaAutoC -Isrc/iop/… -I/build/darktable/src/iop -isystem /build/darktable/src/external -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /usr/include/gtk-3.0 -isystem /usr/include/at-spi2-atk/2.0 -isystem /usr/include/at-spi-2.0 -isystem /usr/include/dbus-1.0 -isystem /usr/lib/x86_64-linux-gnu/dbus-1.0/include -isystem /usr/include/gio-unix-2.0 -isystem /usr/include/cairo -isystem /usr/include/libdrm -isystem /usr/include/pango-1.0 -isystem /usr/include/harfbuzz -isystem /usr/include/fribidi -isystem /usr/include/atk-1.0 -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/gdk-pixbuf-2.0 -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/uuid -isystem /usr/include/libxml2 -isystem /usr/include/libsoup-2.4 -isystem /usr/include/OpenEXR -isystem /usr/include/lensfun -isystem /usr/include/librsvg-2.0 -isystem /usr/include/x86_64-linux-gnu -isystem /usr/include/json-glib-1.0 -isystem /usr/include/openjpeg-2.3 -isystem /usr/include/libsecret-1 -isystem /usr/include/GraphicsMagick -isystem /usr/include/lua5.3 -isystem /usr/include/osmgpsmap-1.0 -isystem /usr/include/colord-1 -pipe -Wall -Wformat -Wformat-security -Wshadow -Wtype-limits -Wvla -Wthread-safety -Wno-error=varargs -Wno-error=address-of-packed-member -Wframe-larger-than=32768 -Wlarger-than=524288 -std=c++14 -std=c++11 -fopenmp=libomp -march=native -msse2 -g -O2 -g -DNDEBUG -O2 -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -Werror -include common/module_api.h -include iop/iop_api.h -std=c++14 -MD -MT src/iop/CMakeFiles/lut3d.dir/decompress_clut.cpp.o -MF src/iop/CMakeFiles/lut3d.dir/decompress_clut.cpp.o.d -o src/iop/CMakeFiles/lut3d.dir/decompress_clut.cpp.o -c /build/darktable/src/iop/decompress_clut.cpp
In file included from /build/darktable/src/iop/decompress_clut.cpp:66:
/build/darktable/src/iop/./CImg.h:23543:25: error: declaration shadows a field of ‘cimg_library::CImg::_cimg_math_parser’ [-Werror,-Wshadow]
CImg expr(mp.opcode[2] - 4);
^
/build/darktable/src/iop/./CImg.h:16087:19: note: previous declaration is here
CImg expr, pexpr;
^
/build/darktable/src/iop/./CImg.h:24230:23: error: declaration shadows a field of ‘cimg_library::CImg::_cimg_math_parser’ [-Werror,-Wshadow]
CImg expr(mp.opcode[2] - 5);
^
/build/darktable/src/iop/./CImg.h:16087:19: note: previous declaration is here
CImg expr, pexpr;
^
2 errors generated.

Some GMIC commands to manipulate lut files.

compress a (color to color transform) haldclut.png file
gmic -i dark_green_1.png -compress_clut 8,2,2048 split c,2 append x permute yxzc -o dark_green_1-c.png

compress a (color to b&w transform) haldclut.png file
gmic -i black_and_white.png -compress_clut 8,2,2048 split c -r[3] 100%,100%,100%,3,1 append c split c,2 append x permute yxzc -o black_and_white-c.png

decompress compressed clut to haldclut png file
gmic -i summer-c.png -split y -append c -permute cxyz -decompress_clut 64,64,64 -r 512,512,1,3,-1 -o summer.png

transform cube to haldclut
gmic -input_cube K_TONE.cube -r 64,64,64,3,3 -r 512,512,1,3,-1 -o K_TONE.png

compress (color to color transform) cube file
gmic -input_cube identity.cube -compress_clut 8,2,2048 split c,2 append x permute yxzc -o identity-c.png

extract one clut from gmic_cluts compressed library compatible with dt, but I haven’t succeeded yet removing the useless black points.
gmic -i gmic_cluts.png rows 128,129 -o edgyember-c.png

1 Like

If not already done those commands should probably be in comment in the 3dlut.c file. And maybe also in the RELEASE_NOTES?

1 Like

https://framagit.org/dtschump/CImg/commit/0c333883a9d16d007e2db6a1792c97aeb2021b51 should fix this.

1 Like

@David_Tschumperle
Great ! that did it ! thank you very much. :slight_smile:

@Pascal_Obry
I’ll do it. Meanwhile I hope I’ll have a complete set.

I know that identity is the most useless lut but it helped me a lot to find my way … Here below is the identity compressed lut work (on the right). I’ve tried 48^3 and 64^3 with the same results: a slight fading of orange and blue. I don’t get that with the identity.cube file (no change when applied)

cube file (remove txt extension) identity size 2.cube.txt (259 Bytes)

identity compressed lut: identity-from%20cube (compression_lut did a perfect work here)

cimgz file: (replace txt extension by cimgz) identity-from cube.txt (52.1 KB)

EDIT: the above quote is misleading, sorry. The cache rounding/compression is not involved here. The effect is already there on the first decompression of the identity compressed clut.

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

And there is already an 7 year old bugreport about this problem:

Still does not make sense to blame it on DT and if you read the issue you know that GLib developers are aware that’s not optimal on Windows but there is no perfect solution and no Windows developer hasn’t stepped up to finish the proposed solution.

There is probably an error here concerning the clut compression.
I don’t get this result. For a 32x32x32 identity clut (rounded to nearest integer), I get 203 keypoints, while you have only 8.
I doubt that with 8 keypoints, you’ll get enough precision for the reconstruction.

$ gmic 32,32,32,3,[x,y,z]*255/31 round nm identity compress_clut
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input image at position 0, with values '[x,y,z]*255/31' (1 image 32x32x32x3).
[gmic]-1./ Round values of image [0] by 1 and nearest rounding.
[gmic]-1./ Set name of image [0] to 'identity'.
[gmic]-1./ Compress color LUT [0] as a set of colored keypoints, with maximum error 8, average error 2 and 2048 maximum keypoints.

* Process CLUT 'identity' (32x32x32).
  > Add [#445] Max_Err = 5.97758, Avg_Err = 1.98607         
  > Rem [#202/203] Max_Err = 7.95582, Avg_Err = 2.0163        
[gmic]-1./ Display image [0] = 'identity'.
[0] = 'identity':
  size = (1,203,1,6) [4872 b of floats].
  data = (0;0;0;0;0;0;0;0;0;0;0;0;(...),0;115;140;255;0;33;66;99;132;189;222;255).
  min = 0, max = 255, mean = 129.287, std = 99.4205, coords_min = (0,0,0,0), coords_max = (0,151,0,0).
[gmic]-1./ End G'MIC interpreter.

Are you sure the values of your identity CLUT are defined in [0,255], and not in [0,1] for instance ?

OK, i understand now.
Your .cube file has a resolution of 2x2x2, and the compression algorithm tries to compress the data at the original resolution. Hence, only 8 points are needed to perfectly compress this CLUT, at resolution 2x2x2.
But, of course, this doesn’t mean that the decompression algorithm reconstruct the color data linearly at any other resolution (actually it doesn’t).

I’ve seen also this. Does that sounds right for you ? My starting point is the cube identity size 2 (eight points of the cube), which is enough to define identity. When I compressed it I’ve got the tiny png you can find above. If you open it you find the same eight points of the cube.

here is the compression process (Max_Err = 0, Avg_Err = 0, perfect, isn’t it ?):

gmic -input_cube identity.cube -compress_clut 8,2,2048 split c,2 append x permute yxzc -output identity-c.png
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input CLUT from file 'identity.cube'.
[gmic]-1./ Compress color LUT [0] as a set of colored keypoints, with maximum error 8, average error 2 and 2048 maximum keypoints.

* Process CLUT 'identity' (2x2x2).
  > Add [#8] Max_Err = 0, Avg_Err = 0
  > Rem [#7/8] Max_Err = 281.893, Avg_Err = 35.2367
[gmic]-1./ Split image [0] along the 'c'-axis, into 2 parts.
[gmic]-2./ Append images [0,1] along the 'x'-axis, with alignment 0.
[gmic]-1./ Permute axes of image [0], with permutation 'yxzc'.
[gmic]-1./ Output image [0] as png file 'identity-c.png' (1 image 8x2x1x3).
[gmic]-1./ End G'MIC interpreter.

We don’t need 32^3 points to define identity, in theory. Now the reconstruction process may need more than 8 points, I haven’t the answer but that is at least a question.

Yes, that is right. The compression algorithm compresses a CLUT at a given resolution, and the reconstruction step doesn’t reconstruct the data linearly (even if for this particular case of identity CLUT it would be nice, it has no reason to do that). So, more than 8 keypoints are needed.
If you compress a CLUT at a 2x2x2 resolution, then of course a perfect reconstruction is achieved with 8 points (8 points is actually the minimal number of points, as it corresponds to the initialization used by the compression algorithm).

That’s not true. If you consider only linear interpolation, then only 8 points are needed.
For other types of interpolations (like the diffusion PDE-based approach, as used by the compression algorithm), you may need more points.
Of course, for a simple CLUT like the identity, it’s a bit a pity to require so much keypoints, but the important thing is that the average number of keypoints stay low even for complex CLUTs.
Actually, 203 keypoints is quite low, compared to the 32^3 = 32768 values contained in a 32^3 CLUT.

1 Like

Thanks a lot for the explanation. That answers my question.

EDIT. thanks to your gmic script I’ve generated compressed identity for sizes 4, 8, 16 & 32. Starting to 8 I don’t see difference any more with the original, while the histogram still changes a bit until 32.
I understand that one should be aware that compressing lut below a certain size may impact the accuracy of the compressed lut. From your experience could you give a minimum size for the source lut ?

1 Like

What I’ve done so far is to compress all the CLUTs I got at their original resolution, when possible.
I got CLUTs with resolution from 13^3 to 144^3.
Anyway to speed up compression, I’ve chosen a max resolution of 64^3, which is IMHO more than sufficient, considering the general smoothness of the considered CLUTs.

Also, I’m not sure there is any interest in trying to compress the identity CLUT, which is a CLUT that is well mathematically defined (we know the formula). It won’t be compressed more than using the formula :slight_smile:

Thank thank you! i was waiting for this for loooong time! now i can finally ditch all the other softwares, and use dt and 3dlutcreator together! amin

Regards

@David_Tschumperle The lut application clips the unbounded input values between [0,1] as @hanatos says. The cube data themselves do not help to treat the input values outside the cube bounds, but … from the compressed lut key points it is maybe possible to interpolate output values for them (as the decompress algorithm does to calculate all the cube points). Of course that would have an impact on the speed but it could be worth to check it. Would do you think ?

That’s an interesting point. Some cameras are able to provide log raw data for example and one can find log luts on the web. But their output is related to a specific colour space (rec709, rec2020, ??). So this would not be without interference with the input colour profile module. If I could find some log raw images I would be happy to make some try.

1 Like

Maybe somebody can help here.

The compressed lut stuff works (at least on windows) but using the static library of gmic (libgmic.a).
So far I don’t succeed in making it work using the dynamic library (libgmic.dll).
The goal is not to include the G’mic 5MB into dt.
Current details are given in PR #2534

Any advice or help is welcome. Thanks in advance.

@David_Tschumperle, I’ve opened an issue there: https://framagit.org/dtschump/gmic/issues/4.
Is that the right place ?
I would like to check if the libgmic.dll I generate is correct. Thanks in advance.

I’m really sorry, but for all Windows-related issues, I can be of little help.
Right now, I don’t really understand how .dll works , for me, it looks like dynamic libraries with extra mess :slight_smile:
I’m afraid you’ll have to rely on someone smarter than me ! (this won’t be hard to find anyway).