Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
derive_filmic_v6_gamut_mapping.py
Go to the documentation of this file.
1# This file is part of darktable,
2# Copyright (C) 2022 Sakari Kapanen.
3#
4# darktable is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# darktable is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with darktable. If not, see <http://www.gnu.org/licenses/>.
16#
17#
18#
19#
20#
21#
22#
23#
24#
25 Derive equation for gamut mapping in Yrg in Filmic v6
26 Based on equations of Yrg -> LMS conversion in
27 src/common/colorspaces_inline_conversions.h
28#
29from sympy import *
30from sympy.solvers.solveset import solveset_real
31
32init_printing(use_unicode=True)
33
34# ch = cos(hue), sh = sin(hue)
35Y, c, ch, sh = symbols('Y c ch sh')
36
37# Go from polar coordinates to Yrg
38Yrg = Matrix([[Y, c * ch + 0.21902143, c * sh + 0.54371398]]).transpose()
39
40# Form normalized rgb
41r = Yrg[1, 0]
42g = Yrg[2, 0]
43rgb = Matrix([[r, g, 1 - r - g]]).transpose()
44
45# Transform to normalized lms space
46rgb_to_lms = Matrix([
47 [0.95, 0.38, 0.00],
48 [0.05, 0.62, 0.03],
49 [0.00, 0.00, 0.97]
50])
51lms = rgb_to_lms * rgb
52
53# Apply normalization based on luminance
54coeff = Y / (0.68990272 * lms[0, 0] + 0.34832189 * lms[1, 0])
55LMS = coeff * lms
56
57# LMS is converted to target RGB.
58# Here, A is a single row of the LMS -> RGB conversion matrix.
59# Thus this corresponds to calculating one component of
60# target RGB. Each component is calculated the same way, coefficients
61# are just different.
62a1, a2, a3 = symbols("a1 a2 a3")
63A = Matrix([[a1, a2, a3]])
64component = (A * LMS)[0, 0]
65
66# k is the target RGB component value (black or white luminance in gamut mapping)
67k = symbols('k')
68
69# Solve for chroma that gives the desired extreme value k for one components.
70# The chroma will be calculated for each component separately, and the smallest
71# value will be chosen to stay in gamut.
72pprint(solveset_real(component - k, c))