-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathAgXBasesRGB.py
103 lines (75 loc) · 4.63 KB
/
AgXBasesRGB.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import colour
import numpy
import luminance_compenstation_bt2020 as lu2020
import luminance_compenstation_srgb as lusRGB
import AgXBaseRec2020
import Guard_Rail_Upper as high_rail
# Log range parameters
midgrey = 0.18
normalized_log2_minimum = -10
normalized_log2_maximum = +6.5
# define color space matrices
bt2020_id65_to_xyz_id65 = numpy.array([[0.6369535067850740, 0.1446191846692331, 0.1688558539228734],
[0.2626983389565560, 0.6780087657728165, 0.0592928952706273],
[0.0000000000000000, 0.0280731358475570, 1.0608272349505707]])
xyz_id65_to_bt2020_id65 = numpy.array([[1.7166634277958805, -0.3556733197301399, -0.2533680878902478],
[-0.6666738361988869, 1.6164557398246981, 0.0157682970961337],
[0.0176424817849772, -0.0427769763827532, 0.9422432810184308]])
inset_matrix = numpy.array([[0.856627153315983, 0.0951212405381588, 0.0482516061458583],
[0.137318972929847, 0.761241990602591, 0.101439036467562],
[0.11189821299995, 0.0767994186031903, 0.811302368396859]])
outset_matrix = numpy.linalg.inv(numpy.array([[0.899796955911611, 0.0871996192028351, 0.013003424885555],
[0.11142098895748, 0.875575586156966, 0.0130034248855548],
[0.11142098895748, 0.0871996192028349, 0.801379391839686]]))
colour.utilities.filter_warnings(python_warnings=True)
def main():
# resolution of the 3DLUT
LUT_res = 37
mix_percent = 40
LUT = colour.LUT3D(name=f'AgX_Formation sRGB',
size=LUT_res)
LUT.domain = ([[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]])
LUT.comments = [f'AgX Base sRGB Formation LUT',
f'This LUT expects input to be E Gamut Log2 encoding from -10 stops to +15 stops',
f'But the end image formation will be from {normalized_log2_minimum} to {normalized_log2_maximum} encoded in power 2.4',
f' rotate = [3.0, -1, -2.0], inset = [0.4, 0.22, 0.13], outset = [0.4, 0.22, 0.04]',
f'The image formed has {mix_percent}% per-channel shifts']
x, y, z, _ = LUT.table.shape
for i in range(x):
for j in range(y):
for k in range(z):
col = numpy.array(LUT.table[i][j][k], dtype=numpy.longdouble)
# decode LUT input transfer function
col = colour.log_decoding(col,
function='Log2',
min_exposure=-10,
max_exposure=+15,
middle_grey=midgrey)
# decode LUT input primaries from E-Gamut to Rec.2020
col = numpy.tensordot(col, lu2020.e_gamut_to_xyz_id65, axes=(0, 1))
col = numpy.tensordot(col, lu2020.xyz_id65_to_bt2020_id65, axes=(0, 1))
# form the image in Rec.2020
col = AgXBaseRec2020.AgX_Base_Rec2020(col, mix_percent)
# convert formed image to rec.709
col = numpy.tensordot(col, lu2020.bt2020_id65_to_xyz_id65, axes=(0, 1))
col = numpy.tensordot(col, lusRGB.xyz_id65_to_bt709_i65, axes=(0, 1))
# apply sRGB's lower Guard Rail
col = lusRGB.compensate_low_side(col)
# should have applied the higher guard rail here, but the higher guard rail actually caused an artifact
# in higher exposure, a test file can be found here: https://discuss.pixls.us/t/sunflower-sagas-and-solutions/33292
# download the "black woman with orange paint on their face" CR2 file, use Darktable to convert to EXR
# import to Blender to test, set exposure to +8, you should see the relative figure-ground luminance relationship
# gets flipped after applying higher guard rail here.
# col = numpy.where(max(col) > 1.0, high_rail.apply_higher(col), col)
# encode transfer function, having an output function helps with precision, so use the same one as the Rec.2020 version
col = colour.models.exponent_function_basic(col, 2.4, 'basicRev')
LUT.table[i][j][k] = numpy.array(col, dtype=LUT.table.dtype)
colour.write_LUT(
LUT,
f"AgX_Base_sRGB.cube")
print(LUT)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass