videovillage / Lattice-Issues

Feature requests, bug tracking, questions, and issues for Lattice.
https://videovillage.co/lattice
6 stars 2 forks source link

Add support for HDR transfer functions #52

Closed stevenrobertson closed 1 year ago

stevenrobertson commented 8 years ago

Hey, Lattice is great!

There are two transfer functions which I think will become increasingly important in the near future, and which it would be awesome to see Lattice support: SMPTE 2084 and HLG.

Background if you aren't already familiar:

SMPTE 2084 (Dolby PQ) is often parameterized based on the peak display luminance. PQ stands out because its codepoints map to specific luminance levels - for instance, the codepoint (512, 512, 512) maps to a gray color that is intended to be 92.2 nits of brightness at the output device. Since modern devices do not go anywhere close to the 10,000 nit peak code value, each device will be responsible for interpreting how to handle out-of-range values, and nobody's releasing content that is mastered for the full 10,000 nit range, most of the time a workflow will pick a reasonable peak value (say, 1,000 nits), and map the highest attainable gamma codepoint in the input space to the same value in the output space.

So, with a target peak luminance of 1,000 nits, an input gamma value of 1.0 would be mapped to an output SMPTE 2084 value of 0.751827096247.

Here's a publicly accessible link: https://www.smpte.org/sites/default/files/23-1615-TS7-2-IProc02-Miller.pdf

and an example implementation taken from an IPython notebook that I've been using to make test cards:

class SMPTE2084TransferFunc(object):
    name = 'smpte-st-2084'
    def __init__(self, luminance_cap=1000):
        self.luma = luminance_cap
        self.factor = luminance_cap / 10000.

    def oetf(self, v):
        ve = (v * self.factor) ** 0.1593017578125
        return ((0.8359375 + 18.8515625 * ve) / (1 + 18.6875 * ve)) ** 78.84375

    def eotf(self, v):
        ve = v ** (1 / 78.84375)
        return (max(0, ve - 0.8359375) / (18.8515625 - 18.6875 * ve)) ** (1 / 0.1593017578125) / self.factor

Hybrid Log-Gamma (ARIB STD-B67) is an alternative HDR proposal that's designed to still be efficient-ish on the same metric that PQ uses, but also to not look terrible when viewed on a traditional gamma display and to not require additional metadata. HLG also has a parameterization, called system gamma, which is used to adapt content for various display environments; there's a recommended application of system gamma as a ratio of display peak to ambient light intensity.

Here's a paper (with some older values): http://www.bbc.co.uk/rd/publications/whitepaper309

Here's the standard where the values have been locked down: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf

And here's the example from that IPython notebook:

class ARIBStdB67TransferFunc(object):
    name = 'arib-std-b67'
    def __init__(self, system_gamma=1.25):
        self.system_gamma = system_gamma

    a = 0.17883277
    b = 0.28466892
    c = 0.55991073
    Lmax = 12

    def oetf(self, v):
        # Note that normally we wouldn't apply system gamma to the input, but 
        # since we are after all doing gamma tests...
        E = v ** (1 / self.system_gamma) * self.Lmax
        if E <= 1:
            E_ = 0.5 * np.sqrt(E)
        else:
            E_ = self.a * np.log(E - self.b) + self.c
        return E_

    def eotf(self, E_):
        if E_ <= 0.5:
            v_ = (E_ * 2) ** 2
        else:
            v_ = np.exp((E_ - self.c) / self.a) + self.b
        return (v_ / self.Lmax) ** self.system_gamma
gregcotten commented 8 years ago

Hi Steven,

Thanks so much for this! We have rudimentary PQ support but no support at all for HLG. I'm currently in the process of adding these functions into the colorspace converter.

gregcotten commented 8 years ago

By the way, would you have any idea as to why Blackmagic's PQ HDR LUTs are intended for boundaries outside 0 to 1?

stevenrobertson commented 8 years ago

It's a philosophical choice on their part. If you import footage into Resolve 12.2, by default the peak of that footage gets seated at 100 nits in the PQ scale, which is "SDR peak brightness". (Except almost all modern SDR televisions have shot past 100 nits long ago.)

The result tends to be a much more highlight-focused workflow with a darker average frame luminance in my experience, which definitely makes something say "I'm HDR!" and will render better on current-gen TVs which can only do full brightness over a small area. But that look may not be the most natural or enduring use of HDR as we move from tech demos to actual narrative content.

On Tue, Jan 5, 2016 at 4:23 PM, Greg Cotten notifications@github.com wrote:

By the way, would you have any idea as to why Blackmagic's PQ HDR LUTs are intended for boundaries outside 0 to 1?

— Reply to this email directly or view it on GitHub https://github.com/videovillage/Lattice-Issues/issues/52#issuecomment-169176997 .