Skip to content

Commit

Permalink
Add proper handling of gamma and black level lift
Browse files Browse the repository at this point in the history
Set lb to 0 and lw to 1000 as these are the minimums for each range.
Gamma will calculate to about 1.2, but it'll make no difference as the
black level lift will be calculated as zero for us anyways due to lb = 0

If we end up changing lb at some point, gamma will have an actual impact
  • Loading branch information
facelessuser committed Jan 20, 2023
1 parent ff05131 commit 8035ff1
Showing 1 changed file with 50 additions and 10 deletions.
60 changes: 50 additions & 10 deletions coloraide/spaces/rec2100_hlg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,68 @@
from .srgb import sRGB
from .. import algebra as alg
from ..types import Vector
import math

A = 0.17883277
B = 0.28466892 # `1 - 4 * A`
C = 0.55991073 # `0.5 - A * alg.nlog(4 * A)`
# Sets 18% grey card to ~38% (37.7...) in order to set diffused white to 75%.
SCALE = 0.26496256042100724
INV_SCALE = 1 / SCALE


def hlg_oetf(values: Vector) -> Vector:
class Environment:
"""Class to calculate and contain any required environmental data."""

def __init__(
self,
lw: float,
lb: float,
scale: float
):
"""Initialize environmental data."""

self.a = 0.17883277
self.b = 0.28466892 # `1 - 4 * a`
self.c = 0.55991073 # `0.5 - a * alg.nlog(4 * a)`
self.beta = hlg_black_level_lift(lw, lb)
self.scale = scale
self.inv_scale = 1 / scale


def hlg_gamma(lw: float = 1000.0) -> float:
"""
Return the reference HLG system gamma.
Ranges should be `lw >= 1000 cd / m^2`.
"""

return 1.2 + 0.42 * math.log(lw / 1000.0)


def hlg_black_level_lift(lw: float = 0.0, lb: float = 1000.0) -> float:
"""
Return beta (the black level lift) using the nominal peak level luminance and display luminance for black.
Ranges should be `lw >= 1000 cd / m^2` and `lb <= 0.005 cd / m^2`.
"""

return math.sqrt(3 * (lb / lw) ** (1 / hlg_gamma(lw)))


def hlg_oetf(values: Vector, env: Environment) -> Vector:
"""HLG OETF."""

adjusted = [] # type: Vector
for e in values:
adjusted.append(alg.nth_root(3 * e, 2) if e <= 1 / 12 else A * alg.nlog(12 * e - B) + C)
e = alg.nth_root(3 * e, 2) if e <= 1 / 12 else env.a * alg.nlog(12 * e - env.b) + env.c
adjusted.append((e - env.beta) / (1 - env.beta))
return adjusted


def hlg_eotf(values: Vector) -> Vector:
def hlg_eotf(values: Vector, env: Environment) -> Vector:
"""HLG EOTF."""

adjusted = [] # type: Vector
for e in values:
adjusted.append((e ** 2) / 3 if e <= 0.5 else (alg.nexp((e - C) / A) + B) / 12)
e = (1 - env.beta) * e + env.beta
adjusted.append((e ** 2) / 3 if e <= 0.5 else (alg.nexp((e - env.c) / env.a) + env.b) / 12)
return adjusted


Expand All @@ -53,13 +92,14 @@ class Rec2100HLG(sRGB):
SERIALIZE = ('--rec2100-hlg',)
WHITE = WHITES['2deg']['D65']
DYNAMIC_RANGE = 'hdr'
ENV = Environment(1000, 0, SCALE)

def to_base(self, coords: Vector) -> Vector:
"""To base from Rec 2100 HLG."""

return alg.multiply(hlg_eotf(coords), INV_SCALE, dims=alg.D1_SC)
return [c * self.ENV.inv_scale for c in hlg_eotf(coords, self.ENV)]

def from_base(self, coords: Vector) -> Vector:
"""From base to Rec. 2100 HLG."""

return hlg_oetf(alg.multiply(coords, SCALE, dims=alg.D1_SC))
return hlg_oetf([c * self.ENV.scale for c in coords], self.ENV)

0 comments on commit 8035ff1

Please sign in to comment.