Beep6581 / RawTherapee

A powerful cross-platform raw photo processing program
https://rawtherapee.com
GNU General Public License v3.0
2.8k stars 316 forks source link

Identity HaldCLUT changes colors #6416

Open Bezierr opened 2 years ago

Bezierr commented 2 years ago

This might be related to what is discussed in #5071 (last two comments).

I'm not sure if this is a bug, if I have wrong expectations, or if the information in RawPedia is misleading.

To reproduce, you need a wide gamut monitor.

  1. Open the attached picture in RT, profile "(neutral)", Working Profile "ProPhoto".
  2. Go to Color / Film Simulation and apply the Identity HaldClut provided by RT, or, alternatively, created with ImageMagick as described in RawPedia.

What I would expect: The colors don't change. What I see: The blue straw changes its color visibly.

Further investigation lead me to believe (though that is by no means certain) that using Film Simulation somehow converts the picture to sRGB, as it seems that only colors outside the sRGB color space are changed when the Identity HaldCLUT is applied


Version: RT 5.8 release; also observed in dev 5.8-3085-ga673190fd Windows 10 20H2

Sample

gaaned92 commented 2 years ago

Take my answer with some caution, as I am not a dev.

This has to be confirmed by a developer, as I am not able to inspect the code.

Bezierr commented 2 years ago

Thank you.

Assuming you are correct, does that imply that, in general, Film Simulation / HaldCLUT will not work correctly on pictures with colors outside the sRGB range? That might indeed explain my observations here https://discuss.pixls.us/t/haldclut-vs-color-toning-colors-not-identical/25954, as it seems that the divergent colors usually are out of sRGB, or at least close to the edge.

gaaned92 commented 2 years ago

A developer should check in the code if what I wrote above is true. @Thanatomanic or @heckflosse could you have a look? My fear is that if you want to output a large gamut image (to use in other SW or display on Wide gamut display), use of Haldclut would jeopardize your result.

I have a normal display, kind of sRGB gamut, but not exactly. It is a little wider toward the blue. It is profiled. On some images, I can see that the blue is tamed by the haldclut function.

heckflosse commented 2 years ago

If the profile embedded in the clut is the same as the working profile, there will be no conversion, else the image will be temporary converted to the profile of the clut.

For reference:

https://github.com/Beep6581/RawTherapee/blob/dev/rtengine/improcfun.cc#L2979

gaaned92 commented 2 years ago

Thanks Ingo. So what is the way to generate and use a haldclut in a Wide Gamut context.

To generate the Halclut:

Using the haldclut:

Do you agree?

TechXavAL commented 2 years ago

AFAIK, the Hald_CLUT_Identity_12.tif file is encoded with sRGB primaries, so if I have understood correctly @heckflosse's post, whenever you apply that clut to a default working profile image (that is, encoded in ProPhoto):

So there will unavoidably be some color degradation, as those colors compressed when encoding into sRGB won't be recovered afterwards, just re-encoded in a bigger color space. So while «doing nothing» with the identity haldclut, you will lose/transform colors from the initial image.

gaaned92 commented 2 years ago

The present Hald_CLUT_Identity_12.tif I have has no ICC profile embedded, so I suppose RT consider it is encoded in sRGB.

a halclut is just a way to pack a 3D LUT. for the identity HaldClut, when you input a value (3 coordinates), you output the same value whatever the color space.

Now I can assign whatever color space I want to the identity HaldClut. Here, I will assign Prophoto linear from Elle stone to the identity.

What is expected : the new output HaldClut should be identical to the identity.

It's not the case, so either there is a bug or I overlooked something.

Lawrence37 commented 2 years ago

The color profile in the HaldCLUT does not matter. RawTherapee will only look at the raw pixel values. The RawPedia page explains this. What isn't documented is that the CLUT is applied in a color space pulled from the name of the HaldCLUT file. The color space name must exactly match one of the working color spaces and appear at the end of the file name before the extension. For example, Identity_ProPhoto.tif will tell RawTherapee to use ProPhoto. If the name does not match any working profiles, sRGB is used.

heckflosse commented 2 years ago

@Lawrence37 That's true for applying a HaldCLUT. But when you open a HaldCLUT file in editor, the color space is not taken from the name of the file. Means, when you open a HaldCLUT in editor to create a new HaldCLUT, you need to tell RT which input color profile it is. Or am I wrong?

Lawrence37 commented 2 years ago

Right. I'm not 100% sure, but I think for creating a HaldCLUT from an identity file, both the input and output profile should be the color space that the transformation is intended to be applied in.

Bezierr commented 2 years ago

I can confirm that renaming the RT-provided Identity HaldCLUT to "RT_Identity_12_ProPhoto.tif", and applying it to my sample photo, does not change the picture anymore :-)

So... I think that in RawPedia should be mentioned that if the name of a HaldCLUT does not end in the name of the Working Profile, a conversion of the picture to a color space whose name can be found at the end of the HAldCLUT filename, or sRGB if there is none, takes place.

To be frank, this seems very un-intuitive to me. Is there a reason for this behavior?

Further, since the default (and recommended) Working Profile is ProPhoto, wouldn't it make sense to name the RT-proveded Identity HAldCLUT something like "RT_Identity_12_ProPhoto.tif"?

gaaned92 commented 2 years ago

1- @Lawrence37 Thanks for the explanation. I thought that the film simulation would transform the photo in the color space of the Haldclut if an, ICC was embedded in this Haldclut. This way would be much much better and more intuitive than appending a color space name at the end of the Haldclut.

2- if I want to create a prophoto Haldclut

3- I don't think it is possible to create a prophoto Haldclut from a SRGB haldclut as for all colors outside sRGB gamut the transformation is not defined.

4- @Bezierr: the hald clut identity is color agnostic and there is no need to append a colorspace name to it, unless you would like to use it in film simulation.

5- @Lawrence37 @heckflosse When I use a sRGB Hald CLUT, what is the rendering intent of the transformation from prophoto to sRGB?

heckflosse commented 2 years ago

When I use a sRGB Hald CLUT, what is the rendering intent of the transformation from prophoto to sRGB?

afaik it's a simple matrix conversion prophoto->xyz->srgb

gaaned92 commented 2 years ago

afaik it's a simple matrix conversion prophoto->xyz->srgb

So where the clipping comes from? from the Clut transformation itself?

Beep6581 commented 2 years ago

What isn't documented is that the CLUT is applied in a color space pulled from the name of the HaldCLUT file.

Could you point me to the code?

heckflosse commented 2 years ago

So where the clipping comes from? from the Clut transformation itself?

If you map a prophoto pixel to a srgb pixel, it may get a value larger than 255 (or 65535), If you apply a clut on this pixel, it will be clipped beause the clut does not support more than the 255/65535 range.

gaaned92 commented 2 years ago

Thanks @heckflosse understood

Lawrence37 commented 2 years ago

@Beep6581 The profile name is read here. https://github.com/Beep6581/RawTherapee/blob/a20fe8b191184be51eb28f8cfdffee3eb9d80ca3/rtengine/clutstore.cc#L293-L306

heckflosse commented 2 years ago

While having a look at the code of clutstore.cc I stumbled about a confusing part, which I would like to fix with this patch to avoid future confusion when looking at this code.

diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc
index e3bd9c988..3f4808566 100644
--- a/rtengine/clutstore.cc
+++ b/rtengine/clutstore.cc
@@ -20,7 +20,6 @@ namespace

 bool loadFile(
     const Glib::ustring& filename,
-    const Glib::ustring& working_color_space,
     AlignedBuffer<std::uint16_t>& clut_image,
     unsigned int& clut_level
 )
@@ -54,15 +53,8 @@ bool loadFile(
         std::unique_ptr<rtengine::Imagefloat> img_float = std::unique_ptr<rtengine::Imagefloat>(new rtengine::Imagefloat(fw, fh));
         const PreviewProps pp(0, 0, fw, fh, 1);

-        rtengine::procparams::ColorManagementParams icm;
-        icm.workingProfile = working_color_space;
-
         img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams());

-        if (!working_color_space.empty()) {
-            img_src.convertColorSpace(img_float.get(), icm, curr_wb);
-        }
-
         AlignedBuffer<std::uint16_t> image(fw * fh * 4 + 4); // getClutValues() loads one pixel in advance

         std::size_t index = 0;
@@ -77,7 +69,6 @@ bool loadFile(
                 index += 2;
             }
         }
-
         clut_image.swap(image);
     }

@@ -129,7 +120,7 @@ rtengine::HaldCLUT::~HaldCLUT()

 bool rtengine::HaldCLUT::load(const Glib::ustring& filename)
 {
-    if (loadFile(filename, "", clut_image, clut_level)) {
+    if (loadFile(filename, clut_image, clut_level)) {
         Glib::ustring name, ext;
         splitClutFilename(filename, name, ext, clut_profile);
Entropy512 commented 2 years ago

If you map a prophoto pixel to a srgb pixel, it may get a value larger than 255 (or 65535), If you apply a clut on this pixel, it will be clipped beause the clut does not support more than the 255/65535 range.

Alternatively, OOG colors may receive a negative value, which will, again, be clipped since the clut doesn't support negative-valued inputs.

One thing I definitely wonder is - the name of the CLUT determines its intended working gamut, but what is the intended working transfer function? I'm guessing not linear in/linear out, that's generally not ideal for a 3D LUT without 1D shapers on the input and output to make the main LUT more perceptually even.

Most of my use of HALD CLUTs in RT is (ab)using input and output ICC profiles to generate a conversion and grading LUT that is fed to ffmpeg...

Bezierr commented 2 years ago
* I input the Hald_CLUT_Identity_12.tif using "**no profile**"  thus obtaining an identity transformation in prophoto space.

* I apply the color processing I previously set up

* I output the result in  a prophoto **linear** space and I append prophoto to the name

I can confirm that this works for me, as long as I don't apply color processing (i.e. basically create another Identity HaldCLUT), and append "ProPhoto" instead of "prophoto".

However, I still don't get desired results when actually applying color processing.

Attached Test.zip contains:

Test.zip

Lawrence37 commented 2 years ago

@Bezierr The hue change in the pp3 is very strong and limited to a narrow range of hues. Have you observed the same issue with less dramatic color adjustments? I tried it myself and got reasonable results. For strong color changes, a larger HaldCLUT may be necessary.

Bezierr commented 2 years ago

@Lawrence37: I intentionally made this change (a) simple (just one color modification; no masks or other complications involved) and (b) strong so its effects could be easily observed and compared.

Yes, I generally observe the issue with all color changes I try, even slight ones. Either my expectations (result with HaldCLUT should be visually, though not necessarily mathematically, identical to color changes applied directly) are off, or I'm making some mistake that I can't figure out, even though I've already spent quite some time trying.

Generally, my results with HaldCLUT look somewhat similar, though by no means identical, to the color changes they are based on.

Lawrence37 commented 2 years ago

Found the problem. The film simulation code assumes the HaldCLUT is encoded with an sRGB gamma. Therefore, you need to use a ProPhoto profile with the sRGB gamma instead of linear. :grimacing:

arbv commented 1 year ago

@Lawrence37 So, the input gamma curve for a for a LUT file should be sRGB gamma curve regardless of the input or resulting colour space. Am I correct?

Or, to be more precise - if I want to generate a LUT file (which I intend to convert into HadlCLUT "format") and I want to change (apply) the gamma (tone curve) to, for example s709, should I do something like this:

image

If I want the transformation to happen in ProPhoto colour space, I should append _ProPhoto to the end of the HaldCLUT filename. Am I correct here too?

Lawrence37 commented 1 year ago

@arbv When applying a HaldCLUT, RawTherapee will always use the sRGB gamma to interpret the CLUT. Therefore, the HaldCLUT should be encoded with the sRGB gamma. I don't know what the context of your screenshot is, but you can adapt the RawTherapee method of generating a HaldCLUT:

  1. Open the identity HaldCLUT.
  2. In color management, set the input and output color profile according to the primaries you want the HaldCLUT be applied in. The gamma should be the sRGB gamma regardless of what the primaries are. It's easy to create a profile if necessary with the ICC profile creator.
  3. Make the desired color and tone adjustments.
  4. Save the HaldCLUT. If you want the CLUT to work in sRGB primaries, you don't need to add anything to the name. Otherwise, you need to append an underscore followed by the profile name as it appears in the RawTherapee working profile drop-down.
arbv commented 1 year ago

@Lawrence37 Thank you for the information.

Oh, sorry for not providing the context. The screenshot is that of LUTCalc. I wanted to generate a .cube LUT file and then convert it into HaldCLUT format via gmic.

On the screenshot - Rec Gamma means "input gamma" - that is what the LUT expects to receive for transformation.

So, I guess, the input gamma for a HaldCLUT is always sRGB.

arbv commented 1 year ago

@Lawrence37

One more question to wrap my head around this: at which stage a HaldCLUT is applied - that is, data being passed to the LUT is in the working colour space or output colour space?

Lawrence37 commented 1 year ago

@arbv My understanding is the gamma and gamut options in LUTCalc are for defining the CLUT transformation (equivalent of step 3 in my comment above), so they are (mostly) unrelated to the input and output profiles used in RawTherapee. Go ahead and create the .cube CLUT without thinking about what RawTherapee expects. Only after you have converted the CLUTs to HaldCLUTs do you have to think about the color profiles. This part you can figure out by knowing that RawTherapee will interpret the HaldCLUT as having an sRGB gamma (and converting it to linear before using it) and apply it in the color space in the name of the HaldCLUT file (or sRGB if there is no explicit color space).

Refer to this section of RawPedia for the Film simulation's location in the processing pipeline. The image data is converted to the color space as defined in the HaldCLUT file name, the film simulation is applied, and finally the data is converted back into the working color space.

arbv commented 1 year ago

@Lawrence37 Thank you for the information! Perhaps, the Wiki article should be updated as well.

This stuff is complicated.