darktable-org / darktable-org/darktable

PQ output does not reach minimum brightness

Open
#19,779 8 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

no-issue-activity
Dominant language
C
Stars
13.1k
Forks
1.4k
Avg merge
22h 14m
Merged PRs (30d)
198

Description

Is there an existing issue for this?
  • I checked and did not find my issue in the already reported ones
Describe the bug

When saving in a output format using the PQ transfer function, the lowest value (0) is mapped to a value of about 5.5% instead of 0% per channel.

Steps to reproduce
  1. Open a file containing channels with values of 0 (or apply negative exposure to one until it does).
  2. Set output to PQ Rec2020 RGB or PQ P3 RGB.
  3. Export file.
  4. Observe exported values are at least 5.5%.

(I have seen values of less than 5.5% for some outputs, notably JPEG, though they don't reach 0)

Expected behavior

Map values of 0 to 0.

Logfile | Screenshot | Screencast

No response

Commit

No response

Where did you obtain darktable from?

distro packaging

darktable version

5.2.1

What OS are you using?

Linux

What is the version of your OS?

Archlinux

Describe your system

Running lcms2 v2.17-1

Are you using OpenCL GPU in darktable?

No

If yes, what is the GPU card and driver?

No response

Please provide additional context if applicable. You can attach files too, but might need to rename to .txt or .zip

I've had a look at this a fair bit, narrowing down where this is value discrepancy originates. It seems that inverting the tone curves using lcms2 for pq in colorspaces.c:188–190 causes the generated LUT to have the first value in the table be 0.055436 instead of 0 like I would expect.

I was not able to further deduce exactly why this occurs, though user frnxt on a reddit post regarding PQ clipping commented:

Is the X axis linear with respect to luminance in this histogram?

My hypothesis (please correct me if I'm wrong!) is that unless someone went out of their way to implement a custom PQ 1DLUT with more precision or the conversion is done in floating-point in shaders, Darktable uses LittleCMS and ICC profiles, and ICC profiles are limited to 16-bit data for a lot of operations including tone curves.

This is not that much a problem in the nonlinear → linear direction (for input PQ files) where PQ(1/65535) ≈ 1e-8 nits.

This is however much more problematic for the linear → nonlinear direction (for output PQ files) where 1/65535 x 10k nit ≈ 0.15 nit. I know some LittleCMS transform modes clip below a certain value at their lowest precision limits so this might be where your 0.0743 nits comes from.

HLG (in its reference implementation with system gamma 1.2) goes up to 1k nit, so the limit should be ≈ 0.015 nit.

This seems to align with my little knowledge so far and may be of assistance in tracking down a solution.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the export with zero-valued channels using PQ Rec2020 RGB or PQ P3 RGB, then inspect src/common/colorspaces.c around lines 188–190 and the lcms2 tone-curve inversion. Compare the generated LUT's first value with the expected zero output, and verify that exported PQ values reach 0% without regressing other output formats.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.