AcademySoftwareFoundation / OpenColorIO

A color management framework for visual effects and animation.
https://opencolorio.org
BSD 3-Clause "New" or "Revised" License
1.78k stars 456 forks source link

Mrv2 clamps the image after using OCIO #2027

Closed archct closed 1 month ago

archct commented 2 months ago

After applying any Aces config in the OCIO settings, the image values begin to be clamped using rgb channels. The values are truncated to 1, however, if we look through the nuke viewer, we see that the shooting values from the Arri camera, when interpreted through the Arri Wide Gamut (EI800), are much higher than one.

This results in loss of information when changing the gamma and exposure parameters. It is necessary to ensure that the image in mrv2 corresponds in values to the image from the nuke viewer. How to achieve this, it would be useful to get instructions on how to properly configure Access in mrv2. A similar problem is observed in mrv

Desktop: OS: Linux Mint Kernel 5.4.0 Version mrv2 v1.2.3 (the same problem on mrv 6.2.3)

I came to the conclusion that mrv2 truncates values for some reason, regardless of the versioning of OCIO and config. At the same time, even when using the latest versions of config inside nuke, we see a larger dynamic range of values, which, with a strong change in the image in gamma and gain, tries to preserve the color gradient. nuke_viewer mrv2

ggarra13 commented 2 months ago

@archct Thanks for reporting this. I looked into the source of the problem and was able to, AFAICT, pinpoint it to a problem with Wide Gamuts in OpenColorIO's GPU pipeline.

The problem is present on both mrv2 and OpenRV, but it does not seem to be present on Nuke (maybe because it uses the CPU pipeline?).

Visually, the images look fine, but on inspection of the RGB values, shows that the values >= 1.0 are clamped.

Here's an .exr and the aces_1.3 config with Wide Gamuts for testing.

https://mega.nz/file/KaBjTYbD#6cFi-3YfPnwcFKhT3zp8fI8NmoJ8rKgyQP5Q4DkOPD8

To reproduce with mrv2:

The source code created by OpenColorIO master (currently v2.4.0dev) produces the attached code (I've marked with // OK up to the point of the ocioFunc() where there's no clamping):

source.log

For further information, including Nuke's settings, refer to:

https://github.com/ggarra13/mrv2/issues/288

remia commented 2 months ago

Silly question but how are you sampling / picking the colour in Nuke? Remember that Nuke picker is applied before the viewerProcess / display LUT so it can be perfectly ok to have values above 1.0 before the LUT and clamped between 0 and 1 after, for example when using ACES sRGB output.

ggarra13 commented 2 months ago

@remia It is not a silly question, but I think Nuke has improved its color picker in v15 (non-commercial) which is the one I checked with.
The problem is not that the color picker displays values above 1.0 before the LUT and clamped after, but the opposite. The values on the original image, set to scene_linear, are between 0.0 and 1.0. But applying the Wide Gamut OCIO transform takes those values between 0...40. I think that's the whole purpose of the Wide Gamut transforms, but I am not a color expert by any means. Furthermore, I verified the color values with mrv2 too (commenting out a portion of the source code of OpenColorIO 2's generated shader code) and I was able to indeed get values between 0..1 in the original image values with no LUT and 0...40 with LUT with modified source code.

remia commented 2 months ago

Unless you apply an OCIODisplay node in the graph and set Nuke viewer to None or Raw, the colour picker will show values in scene-linear before applying the LUT, this doesn't change in recent Nuke version I believe.

Looking at the shader code you shared, it seems expected that after applying the display LUT you will have clamping of values between 0 and 1, a display doesn't accept values above 1 in the general case. Also seeing you are using ACES 1.X config, given that mrv2 seem to support v2, you could check the newer ACES configs for better precision and match against the CPU implementation.

Could it be that on one side you are playing with exposure adjustments before the LUT and on the other side after (in which case you won't recover details)?

remia commented 2 months ago

I think the link to download the EXR is dead.

ggarra13 commented 2 months ago

Sorry. I moved it to a new folder, and mega.nz seems to change the link. Here it is again:

https://mega.nz/file/KaBjTYbD#6cFi-3YfPnwcFKhT3zp8fI8NmoJ8rKgyQP5Q4DkOPD8

ggarra13 commented 2 months ago

Find attached a movie of Nuke v15 showing the Input Color Space in each File node and the values I get from each node. This is how I changed the input color space. It seems much more straight-forward in Nuke v15.

https://github.com/user-attachments/assets/dedb8f77-7baa-4dd5-9a6c-0ea0ae8457ef

remia commented 2 months ago

Looks like your EXR is in some flavour of log space which is generally not recommended but assuming it's in ARRI LogC3 800, I get a match between Nuke and mrv2 when using the studio config and setting the input correctly on both. One difference I seem to have found, Nuke exposure is applied before the viewing LUT, in scene-linear, as expected. For mrv2, it looks like it's applied before the input colour space conversion, so still in log space which is not correct.

ggarra13 commented 2 months ago

@remia Thanks for taking the time to look into the issue. What input color space does it correspond to on the studio config now?

I think you are probably right about mrv2 doing the color transform in the wrong order. Let me know if this looks right to you:

mrv2's current pipeline (which I inherited from Darby Johnston's tlRender) and that is like wrong is:

READ texture

if (videoLevels == LegalRange)
{
  clamp to legal range
}

if (colorFunc)
{
           // gain and color matrix transformations (saturation, etc) 
}

if (colorInvert)
{
           // invert colors
}

if (levelsEnabled)
{
          // gamma with inLow/outLow, inHigh/outHigh
}

if (softClip > 0)
{
        // soft clipping
}

OCIO transform (if available)
OCIO Lut (if available)

if (autoNormalize)
{
    // normalize on min and max RGB values of image
}

if (invalidValues)
{
    // color pixels red where they go < 0 or > 1
}

if (channelSelection)
{
    // select R or G or B or A
}

So according to you, and what I think this should be:

READ texture

if (videoLevels == LegalRange)
{
  clamp to legal range
}

OCIO transform (if available)
OCIO Lut (if available)

if (colorFunc)
{
           // gain and color matrix transformations (saturation, etc) 
}

if (colorInvert)
{
           // invert colors
}

if (levelsEnabled)
{
          // gamma with inLow/outLow, inHigh/outHigh
}

if (softClip > 0)
{
        // soft clipping
}

if (autoNormalize)
{
    // normalize on min and max RGB values of image
}

if (invalidValues)
{
    // color pixels red where they go < 0 or > 1
}

if (channelSelection)
{
    // select R or G or B or A
}
ggarra13 commented 2 months ago

Looks like your EXR is in some flavour of log space which is generally not recommended but assuming it's in ARRI LogC3 800, I get a match between Nuke and mrv2 when using the studio config and setting the input correctly on both.

Following your advice of using an OCIODisplay node and setting the viewer to Raw I also get a match between mrv2 and Nuke. I'll admit this workflow seems totally counter intuitive.

I also fixed the color pipeline and Nuke and mrv2 now have a perfect match.

What I don't get is where does Nuke get the 0...40 rgb values from without the OCIODisplay node?

remia commented 2 months ago

What I don't get is where does Nuke get the 0...40 rgb values from without the OCIODisplay node?

Those values results from the conversion from ARRI LogC3 to ACEScg which is happening inside Nuke when you set your Read node colorspace. ARRI LogC3 EI800 1.0 corresponds to about 55 in scene-linear.

I also fixed the color pipeline and Nuke and mrv2 now have a perfect match.

Glad to hear that! FYI Nuke is following a display pipeline close to the LegacyViewingPipeline from OCIO App helpers.

archct commented 2 months ago

Thanks for the changes, I tried the new beta version of mrv2 today and indeed now the image in mrv2 matches the image from nuke. Now, when changing the gamma, the colors converge, but when changing the gain, you can see that the image begins to clamp in white areas in brightness, it would be great if you also corrected this point. mrv2_gain nuke_gain

ggarra13 commented 2 months ago

@archct Thanks for checking the beta. I also noticed the problem. It is due to Darby's tlRender library not taking advantage of the new OpenColorIO 2.x.x functions which now do the color calculations in linear space. I will address the color pipeline issues but it will probably take me at least a week to do so and test them.

ggarra13 commented 2 months ago

@archct The final fix for mrv2's color pipeline with optimizations is now on sourceforge's beta for you to test. If you find further issues, report them to the mrv2 github Issues web page. @remia Feel free to close this issue here now and sorry for having you waste your time.

remia commented 2 months ago

@ggarra13 We can close when it's confirmed the color pipeline is working as expected in the new build, no rush!

archct commented 2 months ago

Thank you for your help! Now mrv2 correctly displays the colors after the lut, the image is identical to the viewer from nuke.

doug-walker commented 1 month ago

Closing as fixed.